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; |