Revision 419fb20a
b/target-i386/kvm.c | ||
---|---|---|
172 | 172 |
#endif |
173 | 173 |
return features; |
174 | 174 |
} |
175 |
#endif |
|
175 |
#endif /* CONFIG_KVM_PARA */
|
|
176 | 176 |
|
177 | 177 |
#ifdef KVM_CAP_MCE |
178 | 178 |
static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap, |
... | ... | |
273 | 273 |
run_on_cpu(env, kvm_do_inject_x86_mce, &data); |
274 | 274 |
} |
275 | 275 |
|
276 |
static void kvm_mce_broadcast_rest(CPUState *env); |
|
277 |
#endif |
|
276 |
static void kvm_mce_broadcast_rest(CPUState *env) |
|
277 |
{ |
|
278 |
struct kvm_x86_mce mce = { |
|
279 |
.bank = 1, |
|
280 |
.status = MCI_STATUS_VAL | MCI_STATUS_UC, |
|
281 |
.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, |
|
282 |
.addr = 0, |
|
283 |
.misc = 0, |
|
284 |
}; |
|
285 |
CPUState *cenv; |
|
286 |
|
|
287 |
/* Broadcast MCA signal for processor version 06H_EH and above */ |
|
288 |
if (cpu_x86_support_mca_broadcast(env)) { |
|
289 |
for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { |
|
290 |
if (cenv == env) { |
|
291 |
continue; |
|
292 |
} |
|
293 |
kvm_inject_x86_mce_on(cenv, &mce, ABORT_ON_ERROR); |
|
294 |
} |
|
295 |
} |
|
296 |
} |
|
297 |
|
|
298 |
static void kvm_mce_inj_srar_dataload(CPUState *env, target_phys_addr_t paddr) |
|
299 |
{ |
|
300 |
struct kvm_x86_mce mce = { |
|
301 |
.bank = 9, |
|
302 |
.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
|
303 |
| MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S |
|
304 |
| MCI_STATUS_AR | 0x134, |
|
305 |
.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV, |
|
306 |
.addr = paddr, |
|
307 |
.misc = (MCM_ADDR_PHYS << 6) | 0xc, |
|
308 |
}; |
|
309 |
int r; |
|
310 |
|
|
311 |
r = kvm_set_mce(env, &mce); |
|
312 |
if (r < 0) { |
|
313 |
fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno)); |
|
314 |
abort(); |
|
315 |
} |
|
316 |
kvm_mce_broadcast_rest(env); |
|
317 |
} |
|
318 |
|
|
319 |
static void kvm_mce_inj_srao_memscrub(CPUState *env, target_phys_addr_t paddr) |
|
320 |
{ |
|
321 |
struct kvm_x86_mce mce = { |
|
322 |
.bank = 9, |
|
323 |
.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
|
324 |
| MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S |
|
325 |
| 0xc0, |
|
326 |
.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, |
|
327 |
.addr = paddr, |
|
328 |
.misc = (MCM_ADDR_PHYS << 6) | 0xc, |
|
329 |
}; |
|
330 |
int r; |
|
331 |
|
|
332 |
r = kvm_set_mce(env, &mce); |
|
333 |
if (r < 0) { |
|
334 |
fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno)); |
|
335 |
abort(); |
|
336 |
} |
|
337 |
kvm_mce_broadcast_rest(env); |
|
338 |
} |
|
339 |
|
|
340 |
static void kvm_mce_inj_srao_memscrub2(CPUState *env, target_phys_addr_t paddr) |
|
341 |
{ |
|
342 |
struct kvm_x86_mce mce = { |
|
343 |
.bank = 9, |
|
344 |
.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
|
345 |
| MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S |
|
346 |
| 0xc0, |
|
347 |
.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, |
|
348 |
.addr = paddr, |
|
349 |
.misc = (MCM_ADDR_PHYS << 6) | 0xc, |
|
350 |
}; |
|
351 |
|
|
352 |
kvm_inject_x86_mce_on(env, &mce, ABORT_ON_ERROR); |
|
353 |
kvm_mce_broadcast_rest(env); |
|
354 |
} |
|
355 |
#endif /* KVM_CAP_MCE */ |
|
356 |
|
|
357 |
static void hardware_memory_error(void) |
|
358 |
{ |
|
359 |
fprintf(stderr, "Hardware memory error!\n"); |
|
360 |
exit(1); |
|
361 |
} |
|
362 |
|
|
363 |
int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) |
|
364 |
{ |
|
365 |
#ifdef KVM_CAP_MCE |
|
366 |
void *vaddr; |
|
367 |
ram_addr_t ram_addr; |
|
368 |
target_phys_addr_t paddr; |
|
369 |
|
|
370 |
if ((env->mcg_cap & MCG_SER_P) && addr |
|
371 |
&& (code == BUS_MCEERR_AR |
|
372 |
|| code == BUS_MCEERR_AO)) { |
|
373 |
vaddr = (void *)addr; |
|
374 |
if (qemu_ram_addr_from_host(vaddr, &ram_addr) || |
|
375 |
!kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, &paddr)) { |
|
376 |
fprintf(stderr, "Hardware memory error for memory used by " |
|
377 |
"QEMU itself instead of guest system!\n"); |
|
378 |
/* Hope we are lucky for AO MCE */ |
|
379 |
if (code == BUS_MCEERR_AO) { |
|
380 |
return 0; |
|
381 |
} else { |
|
382 |
hardware_memory_error(); |
|
383 |
} |
|
384 |
} |
|
385 |
|
|
386 |
if (code == BUS_MCEERR_AR) { |
|
387 |
/* Fake an Intel architectural Data Load SRAR UCR */ |
|
388 |
kvm_mce_inj_srar_dataload(env, paddr); |
|
389 |
} else { |
|
390 |
/* |
|
391 |
* If there is an MCE excpetion being processed, ignore |
|
392 |
* this SRAO MCE |
|
393 |
*/ |
|
394 |
if (!kvm_mce_in_progress(env)) { |
|
395 |
/* Fake an Intel architectural Memory scrubbing UCR */ |
|
396 |
kvm_mce_inj_srao_memscrub(env, paddr); |
|
397 |
} |
|
398 |
} |
|
399 |
} else |
|
400 |
#endif /* KVM_CAP_MCE */ |
|
401 |
{ |
|
402 |
if (code == BUS_MCEERR_AO) { |
|
403 |
return 0; |
|
404 |
} else if (code == BUS_MCEERR_AR) { |
|
405 |
hardware_memory_error(); |
|
406 |
} else { |
|
407 |
return 1; |
|
408 |
} |
|
409 |
} |
|
410 |
return 0; |
|
411 |
} |
|
412 |
|
|
413 |
int kvm_arch_on_sigbus(int code, void *addr) |
|
414 |
{ |
|
415 |
#ifdef KVM_CAP_MCE |
|
416 |
if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) { |
|
417 |
void *vaddr; |
|
418 |
ram_addr_t ram_addr; |
|
419 |
target_phys_addr_t paddr; |
|
420 |
|
|
421 |
/* Hope we are lucky for AO MCE */ |
|
422 |
vaddr = addr; |
|
423 |
if (qemu_ram_addr_from_host(vaddr, &ram_addr) || |
|
424 |
!kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, |
|
425 |
&paddr)) { |
|
426 |
fprintf(stderr, "Hardware memory error for memory used by " |
|
427 |
"QEMU itself instead of guest system!: %p\n", addr); |
|
428 |
return 0; |
|
429 |
} |
|
430 |
kvm_mce_inj_srao_memscrub2(first_cpu, paddr); |
|
431 |
} else |
|
432 |
#endif /* KVM_CAP_MCE */ |
|
433 |
{ |
|
434 |
if (code == BUS_MCEERR_AO) { |
|
435 |
return 0; |
|
436 |
} else if (code == BUS_MCEERR_AR) { |
|
437 |
hardware_memory_error(); |
|
438 |
} else { |
|
439 |
return 1; |
|
440 |
} |
|
441 |
} |
|
442 |
return 0; |
|
443 |
} |
|
278 | 444 |
|
279 | 445 |
void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, |
280 | 446 |
uint64_t mcg_status, uint64_t addr, uint64_t misc, |
... | ... | |
294 | 460 |
} |
295 | 461 |
|
296 | 462 |
kvm_inject_x86_mce_on(cenv, &mce, flag); |
297 |
#else |
|
463 |
#else /* !KVM_CAP_MCE*/
|
|
298 | 464 |
if (flag & ABORT_ON_ERROR) { |
299 | 465 |
abort(); |
300 | 466 |
} |
301 |
#endif |
|
467 |
#endif /* !KVM_CAP_MCE*/
|
|
302 | 468 |
} |
303 | 469 |
|
304 | 470 |
static void cpu_update_state(void *opaque, int running, int reason) |
... | ... | |
1783 | 1949 |
return !(env->cr[0] & CR0_PE_MASK) || |
1784 | 1950 |
((env->segs[R_CS].selector & 3) != 3); |
1785 | 1951 |
} |
1786 |
|
|
1787 |
static void hardware_memory_error(void) |
|
1788 |
{ |
|
1789 |
fprintf(stderr, "Hardware memory error!\n"); |
|
1790 |
exit(1); |
|
1791 |
} |
|
1792 |
|
|
1793 |
#ifdef KVM_CAP_MCE |
|
1794 |
static void kvm_mce_broadcast_rest(CPUState *env) |
|
1795 |
{ |
|
1796 |
struct kvm_x86_mce mce = { |
|
1797 |
.bank = 1, |
|
1798 |
.status = MCI_STATUS_VAL | MCI_STATUS_UC, |
|
1799 |
.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, |
|
1800 |
.addr = 0, |
|
1801 |
.misc = 0, |
|
1802 |
}; |
|
1803 |
CPUState *cenv; |
|
1804 |
|
|
1805 |
/* Broadcast MCA signal for processor version 06H_EH and above */ |
|
1806 |
if (cpu_x86_support_mca_broadcast(env)) { |
|
1807 |
for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { |
|
1808 |
if (cenv == env) { |
|
1809 |
continue; |
|
1810 |
} |
|
1811 |
kvm_inject_x86_mce_on(cenv, &mce, ABORT_ON_ERROR); |
|
1812 |
} |
|
1813 |
} |
|
1814 |
} |
|
1815 |
|
|
1816 |
static void kvm_mce_inj_srar_dataload(CPUState *env, target_phys_addr_t paddr) |
|
1817 |
{ |
|
1818 |
struct kvm_x86_mce mce = { |
|
1819 |
.bank = 9, |
|
1820 |
.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
|
1821 |
| MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S |
|
1822 |
| MCI_STATUS_AR | 0x134, |
|
1823 |
.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV, |
|
1824 |
.addr = paddr, |
|
1825 |
.misc = (MCM_ADDR_PHYS << 6) | 0xc, |
|
1826 |
}; |
|
1827 |
int r; |
|
1828 |
|
|
1829 |
r = kvm_set_mce(env, &mce); |
|
1830 |
if (r < 0) { |
|
1831 |
fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno)); |
|
1832 |
abort(); |
|
1833 |
} |
|
1834 |
kvm_mce_broadcast_rest(env); |
|
1835 |
} |
|
1836 |
|
|
1837 |
static void kvm_mce_inj_srao_memscrub(CPUState *env, target_phys_addr_t paddr) |
|
1838 |
{ |
|
1839 |
struct kvm_x86_mce mce = { |
|
1840 |
.bank = 9, |
|
1841 |
.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
|
1842 |
| MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S |
|
1843 |
| 0xc0, |
|
1844 |
.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, |
|
1845 |
.addr = paddr, |
|
1846 |
.misc = (MCM_ADDR_PHYS << 6) | 0xc, |
|
1847 |
}; |
|
1848 |
int r; |
|
1849 |
|
|
1850 |
r = kvm_set_mce(env, &mce); |
|
1851 |
if (r < 0) { |
|
1852 |
fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno)); |
|
1853 |
abort(); |
|
1854 |
} |
|
1855 |
kvm_mce_broadcast_rest(env); |
|
1856 |
} |
|
1857 |
|
|
1858 |
static void kvm_mce_inj_srao_memscrub2(CPUState *env, target_phys_addr_t paddr) |
|
1859 |
{ |
|
1860 |
struct kvm_x86_mce mce = { |
|
1861 |
.bank = 9, |
|
1862 |
.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
|
1863 |
| MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S |
|
1864 |
| 0xc0, |
|
1865 |
.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, |
|
1866 |
.addr = paddr, |
|
1867 |
.misc = (MCM_ADDR_PHYS << 6) | 0xc, |
|
1868 |
}; |
|
1869 |
|
|
1870 |
kvm_inject_x86_mce_on(env, &mce, ABORT_ON_ERROR); |
|
1871 |
kvm_mce_broadcast_rest(env); |
|
1872 |
} |
|
1873 |
|
|
1874 |
#endif |
|
1875 |
|
|
1876 |
int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) |
|
1877 |
{ |
|
1878 |
#if defined(KVM_CAP_MCE) |
|
1879 |
void *vaddr; |
|
1880 |
ram_addr_t ram_addr; |
|
1881 |
target_phys_addr_t paddr; |
|
1882 |
|
|
1883 |
if ((env->mcg_cap & MCG_SER_P) && addr |
|
1884 |
&& (code == BUS_MCEERR_AR |
|
1885 |
|| code == BUS_MCEERR_AO)) { |
|
1886 |
vaddr = (void *)addr; |
|
1887 |
if (qemu_ram_addr_from_host(vaddr, &ram_addr) || |
|
1888 |
!kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, &paddr)) { |
|
1889 |
fprintf(stderr, "Hardware memory error for memory used by " |
|
1890 |
"QEMU itself instead of guest system!\n"); |
|
1891 |
/* Hope we are lucky for AO MCE */ |
|
1892 |
if (code == BUS_MCEERR_AO) { |
|
1893 |
return 0; |
|
1894 |
} else { |
|
1895 |
hardware_memory_error(); |
|
1896 |
} |
|
1897 |
} |
|
1898 |
|
|
1899 |
if (code == BUS_MCEERR_AR) { |
|
1900 |
/* Fake an Intel architectural Data Load SRAR UCR */ |
|
1901 |
kvm_mce_inj_srar_dataload(env, paddr); |
|
1902 |
} else { |
|
1903 |
/* |
|
1904 |
* If there is an MCE excpetion being processed, ignore |
|
1905 |
* this SRAO MCE |
|
1906 |
*/ |
|
1907 |
if (!kvm_mce_in_progress(env)) { |
|
1908 |
/* Fake an Intel architectural Memory scrubbing UCR */ |
|
1909 |
kvm_mce_inj_srao_memscrub(env, paddr); |
|
1910 |
} |
|
1911 |
} |
|
1912 |
} else |
|
1913 |
#endif |
|
1914 |
{ |
|
1915 |
if (code == BUS_MCEERR_AO) { |
|
1916 |
return 0; |
|
1917 |
} else if (code == BUS_MCEERR_AR) { |
|
1918 |
hardware_memory_error(); |
|
1919 |
} else { |
|
1920 |
return 1; |
|
1921 |
} |
|
1922 |
} |
|
1923 |
return 0; |
|
1924 |
} |
|
1925 |
|
|
1926 |
int kvm_arch_on_sigbus(int code, void *addr) |
|
1927 |
{ |
|
1928 |
#if defined(KVM_CAP_MCE) |
|
1929 |
if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) { |
|
1930 |
void *vaddr; |
|
1931 |
ram_addr_t ram_addr; |
|
1932 |
target_phys_addr_t paddr; |
|
1933 |
|
|
1934 |
/* Hope we are lucky for AO MCE */ |
|
1935 |
vaddr = addr; |
|
1936 |
if (qemu_ram_addr_from_host(vaddr, &ram_addr) || |
|
1937 |
!kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, &paddr)) { |
|
1938 |
fprintf(stderr, "Hardware memory error for memory used by " |
|
1939 |
"QEMU itself instead of guest system!: %p\n", addr); |
|
1940 |
return 0; |
|
1941 |
} |
|
1942 |
kvm_mce_inj_srao_memscrub2(first_cpu, paddr); |
|
1943 |
} else |
|
1944 |
#endif |
|
1945 |
{ |
|
1946 |
if (code == BUS_MCEERR_AO) { |
|
1947 |
return 0; |
|
1948 |
} else if (code == BUS_MCEERR_AR) { |
|
1949 |
hardware_memory_error(); |
|
1950 |
} else { |
|
1951 |
return 1; |
|
1952 |
} |
|
1953 |
} |
|
1954 |
return 0; |
|
1955 |
} |
Also available in: Unified diff