I found there is a qemu-kvm.git on git.kernel.org. I will re-base my patches for that. And I found that the kvm support in qemu (target-i386/kvm.c) is quite different from that in qemu-kvm (kvm/). Where should MCE support goes? To target-i386/kvm.c or kvm/ or both? Best Regards, Huang Ying On Thu, 2009-04-30 at 16:53 +0800, Huang Ying wrote: > - 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. > > Signed-off-by: Huang Ying <ying.huang@xxxxxxxxx> > > --- > cpu-all.h | 4 ++ > cpu-exec.c | 4 ++ > monitor.c | 49 +++++++++++++++++++++++++++++++++ > target-i386/cpu.h | 22 +++++++++++++++ > target-i386/helper.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ > target-i386/op_helper.c | 34 +++++++++++++++++++++++ > 6 files changed, 183 insertions(+) > > --- a/target-i386/cpu.h > +++ b/target-i386/cpu.h > @@ -202,6 +202,7 @@ > #define CR4_DE_MASK (1 << 3) > #define CR4_PSE_MASK (1 << 4) > #define CR4_PAE_MASK (1 << 5) > +#define CR4_MCE_MASK (1 << 6) > #define CR4_PGE_MASK (1 << 7) > #define CR4_PCE_MASK (1 << 8) > #define CR4_OSFXSR_SHIFT 9 > @@ -248,6 +249,17 @@ > #define PG_ERROR_RSVD_MASK 0x08 > #define PG_ERROR_I_D_MASK 0x10 > > +#define MCE_CAP_DEF 0x100 > +#define MCE_BANKS_DEF 4 > + > +#define MCG_CTL_P (1UL<<8) > + > +#define MCG_STATUS_MCIP (1UL<<2) > + > +#define MCI_STATUS_VAL (1UL<<63) > +#define MCI_STATUS_OVER (1UL<<62) > +#define MCI_STATUS_UC (1UL<<61) > + > #define MSR_IA32_TSC 0x10 > #define MSR_IA32_APICBASE 0x1b > #define MSR_IA32_APICBASE_BSP (1<<8) > @@ -288,6 +300,11 @@ > > #define MSR_MTRRdefType 0x2ff > > +#define MSR_MC0_CTL 0x400 > +#define MSR_MC0_STATUS 0x401 > +#define MSR_MC0_ADDR 0x402 > +#define MSR_MC0_MISC 0x403 > + > #define MSR_EFER 0xc0000080 > > #define MSR_EFER_SCE (1 << 0) > @@ -673,6 +690,11 @@ typedef struct CPUX86State { > /* in order to simplify APIC support, we leave this pointer to the > user */ > struct APICState *apic_state; > + > + uint64 mcg_cap; > + uint64 mcg_status; > + uint64 mcg_ctl; > + uint64 *mce_banks; > } CPUX86State; > > CPUX86State *cpu_x86_init(const char *cpu_model); > --- a/target-i386/op_helper.c > +++ b/target-i386/op_helper.c > @@ -3133,7 +3133,23 @@ void helper_wrmsr(void) > case MSR_MTRRdefType: > env->mtrr_deftype = val; > break; > + case MSR_MCG_STATUS: > + env->mcg_status = val; > + break; > + case MSR_MCG_CTL: > + if ((env->mcg_cap & MCG_CTL_P) > + && (val == 0 || val == ~(uint64_t)0)) > + env->mcg_ctl = val; > + break; > default: > + if ((uint32_t)ECX >= MSR_MC0_CTL > + && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) { > + uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL; > + if ((offset & 0x3) != 0 > + || (val == 0 || val == ~(uint64_t)0)) > + env->mce_banks[offset] = val; > + break; > + } > /* XXX: exception ? */ > break; > } > @@ -3252,7 +3268,25 @@ void helper_rdmsr(void) > /* XXX: exception ? */ > val = 0; > break; > + case MSR_MCG_CAP: > + val = env->mcg_cap; > + break; > + case MSR_MCG_CTL: > + if (env->mcg_cap & MCG_CTL_P) > + val = env->mcg_ctl; > + else > + val = 0; > + break; > + case MSR_MCG_STATUS: > + val = env->mcg_status; > + break; > default: > + if ((uint32_t)ECX >= MSR_MC0_CTL > + && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) { > + uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL; > + val = env->mce_banks[offset]; > + break; > + } > /* XXX: exception ? */ > val = 0; > break; > --- a/target-i386/helper.c > +++ b/target-i386/helper.c > @@ -1430,6 +1430,75 @@ static void breakpoint_handler(CPUState > } > #endif /* !CONFIG_USER_ONLY */ > > +/* This should come from sysemu.h - if we could include it here... */ > +void qemu_system_reset_request(void); > + > +void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, > + uint64_t mcg_status, uint64_t addr, uint64_t misc) > +{ > + uint64_t mcg_cap = cenv->mcg_cap; > + unsigned bank_num = mcg_cap & 0xff; > + uint64_t *banks = cenv->mce_banks; > + > + if (bank >= bank_num || !(status & MCI_STATUS_VAL)) > + return; > + > + /* > + * if MSR_MCG_CTL is not all 1s, the uncorrected error > + * reporting is disabled > + */ > + if ((status & MCI_STATUS_UC) && (mcg_cap & MCG_CTL_P) && > + cenv->mcg_ctl != ~(uint64_t)0) > + return; > + banks += 4 * bank; > + /* > + * if MSR_MCi_CTL is not all 1s, the uncorrected error > + * reporting is disabled for the bank > + */ > + if ((status & MCI_STATUS_UC) && banks[0] != ~(uint64_t)0) > + return; > + if (status & MCI_STATUS_UC) { > + if ((cenv->mcg_status & MCG_STATUS_MCIP) || > + !(cenv->cr[4] & CR4_MCE_MASK)) { > + fprintf(stderr, "injects mce exception while previous " > + "one is in progress!\n"); > + qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); > + qemu_system_reset_request(); > + return; > + } > + if (banks[1] & MCI_STATUS_VAL) > + status |= MCI_STATUS_OVER; > + banks[2] = addr; > + banks[3] = misc; > + cenv->mcg_status = mcg_status; > + banks[1] = status; > + cpu_interrupt(cenv, CPU_INTERRUPT_MCE); > + } else if (!(banks[1] & MCI_STATUS_VAL) > + || !(banks[1] & MCI_STATUS_UC)) { > + if (banks[1] & MCI_STATUS_VAL) > + status |= MCI_STATUS_OVER; > + banks[2] = addr; > + banks[3] = misc; > + banks[1] = status; > + } else > + banks[1] |= MCI_STATUS_OVER; > +} > + > +static void mce_init(CPUX86State *cenv) > +{ > + unsigned int bank, bank_num; > + > + if (((cenv->cpuid_version >> 8)&0xf) >= 6 > + && (cenv->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)) { > + cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF; > + cenv->mcg_ctl = ~(uint64_t)0; > + bank_num = cenv->mcg_cap & 0xff; > + cenv->mce_banks = qemu_mallocz(bank_num * sizeof(uint64_t) * 4); > + for (bank = 0; bank < bank_num; bank++) > + cenv->mce_banks[bank*4] = ~(uint64_t)0; > + } > +} > + > static void host_cpuid(uint32_t function, uint32_t count, > uint32_t *eax, uint32_t *ebx, > uint32_t *ecx, uint32_t *edx) > @@ -1688,6 +1757,7 @@ CPUX86State *cpu_x86_init(const char *cp > cpu_x86_close(env); > return NULL; > } > + mce_init(env); > cpu_reset(env); > #ifdef CONFIG_KQEMU > kqemu_init(env); > --- a/monitor.c > +++ b/monitor.c > @@ -1652,6 +1652,28 @@ static void do_acl(Monitor *mon, > } > } > > +#if defined(TARGET_I386) > +static void do_inject_mce(Monitor *mon, > + int cpu_index, int bank, > + unsigned status_hi, unsigned status_lo, > + unsigned mcg_status_hi, unsigned mcg_status_lo, > + unsigned addr_hi, unsigned addr_lo, > + unsigned misc_hi, unsigned misc_lo) > +{ > + CPUState *cenv; > + uint64_t status = ((uint64_t)status_hi << 32) | status_lo; > + uint64_t mcg_status = ((uint64_t)mcg_status_hi << 32) | mcg_status_lo; > + uint64_t addr = ((uint64_t)addr_hi << 32) | addr_lo; > + uint64_t misc = ((uint64_t)misc_hi << 32) | misc_lo; > + > + for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) > + if (cenv->cpu_index == cpu_index && cenv->mcg_cap) { > + cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc); > + break; > + } > +} > +#endif > + > /* Please update qemu-doc.texi when adding or changing commands */ > static const mon_cmd_t mon_cmds[] = { > { "help|?", "s?", help_cmd, > @@ -1768,6 +1790,9 @@ static const mon_cmd_t mon_cmds[] = { > "acl allow vnc.username fred\n" > "acl deny vnc.username bob\n" > "acl reset vnc.username\n" }, > +#if defined(TARGET_I386) > + { "mce", "iillll", do_inject_mce, "cpu bank status mcgstatus addr misc", "inject a MCE on the given CPU"}, > +#endif > { NULL, NULL, }, > }; > > @@ -2513,6 +2538,15 @@ static void monitor_handle_command(Monit > void *arg3, void *arg4, void *arg5); > void (*handler_7)(Monitor *mon, void *arg0, void *arg1, void *arg2, > void *arg3, void *arg4, void *arg5, void *arg6); > + void (*handler_8)(Monitor *mon, void *arg0, void *arg1, void *arg2, > + void *arg3, void *arg4, void *arg5, void *arg6, > + void *arg7); > + void (*handler_9)(Monitor *mon, void *arg0, void *arg1, void *arg2, > + void *arg3, void *arg4, void *arg5, void *arg6, > + void *arg7, void *arg8); > + void (*handler_10)(Monitor *mon, void *arg0, void *arg1, void *arg2, > + void *arg3, void *arg4, void *arg5, void *arg6, > + void *arg7, void *arg8, void *arg9); > > #ifdef DEBUG > monitor_printf(mon, "command='%s'\n", cmdline); > @@ -2810,6 +2844,21 @@ static void monitor_handle_command(Monit > handler_7(mon, args[0], args[1], args[2], args[3], args[4], args[5], > args[6]); > break; > + case 8: > + handler_8 = cmd->handler; > + handler_8(mon, args[0], args[1], args[2], args[3], args[4], args[5], > + args[6], args[7]); > + break; > + case 9: > + handler_9 = cmd->handler; > + handler_9(mon, args[0], args[1], args[2], args[3], args[4], args[5], > + args[6], args[7], args[8]); > + break; > + case 10: > + handler_10 = cmd->handler; > + handler_10(mon, args[0], args[1], args[2], args[3], args[4], args[5], > + args[6], args[7], args[8], args[9]); > + break; > default: > monitor_printf(mon, "unsupported number of arguments: %d\n", nb_args); > goto fail; > --- a/cpu-all.h > +++ b/cpu-all.h > @@ -769,6 +769,7 @@ extern int use_icount; > #define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ > #define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */ > #define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ > +#define CPU_INTERRUPT_MCE 0x400 /* (x86 only) MCE pending. */ > > void cpu_interrupt(CPUState *s, int mask); > void cpu_reset_interrupt(CPUState *env, int mask); > @@ -910,6 +911,9 @@ void *qemu_get_ram_ptr(ram_addr_t addr); > /* This should not be used by devices. */ > ram_addr_t qemu_ram_addr_from_host(void *ptr); > > +void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, > + uint64_t mcg_status, uint64_t addr, uint64_t misc); > + > int cpu_register_io_memory(int io_index, > CPUReadMemoryFunc **mem_read, > CPUWriteMemoryFunc **mem_write, > --- a/cpu-exec.c > +++ b/cpu-exec.c > @@ -384,6 +384,10 @@ int cpu_exec(CPUState *env1) > env->hflags2 |= HF2_NMI_MASK; > do_interrupt(EXCP02_NMI, 0, 0, 0, 1); > next_tb = 0; > + } else if (interrupt_request & CPU_INTERRUPT_MCE) { > + env->interrupt_request &= ~CPU_INTERRUPT_MCE; > + do_interrupt(EXCP12_MCHK, 0, 0, 0, 0); > + next_tb = 0; > } else if ((interrupt_request & CPU_INTERRUPT_HARD) && > (((env->hflags2 & HF2_VINTR_MASK) && > (env->hflags2 & HF2_HIF_MASK)) || >
Attachment:
signature.asc
Description: This is a digitally signed message part