MCE features are detected, initialized and injected via the corresponding KVM ioctl. Signed-off-by: Huang Ying <ying.huang@xxxxxxxxx> --- kvm-all.c | 24 ++++++++++++++++++ kvm.h | 4 +++ target-i386/helper.c | 8 +++++- target-i386/kvm.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 101 insertions(+), 2 deletions(-) --- a/kvm-all.c +++ b/kvm-all.c @@ -765,6 +765,30 @@ int kvm_has_sync_mmu(void) return 0; } +int kvm_has_mce(void) +{ +#ifdef KVM_CAP_MCE + KVMState *s = kvm_state; + int r; + + r = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_MCE); + if (r > 0) + return r; +#endif + return 0; +} + +int kvm_get_mce_cap_supported(uint64_t *mce_cap) +{ +#ifdef KVM_CAP_MCE + KVMState *s = kvm_state; + + return kvm_ioctl(s, KVM_X86_GET_MCE_CAP_SUPPORTED, mce_cap); +#else + return -ENOSYS; +#endif +} + #ifdef KVM_CAP_SET_GUEST_DEBUG struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, target_ulong pc) --- a/kvm.h +++ b/kvm.h @@ -47,6 +47,10 @@ int kvm_log_start(target_phys_addr_t phy int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size); int kvm_has_sync_mmu(void); +int kvm_has_mce(void); +int kvm_get_mce_cap_supported(uint64_t *mce_cap); +void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, + uint64_t mcg_status, uint64_t addr, uint64_t misc); int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1440,6 +1440,11 @@ void cpu_inject_x86_mce(CPUState *cenv, unsigned bank_num = mcg_cap & 0xff; uint64_t *banks = cenv->mce_banks; + if (kvm_enabled()) { + kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc); + return; + } + if (bank >= bank_num || !(status & MCI_STATUS_VAL)) return; @@ -1757,7 +1762,8 @@ CPUX86State *cpu_x86_init(const char *cp cpu_x86_close(env); return NULL; } - mce_init(env); + if (!kvm_enabled()) + mce_init(env); cpu_reset(env); #ifdef CONFIG_KQEMU kqemu_init(env); --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -34,6 +34,42 @@ do { } while (0) #endif +static void kvm_arch_setup_mce(CPUState *env) +{ + int banks; + int ret; + uint64_t mcg_cap; + +#ifdef KVM_CAP_MCE + if (((env->cpuid_version >> 8) & 0xf) < 6) + return; + + if ((env->cpuid_features & (CPUID_MCE|CPUID_MCA)) != (CPUID_MCE|CPUID_MCA)) + return; + + banks = kvm_has_mce(); + if (banks <= 0) + return; + + ret = kvm_get_mce_cap_supported(&mcg_cap); + if (ret) { + fprintf(stderr, "kvm_get_mce_cap_supported FAILED\n"); + return; + } + + if (banks > MCE_BANKS_DEF) + banks = MCE_BANKS_DEF; + mcg_cap &= MCE_CAP_DEF; + mcg_cap |= banks; + + if (kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, &mcg_cap)) { + fprintf(stderr, "kvm: setup mce FAILED\n"); + return; + } + env->mcg_cap = mcg_cap; +#endif +} + int kvm_arch_init_vcpu(CPUState *env) { struct { @@ -42,6 +78,7 @@ int kvm_arch_init_vcpu(CPUState *env) } __attribute__((packed)) cpuid_data; uint32_t limit, i, j, cpuid_i; uint32_t unused; + int ret; cpuid_i = 0; @@ -107,7 +144,13 @@ int kvm_arch_init_vcpu(CPUState *env) cpuid_data.cpuid.nent = cpuid_i; - return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data); + ret = kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data); + if (ret < 0) + return ret; + + kvm_arch_setup_mce(env); + + return 0; } static int kvm_has_msr_star(CPUState *env) @@ -665,6 +708,28 @@ int kvm_arch_handle_exit(CPUState *env, return ret; } +void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, + uint64_t mcg_status, uint64_t addr, uint64_t misc) +{ +#ifdef KVM_CAP_MCE + struct kvm_x86_mce mce = { + .bank = bank, + .status = status, + .mcg_status = mcg_status, + .addr = addr, + .misc = misc, + }; + int ret; + + if (kvm_has_mce() <= 0) + return; + + ret = kvm_vcpu_ioctl(cenv, KVM_X86_SET_MCE, &mce); + if (ret < 0) + fprintf(stderr, "kvm: inject mce FAILED\n"); +#endif +} + #ifdef KVM_CAP_SET_GUEST_DEBUG int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) {
Attachment:
signature.asc
Description: This is a digitally signed message part