Commit 79c4f6b08009a1d23177c2be8bd003253cf3686a

Authored by Huang Ying
Committed by Anthony Liguori
1 parent 2152390d

QEMU: MCE: Add MCE simulation to qemu/tcg

- MCE features are initialized when VCPU is intialized according to CPUID.
- A monitor command "mce" is added to inject a MCE.
- A new interrupt mask: CPU_INTERRUPT_MCE is added to inject the MCE.

aliguori: fix build for linux-user

Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
cpu-all.h
@@ -770,6 +770,7 @@ extern int use_icount; @@ -770,6 +770,7 @@ extern int use_icount;
770 #define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ 770 #define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */
771 #define CPU_INTERRUPT_INIT 0x400 /* INIT pending. */ 771 #define CPU_INTERRUPT_INIT 0x400 /* INIT pending. */
772 #define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */ 772 #define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */
  773 +#define CPU_INTERRUPT_MCE 0x1000 /* (x86 only) MCE pending. */
773 774
774 void cpu_interrupt(CPUState *s, int mask); 775 void cpu_interrupt(CPUState *s, int mask);
775 void cpu_reset_interrupt(CPUState *env, int mask); 776 void cpu_reset_interrupt(CPUState *env, int mask);
@@ -1071,4 +1072,7 @@ extern int64_t kqemu_ret_excp_count; @@ -1071,4 +1072,7 @@ extern int64_t kqemu_ret_excp_count;
1071 extern int64_t kqemu_ret_intr_count; 1072 extern int64_t kqemu_ret_intr_count;
1072 #endif 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 #endif /* CPU_ALL_H */ 1078 #endif /* CPU_ALL_H */
cpu-exec.c
@@ -400,6 +400,10 @@ int cpu_exec(CPUState *env1) @@ -400,6 +400,10 @@ int cpu_exec(CPUState *env1)
400 env->hflags2 |= HF2_NMI_MASK; 400 env->hflags2 |= HF2_NMI_MASK;
401 do_interrupt(EXCP02_NMI, 0, 0, 0, 1); 401 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
402 next_tb = 0; 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 } else if ((interrupt_request & CPU_INTERRUPT_HARD) && 407 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
404 (((env->hflags2 & HF2_VINTR_MASK) && 408 (((env->hflags2 & HF2_VINTR_MASK) &&
405 (env->hflags2 & HF2_HIF_MASK)) || 409 (env->hflags2 & HF2_HIF_MASK)) ||
monitor.c
@@ -1677,6 +1677,28 @@ static void do_acl_remove(Monitor *mon, const char *aclname, const char *match) @@ -1677,6 +1677,28 @@ static void do_acl_remove(Monitor *mon, const char *aclname, const char *match)
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 static const mon_cmd_t mon_cmds[] = { 1702 static const mon_cmd_t mon_cmds[] = {
1681 #include "qemu-monitor.h" 1703 #include "qemu-monitor.h"
1682 { NULL, NULL, }, 1704 { NULL, NULL, },
@@ -2451,6 +2473,15 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) @@ -2451,6 +2473,15 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline)
2451 void *arg3, void *arg4, void *arg5); 2473 void *arg3, void *arg4, void *arg5);
2452 void (*handler_7)(Monitor *mon, void *arg0, void *arg1, void *arg2, 2474 void (*handler_7)(Monitor *mon, void *arg0, void *arg1, void *arg2,
2453 void *arg3, void *arg4, void *arg5, void *arg6); 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 #ifdef DEBUG 2486 #ifdef DEBUG
2456 monitor_printf(mon, "command='%s'\n", cmdline); 2487 monitor_printf(mon, "command='%s'\n", cmdline);
@@ -2739,6 +2770,21 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline) @@ -2739,6 +2770,21 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline)
2739 handler_7(mon, args[0], args[1], args[2], args[3], args[4], args[5], 2770 handler_7(mon, args[0], args[1], args[2], args[3], args[4], args[5],
2740 args[6]); 2771 args[6]);
2741 break; 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 default: 2788 default:
2743 monitor_printf(mon, "unsupported number of arguments: %d\n", nb_args); 2789 monitor_printf(mon, "unsupported number of arguments: %d\n", nb_args);
2744 goto fail; 2790 goto fail;
qemu-monitor.hx
@@ -615,6 +615,14 @@ Remove all matches from the access control list, and set the default @@ -615,6 +615,14 @@ Remove all matches from the access control list, and set the default
615 policy back to @code{deny}. 615 policy back to @code{deny}.
616 ETEXI 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 STEXI 626 STEXI
619 @end table 627 @end table
620 ETEXI 628 ETEXI
target-i386/cpu.h
@@ -204,6 +204,7 @@ @@ -204,6 +204,7 @@
204 #define CR4_DE_MASK (1 << 3) 204 #define CR4_DE_MASK (1 << 3)
205 #define CR4_PSE_MASK (1 << 4) 205 #define CR4_PSE_MASK (1 << 4)
206 #define CR4_PAE_MASK (1 << 5) 206 #define CR4_PAE_MASK (1 << 5)
  207 +#define CR4_MCE_MASK (1 << 6)
