Revision 79c4f6b0
b/cpu-all.h | ||
---|---|---|
770 | 770 |
#define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ |
771 | 771 |
#define CPU_INTERRUPT_INIT 0x400 /* INIT pending. */ |
772 | 772 |
#define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */ |
773 |
#define CPU_INTERRUPT_MCE 0x1000 /* (x86 only) MCE pending. */ |
|
773 | 774 |
|
774 | 775 |
void cpu_interrupt(CPUState *s, int mask); |
775 | 776 |
void cpu_reset_interrupt(CPUState *env, int mask); |
... | ... | |
1071 | 1072 |
extern int64_t kqemu_ret_intr_count; |
1072 | 1073 |
#endif |
1073 | 1074 |
|
1075 |
void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, |
|
1076 |
uint64_t mcg_status, uint64_t addr, uint64_t misc); |
|
1077 |
|
|
1074 | 1078 |
#endif /* CPU_ALL_H */ |
b/cpu-exec.c | ||
---|---|---|
400 | 400 |
env->hflags2 |= HF2_NMI_MASK; |
401 | 401 |
do_interrupt(EXCP02_NMI, 0, 0, 0, 1); |
402 | 402 |
next_tb = 0; |
403 |
} else if (interrupt_request & CPU_INTERRUPT_MCE) { |
|
404 |
env->interrupt_request &= ~CPU_INTERRUPT_MCE; |
|
405 |
do_interrupt(EXCP12_MCHK, 0, 0, 0, 0); |
|
406 |
next_tb = 0; |
|
403 | 407 |
} else if ((interrupt_request & CPU_INTERRUPT_HARD) && |
404 | 408 |
(((env->hflags2 & HF2_VINTR_MASK) && |
405 | 409 |
(env->hflags2 & HF2_HIF_MASK)) || |
b/monitor.c | ||
---|---|---|
1677 | 1677 |
} |
1678 | 1678 |
} |
1679 | 1679 |
|
1680 |
#if defined(TARGET_I386) |
|
1681 |
static void do_inject_mce(Monitor *mon, |
|
1682 |
int cpu_index, int bank, |
|
1683 |
unsigned status_hi, unsigned status_lo, |
|
1684 |
unsigned mcg_status_hi, unsigned mcg_status_lo, |
|
1685 |
unsigned addr_hi, unsigned addr_lo, |
|
1686 |
unsigned misc_hi, unsigned misc_lo) |
|
1687 |
{ |
|
1688 |
CPUState *cenv; |
|
1689 |
uint64_t status = ((uint64_t)status_hi << 32) | status_lo; |
|
1690 |
uint64_t mcg_status = ((uint64_t)mcg_status_hi << 32) | mcg_status_lo; |
|
1691 |
uint64_t addr = ((uint64_t)addr_hi << 32) | addr_lo; |
|
1692 |
uint64_t misc = ((uint64_t)misc_hi << 32) | misc_lo; |
|
1693 |
|
|
1694 |
for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) |
|
1695 |
if (cenv->cpu_index == cpu_index && cenv->mcg_cap) { |
|
1696 |
cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc); |
|
1697 |
break; |
|
1698 |
} |
|
1699 |
} |
|
1700 |
#endif |
|
1701 |
|
|
1680 | 1702 |
static const mon_cmd_t mon_cmds[] = { |
1681 | 1703 |
#include "qemu-monitor.h" |
1682 | 1704 |
{ NULL, NULL, }, |
... | ... | |
2451 | 2473 |
void *arg3, void *arg4, void *arg5); |
2452 | 2474 |
void (*handler_7)(Monitor *mon, void *arg0, void *arg1, void *arg2, |
2453 | 2475 |
void *arg3, void *arg4, void *arg5, void *arg6); |
2476 |
void (*handler_8)(Monitor *mon, void *arg0, void *arg1, void *arg2, |
|
2477 |
void *arg3, void *arg4, void *arg5, void *arg6, |
|
2478 |
void *arg7); |
|
2479 |
void (*handler_9)(Monitor *mon, void *arg0, void *arg1, void *arg2, |
|
2480 |
void *arg3, void *arg4, void *arg5, void *arg6, |
|
2481 |
void *arg7, void *arg8); |
|
2482 |
void (*handler_10)(Monitor *mon, void *arg0, void *arg1, void *arg2, |
|
2483 |
void *arg3, void *arg4, void *arg5, void *arg6, |
|
2484 |
void *arg7, void *arg8, void *arg9); |
|
2454 | 2485 |
|
2455 | 2486 |
#ifdef DEBUG |
2456 | 2487 |
monitor_printf(mon, "command='%s'\n", cmdline); |
... | ... | |
2739 | 2770 |
handler_7(mon, args[0], args[1], args[2], args[3], args[4], args[5], |
2740 | 2771 |
args[6]); |
2741 | 2772 |
break; |
2773 |
case 8: |
|
2774 |
handler_8 = cmd->handler; |
|
2775 |
handler_8(mon, args[0], args[1], args[2], args[3], args[4], args[5], |
|
2776 |
args[6], args[7]); |
|
2777 |
break; |
|
2778 |
case 9: |
|
2779 |
handler_9 = cmd->handler; |
|
2780 |
handler_9(mon, args[0], args[1], args[2], args[3], args[4], args[5], |
|
2781 |
args[6], args[7], args[8]); |
|
2782 |
break; |
|
2783 |
case 10: |
|
2784 |
handler_10 = cmd->handler; |
|
2785 |
handler_10(mon, args[0], args[1], args[2], args[3], args[4], args[5], |
|
2786 |
args[6], args[7], args[8], args[9]); |
|
2787 |
break; |
|
2742 | 2788 |
default: |
2743 | 2789 |
monitor_printf(mon, "unsupported number of arguments: %d\n", nb_args); |
2744 | 2790 |
goto fail; |
b/qemu-monitor.hx | ||
---|---|---|
615 | 615 |
policy back to @code{deny}. |
616 | 616 |
ETEXI |
617 | 617 |
|
618 |
#if defined(TARGET_I386) |
|
619 |
{ "mce", "iillll", do_inject_mce, "cpu bank status mcgstatus addr misc", "inject a MCE on the given CPU"}, |
|
620 |
#endif |
|
621 |
STEXI |
|
622 |
@item mce @var{cpu} @var{bank} @var{status} @var{mcgstatus} @var{addr} @var{misc} |
|
623 |
Inject an MCE on the given CPU (x86 only). |
|
624 |
ETEXI |
|
625 |
|
|
618 | 626 |
STEXI |
619 | 627 |
@end table |
620 | 628 |
ETEXI |
b/target-i386/cpu.h | ||
---|---|---|
204 | 204 |
#define CR4_DE_MASK (1 << 3) |
205 | 205 |
#define CR4_PSE_MASK (1 << 4) |
206 | 206 |
#define CR4_PAE_MASK (1 << 5) |
207 |
#define CR4_MCE_MASK (1 << 6) |
|
207 | 208 |
#define CR4_PGE_MASK (1 << 7) |
208 | 209 |
#define CR4_PCE_MASK (1 << 8) |
209 | 210 |
#define CR4_OSFXSR_SHIFT 9 |
... | ... | |
250 | 251 |
#define PG_ERROR_RSVD_MASK 0x08 |
251 | 252 |
#define PG_ERROR_I_D_MASK 0x10 |
252 | 253 |
|
254 |
#define MCG_CTL_P (1UL<<8) /* MCG_CAP register available */ |
|
255 |
|
|
256 |
#define MCE_CAP_DEF MCG_CTL_P |
|
257 |
#define MCE_BANKS_DEF 10 |
|
258 |
|
|
259 |
#define MCG_STATUS_MCIP (1UL<<2) /* machine check in progress */ |
|
260 |
|
|
261 |
#define MCI_STATUS_VAL (1UL<<63) /* valid error */ |
|
262 |
#define MCI_STATUS_OVER (1UL<<62) /* previous errors lost */ |
|
263 |
#define MCI_STATUS_UC (1UL<<61) /* uncorrected error */ |
|
264 |
|
|
253 | 265 |
#define MSR_IA32_TSC 0x10 |
254 | 266 |
#define MSR_IA32_APICBASE 0x1b |
255 | 267 |
#define MSR_IA32_APICBASE_BSP (1<<8) |
... | ... | |
290 | 302 |
|
291 | 303 |
#define MSR_MTRRdefType 0x2ff |
292 | 304 |
|
305 |
#define MSR_MC0_CTL 0x400 |
|
306 |
#define MSR_MC0_STATUS 0x401 |
|
307 |
#define MSR_MC0_ADDR 0x402 |
|
308 |
#define MSR_MC0_MISC 0x403 |
|
309 |
|
|
293 | 310 |
#define MSR_EFER 0xc0000080 |
294 | 311 |
|
295 | 312 |
#define MSR_EFER_SCE (1 << 0) |
... | ... | |
678 | 695 |
/* in order to simplify APIC support, we leave this pointer to the |
679 | 696 |
user */ |
680 | 697 |
struct APICState *apic_state; |
698 |
|
|
699 |
uint64 mcg_cap; |
|
700 |
uint64 mcg_status; |
|
701 |
uint64 mcg_ctl; |
|
702 |
uint64 *mce_banks; |
|
681 | 703 |
} CPUX86State; |
682 | 704 |
|
683 | 705 |
CPUX86State *cpu_x86_init(const char *cpu_model); |
... | ... | |
842 | 864 |
#define cpu_signal_handler cpu_x86_signal_handler |
843 | 865 |
#define cpu_list x86_cpu_list |
844 | 866 |
|
845 |
#define CPU_SAVE_VERSION 9
|
|
867 |
#define CPU_SAVE_VERSION 10
|
|
846 | 868 |
|
847 | 869 |
/* MMU modes definitions */ |
848 | 870 |
#define MMU_MODE0_SUFFIX _kernel |
b/target-i386/helper.c | ||
---|---|---|
1496 | 1496 |
if (prev_debug_excp_handler) |
1497 | 1497 |
prev_debug_excp_handler(env); |
1498 | 1498 |
} |
1499 |
|
|
1500 |
/* This should come from sysemu.h - if we could include it here... */ |
|
1501 |
void qemu_system_reset_request(void); |
|
1502 |
|
|
1503 |
void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, |
|
1504 |
uint64_t mcg_status, uint64_t addr, uint64_t misc) |
|
1505 |
{ |
|
1506 |
uint64_t mcg_cap = cenv->mcg_cap; |
|
1507 |
unsigned bank_num = mcg_cap & 0xff; |
|
1508 |
uint64_t *banks = cenv->mce_banks; |
|
1509 |
|
|
1510 |
if (bank >= bank_num || !(status & MCI_STATUS_VAL)) |
|
1511 |
return; |
|
1512 |
|
|
1513 |
/* |
|
1514 |
* if MSR_MCG_CTL is not all 1s, the uncorrected error |
|
1515 |
* reporting is disabled |
|
1516 |
*/ |
|
1517 |
if ((status & MCI_STATUS_UC) && (mcg_cap & MCG_CTL_P) && |
|
1518 |
cenv->mcg_ctl != ~(uint64_t)0) |
|
1519 |
return; |
|
1520 |
banks += 4 * bank; |
|
1521 |
/* |
|
1522 |
* if MSR_MCi_CTL is not all 1s, the uncorrected error |
|
1523 |
* reporting is disabled for the bank |
|
1524 |
*/ |
|
1525 |
if ((status & MCI_STATUS_UC) && banks[0] != ~(uint64_t)0) |
|
1526 |
return; |
|
1527 |
if (status & MCI_STATUS_UC) { |
|
1528 |
if ((cenv->mcg_status & MCG_STATUS_MCIP) || |
|
1529 |
!(cenv->cr[4] & CR4_MCE_MASK)) { |
|
1530 |
fprintf(stderr, "injects mce exception while previous " |
|
1531 |
"one is in progress!\n"); |
|
1532 |
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); |
|
1533 |
qemu_system_reset_request(); |
|
1534 |
return; |
|
1535 |
} |
|
1536 |
if (banks[1] & MCI_STATUS_VAL) |
|
1537 |
status |= MCI_STATUS_OVER; |
|
1538 |
banks[2] = addr; |
|
1539 |
banks[3] = misc; |
|
1540 |
cenv->mcg_status = mcg_status; |
|
1541 |
banks[1] = status; |
|
1542 |
cpu_interrupt(cenv, CPU_INTERRUPT_MCE); |
|
1543 |
} else if (!(banks[1] & MCI_STATUS_VAL) |
|
1544 |
|| !(banks[1] & MCI_STATUS_UC)) { |
|
1545 |
if (banks[1] & MCI_STATUS_VAL) |
|
1546 |
status |= MCI_STATUS_OVER; |
|
1547 |
banks[2] = addr; |
|
1548 |
banks[3] = misc; |
|
1549 |
banks[1] = status; |
|
1550 |
} else |
|
1551 |
banks[1] |= MCI_STATUS_OVER; |
|
1552 |
} |
|
1499 | 1553 |
#endif /* !CONFIG_USER_ONLY */ |
1500 | 1554 |
|
1555 |
static void mce_init(CPUX86State *cenv) |
|
1556 |
{ |
|
1557 |
unsigned int bank, bank_num; |
|
1558 |
|
|
1559 |
if (((cenv->cpuid_version >> 8)&0xf) >= 6 |
|
1560 |
&& (cenv->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)) { |
|
1561 |
cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF; |
|
1562 |
cenv->mcg_ctl = ~(uint64_t)0; |
|
1563 |
bank_num = cenv->mcg_cap & 0xff; |
|
1564 |
cenv->mce_banks = qemu_mallocz(bank_num * sizeof(uint64_t) * 4); |
|
1565 |
for (bank = 0; bank < bank_num; bank++) |
|
1566 |
cenv->mce_banks[bank*4] = ~(uint64_t)0; |
|
1567 |
} |
|
1568 |
} |
|
1569 |
|
|
1501 | 1570 |
static void host_cpuid(uint32_t function, uint32_t count, |
1502 | 1571 |
uint32_t *eax, uint32_t *ebx, |
1503 | 1572 |
uint32_t *ecx, uint32_t *edx) |
... | ... | |
1735 | 1804 |
cpu_x86_close(env); |
1736 | 1805 |
return NULL; |
1737 | 1806 |
} |
1807 |
mce_init(env); |
|
1738 | 1808 |
cpu_reset(env); |
1739 | 1809 |
#ifdef CONFIG_KQEMU |
1740 | 1810 |
kqemu_init(env); |
b/target-i386/machine.c | ||
---|---|---|
158 | 158 |
qemu_put_sbe32s(f, &pending_irq); |
159 | 159 |
qemu_put_be32s(f, &env->mp_state); |
160 | 160 |
qemu_put_be64s(f, &env->tsc); |
161 |
} |
|
161 |
|
|
162 |
/* MCE */ |
|
163 |
qemu_put_be64s(f, &env->mcg_cap); |
|
164 |
if (env->mcg_cap) { |
|
165 |
qemu_put_be64s(f, &env->mcg_status); |
|
166 |
qemu_put_be64s(f, &env->mcg_ctl); |
|
167 |
for (i = 0; i < (env->mcg_cap & 0xff); i++) { |
|
168 |
qemu_put_be64s(f, &env->mce_banks[4*i]); |
|
169 |
qemu_put_be64s(f, &env->mce_banks[4*i + 1]); |
|
170 |
qemu_put_be64s(f, &env->mce_banks[4*i + 2]); |
|
171 |
qemu_put_be64s(f, &env->mce_banks[4*i + 3]); |
|
172 |
} |
|
173 |
} |
|
174 |
} |
|
162 | 175 |
|
163 | 176 |
#ifdef USE_X86LDOUBLE |
164 | 177 |
/* XXX: add that in a FPU generic layer */ |
... | ... | |
349 | 362 |
qemu_get_be64s(f, &env->tsc); |
350 | 363 |
} |
351 | 364 |
|
365 |
if (version_id >= 10) { |
|
366 |
qemu_get_be64s(f, &env->mcg_cap); |
|
367 |
if (env->mcg_cap) { |
|
368 |
qemu_get_be64s(f, &env->mcg_status); |
|
369 |
qemu_get_be64s(f, &env->mcg_ctl); |
|
370 |
for (i = 0; i < (env->mcg_cap & 0xff); i++) { |
|
371 |
qemu_get_be64s(f, &env->mce_banks[4*i]); |
|
372 |
qemu_get_be64s(f, &env->mce_banks[4*i + 1]); |
|
373 |
qemu_get_be64s(f, &env->mce_banks[4*i + 2]); |
|
374 |
qemu_get_be64s(f, &env->mce_banks[4*i + 3]); |
|
375 |
} |
|
376 |
} |
|
377 |
} |
|
378 |
|
|
352 | 379 |
/* XXX: ensure compatiblity for halted bit ? */ |
353 | 380 |
/* XXX: compute redundant hflags bits */ |
354 | 381 |
env->hflags = hflags; |
b/target-i386/op_helper.c | ||
---|---|---|
3133 | 3133 |
case MSR_MTRRdefType: |
3134 | 3134 |
env->mtrr_deftype = val; |
3135 | 3135 |
break; |
3136 |
case MSR_MCG_STATUS: |
|
3137 |
env->mcg_status = val; |
|
3138 |
break; |
|
3139 |
case MSR_MCG_CTL: |
|
3140 |
if ((env->mcg_cap & MCG_CTL_P) |
|
3141 |
&& (val == 0 || val == ~(uint64_t)0)) |
|
3142 |
env->mcg_ctl = val; |
|
3143 |
break; |
|
3136 | 3144 |
default: |
3145 |
if ((uint32_t)ECX >= MSR_MC0_CTL |
|
3146 |
&& (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) { |
|
3147 |
uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL; |
|
3148 |
if ((offset & 0x3) != 0 |
|
3149 |
|| (val == 0 || val == ~(uint64_t)0)) |
|
3150 |
env->mce_banks[offset] = val; |
|
3151 |
break; |
|
3152 |
} |
|
3137 | 3153 |
/* XXX: exception ? */ |
3138 | 3154 |
break; |
3139 | 3155 |
} |
... | ... | |
3252 | 3268 |
/* XXX: exception ? */ |
3253 | 3269 |
val = 0; |
3254 | 3270 |
break; |
3271 |
case MSR_MCG_CAP: |
|
3272 |
val = env->mcg_cap; |
|
3273 |
break; |
|
3274 |
case MSR_MCG_CTL: |
|
3275 |
if (env->mcg_cap & MCG_CTL_P) |
|
3276 |
val = env->mcg_ctl; |
|
3277 |
else |
|
3278 |
val = 0; |
|
3279 |
break; |
|
3280 |
case MSR_MCG_STATUS: |
|
3281 |
val = env->mcg_status; |
|
3282 |
break; |
|
3255 | 3283 |
default: |
3284 |
if ((uint32_t)ECX >= MSR_MC0_CTL |
|
3285 |
&& (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) { |
|
3286 |
uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL; |
|
3287 |
val = env->mce_banks[offset]; |
|
3288 |
break; |
|
3289 |
} |
|
3256 | 3290 |
/* XXX: exception ? */ |
3257 | 3291 |
val = 0; |
3258 | 3292 |
break; |
Also available in: Unified diff