Commit 79c4f6b08009a1d23177c2be8bd003253cf3686a
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>
Showing
8 changed files
with
217 additions
and
2 deletions
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; |