207 #define CR4_PGE_MASK (1 << 7) 208 #define CR4_PGE_MASK (1 << 7)
208 #define CR4_PCE_MASK (1 << 8) 209 #define CR4_PCE_MASK (1 << 8)
209 #define CR4_OSFXSR_SHIFT 9 210 #define CR4_OSFXSR_SHIFT 9
@@ -250,6 +251,17 @@ @@ -250,6 +251,17 @@
250 #define PG_ERROR_RSVD_MASK 0x08 251 #define PG_ERROR_RSVD_MASK 0x08
251 #define PG_ERROR_I_D_MASK 0x10 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 #define MSR_IA32_TSC 0x10 265 #define MSR_IA32_TSC 0x10
254 #define MSR_IA32_APICBASE 0x1b 266 #define MSR_IA32_APICBASE 0x1b
255 #define MSR_IA32_APICBASE_BSP (1<<8) 267 #define MSR_IA32_APICBASE_BSP (1<<8)
@@ -290,6 +302,11 @@ @@ -290,6 +302,11 @@
290 302
291 #define MSR_MTRRdefType 0x2ff 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 #define MSR_EFER 0xc0000080 310 #define MSR_EFER 0xc0000080
294 311
295 #define MSR_EFER_SCE (1 << 0) 312 #define MSR_EFER_SCE (1 << 0)
@@ -678,6 +695,11 @@ typedef struct CPUX86State { @@ -678,6 +695,11 @@ typedef struct CPUX86State {
678 /* in order to simplify APIC support, we leave this pointer to the 695 /* in order to simplify APIC support, we leave this pointer to the
679 user */ 696 user */
680 struct APICState *apic_state; 697 struct APICState *apic_state;
  698 +
  699 + uint64 mcg_cap;
  700 + uint64 mcg_status;
  701 + uint64 mcg_ctl;
  702 + uint64 *mce_banks;
681 } CPUX86State; 703 } CPUX86State;
682 704
683 CPUX86State *cpu_x86_init(const char *cpu_model); 705 CPUX86State *cpu_x86_init(const char *cpu_model);
@@ -842,7 +864,7 @@ static inline int cpu_get_time_fast(void) @@ -842,7 +864,7 @@ static inline int cpu_get_time_fast(void)
842 #define cpu_signal_handler cpu_x86_signal_handler 864 #define cpu_signal_handler cpu_x86_signal_handler
843 #define cpu_list x86_cpu_list 865 #define cpu_list x86_cpu_list
844 866
845 -#define CPU_SAVE_VERSION 9 867 +#define CPU_SAVE_VERSION 10
846 868
847 /* MMU modes definitions */ 869 /* MMU modes definitions */
848 #define MMU_MODE0_SUFFIX _kernel 870 #define MMU_MODE0_SUFFIX _kernel
target-i386/helper.c
@@ -1496,8 +1496,77 @@ static void breakpoint_handler(CPUState *env) @@ -1496,8 +1496,77 @@ static void breakpoint_handler(CPUState *env)
1496 if (prev_debug_excp_handler) 1496 if (prev_debug_excp_handler)
1497 prev_debug_excp_handler(env); 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 #endif /* !CONFIG_USER_ONLY */ 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 static void host_cpuid(uint32_t function, uint32_t count, 1570 static void host_cpuid(uint32_t function, uint32_t count,
1502 uint32_t *eax, uint32_t *ebx, 1571 uint32_t *eax, uint32_t *ebx,
1503 uint32_t *ecx, uint32_t *edx) 1572 uint32_t *ecx, uint32_t *edx)
@@ -1735,6 +1804,7 @@ CPUX86State *cpu_x86_init(const char *cpu_model) @@ -1735,6 +1804,7 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
1735 cpu_x86_close(env); 1804 cpu_x86_close(env);
1736 return NULL; 1805 return NULL;
1737 } 1806 }
  1807 + mce_init(env);
1738 cpu_reset(env); 1808 cpu_reset(env);
1739 #ifdef CONFIG_KQEMU 1809 #ifdef CONFIG_KQEMU
1740 kqemu_init(env); 1810 kqemu_init(env);
target-i386/machine.c
@@ -158,7 +158,20 @@ void cpu_save(QEMUFile *f, void *opaque) @@ -158,7 +158,20 @@ void cpu_save(QEMUFile *f, void *opaque)
158 qemu_put_sbe32s(f, &pending_irq); 158 qemu_put_sbe32s(f, &pending_irq);
159 qemu_put_be32s(f, &env->mp_state); 159 qemu_put_be32s(f, &env->mp_state);
160 qemu_put_be64s(f, &env->tsc); 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 #ifdef USE_X86LDOUBLE 176 #ifdef USE_X86LDOUBLE
164 /* XXX: add that in a FPU generic layer */ 177 /* XXX: add that in a FPU generic layer */
@@ -349,6 +362,20 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) @@ -349,6 +362,20 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
349 qemu_get_be64s(f, &env->tsc); 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 /* XXX: ensure compatiblity for halted bit ? */ 379 /* XXX: ensure compatiblity for halted bit ? */
353 /* XXX: compute redundant hflags bits */ 380 /* XXX: compute redundant hflags bits */
354 env->hflags = hflags; 381 env->hflags = hflags;
target-i386/op_helper.c
@@ -3133,7 +3133,23 @@ void helper_wrmsr(void) @@ -3133,7 +3133,23 @@ void helper_wrmsr(void)
3133 case MSR_MTRRdefType: 3133 case MSR_MTRRdefType:
3134 env->mtrr_deftype = val; 3134 env->mtrr_deftype = val;
3135 break; 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 default: 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 /* XXX: exception ? */ 3153 /* XXX: exception ? */
3138 break; 3154 break;
3139 } 3155 }
@@ -3252,7 +3268,25 @@ void helper_rdmsr(void) @@ -3252,7 +3268,25 @@ void helper_rdmsr(void)
3252 /* XXX: exception ? */ 3268 /* XXX: exception ? */
3253 val = 0; 3269 val = 0;
3254 break; 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 default: 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 /* XXX: exception ? */ 3290 /* XXX: exception ? */
3257 val = 0; 3291 val = 0;
3258 break; 3292 break;