From patchwork Fri Jun 3 06:09:43 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Haozhong Zhang X-Patchwork-Id: 9151877 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4A99E60221 for ; Fri, 3 Jun 2016 06:11:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 389BC26E5D for ; Fri, 3 Jun 2016 06:11:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2A63E282EE; Fri, 3 Jun 2016 06:11:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8DF2B26E5D for ; Fri, 3 Jun 2016 06:11:05 +0000 (UTC) Received: from localhost ([::1]:52180 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8iK0-0003yu-LR for patchwork-qemu-devel@patchwork.kernel.org; Fri, 03 Jun 2016 02:11:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42622) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8iJV-0003vH-Az for qemu-devel@nongnu.org; Fri, 03 Jun 2016 02:10:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1b8iJR-0003ti-18 for qemu-devel@nongnu.org; Fri, 03 Jun 2016 02:10:32 -0400 Received: from mga04.intel.com ([192.55.52.120]:14790) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1b8iJQ-0003td-MA for qemu-devel@nongnu.org; Fri, 03 Jun 2016 02:10:28 -0400 Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga104.fm.intel.com with ESMTP; 02 Jun 2016 23:10:27 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.26,410,1459839600"; d="scan'208";a="820787122" Received: from hz-desktop.sh.intel.com (HELO localhost) ([10.239.13.126]) by orsmga003.jf.intel.com with ESMTP; 02 Jun 2016 23:10:25 -0700 From: Haozhong Zhang To: qemu-devel@nongnu.org Date: Fri, 3 Jun 2016 14:09:43 +0800 Message-Id: <20160603060944.17373-2-haozhong.zhang@intel.com> X-Mailer: git-send-email 2.8.3 In-Reply-To: <20160603060944.17373-1-haozhong.zhang@intel.com> References: <20160603060944.17373-1-haozhong.zhang@intel.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 192.55.52.120 Subject: [Qemu-devel] [PATCH v3 1/2] target-i386: KVM: add basic Intel LMCE support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Haozhong Zhang , Tony Luck , Eduardo Habkost , kvm@vger.kernel.org, "Michael S . Tsirkin" , Marcelo Tosatti , Andi Kleen , Paolo Bonzini , Ashok Raj , Boris Petkov , Richard Henderson Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP This patch adds the support to inject SRAR and SRAO as LMCE, i.e. they will be injected to only one VCPU rather than broadcast to all VCPUs. As KVM reports LMCE support on Intel platforms, this features is only available on Intel platforms. Signed-off-by: Ashok Raj Signed-off-by: Haozhong Zhang --- Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Cc: Marcelo Tosatti Cc: Boris Petkov Cc: kvm@vger.kernel.org Cc: Tony Luck Cc: Andi Kleen --- target-i386/cpu.c | 26 ++++++++++++++++++++++++++ target-i386/cpu.h | 13 ++++++++++++- target-i386/kvm.c | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 895a386..9b4dbab 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2777,6 +2777,18 @@ static void x86_cpu_machine_reset_cb(void *opaque) } #endif +static bool lmce_supported(void) +{ + uint64_t mce_cap; + + if (!kvm_enabled() || + kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) { + return false; + } + + return !!(mce_cap & MCG_LMCE_P); +} + static void mce_init(X86CPU *cpu) { CPUX86State *cenv = &cpu->env; @@ -2786,6 +2798,20 @@ static void mce_init(X86CPU *cpu) && (cenv->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) == (CPUID_MCE | CPUID_MCA)) { cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF; + + if (cpu->enable_lmce) { + if (lmce_supported()) { + cenv->mcg_cap |= MCG_LMCE_P; + cenv->msr_ia32_feature_control |= + MSR_IA32_FEATURE_CONTROL_LMCE | + MSR_IA32_FEATURE_CONTROL_LOCKED; + } else { + error_report("Warning: KVM unavailable or not support LMCE, " + "LMCE disabled"); + cpu->enable_lmce = false; + } + } + cenv->mcg_ctl = ~(uint64_t)0; for (bank = 0; bank < MCE_BANKS_DEF; bank++) { cenv->mce_banks[bank * 4] = ~(uint64_t)0; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 0426459..2d411ba 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -292,6 +292,7 @@ #define MCG_CTL_P (1ULL<<8) /* MCG_CAP register available */ #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ +#define MCG_LMCE_P (1ULL<<27) /* Local Machine Check Supported */ #define MCE_CAP_DEF (MCG_CTL_P|MCG_SER_P) #define MCE_BANKS_DEF 10 @@ -301,6 +302,9 @@ #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ #define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */ #define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */ +#define MCG_STATUS_LMCE (1ULL<<3) /* Local MCE signaled */ + +#define MCG_EXT_CTL_LMCE_EN (1ULL<<0) /* Local MCE enabled */ #define MCI_STATUS_VAL (1ULL<<63) /* valid error */ #define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */ @@ -325,6 +329,8 @@ #define MSR_IA32_APICBASE_ENABLE (1<<11) #define MSR_IA32_APICBASE_BASE (0xfffffU<<12) #define MSR_IA32_FEATURE_CONTROL 0x0000003a +#define MSR_IA32_FEATURE_CONTROL_LOCKED (1<<0) +#define MSR_IA32_FEATURE_CONTROL_LMCE (1<<20) #define MSR_TSC_ADJUST 0x0000003b #define MSR_IA32_TSCDEADLINE 0x6e0 @@ -343,6 +349,7 @@ #define MSR_MCG_CAP 0x179 #define MSR_MCG_STATUS 0x17a #define MSR_MCG_CTL 0x17b +#define MSR_MCG_EXT_CTL 0x4d0 #define MSR_P6_EVNTSEL0 0x186 @@ -1011,7 +1018,6 @@ typedef struct CPUX86State { uint64_t mcg_status; uint64_t msr_ia32_misc_enable; - uint64_t msr_ia32_feature_control; uint64_t msr_fixed_ctr_ctrl; uint64_t msr_global_ctrl; @@ -1104,8 +1110,11 @@ typedef struct CPUX86State { int64_t user_tsc_khz; /* for sanity check only */ void *kvm_xsave_buf; + uint64_t msr_ia32_feature_control; + uint64_t mcg_cap; uint64_t mcg_ctl; + uint64_t mcg_ext_ctl; uint64_t mce_banks[MCE_BANKS_DEF*4]; uint64_t tsc_aux; @@ -1173,6 +1182,8 @@ struct X86CPU { */ bool enable_pmu; + bool enable_lmce; + /* in order to simplify APIC support, we leave this pointer to the user */ struct DeviceState *apic_state; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index abf50e6..ea442b3 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -107,6 +107,8 @@ static int has_xsave; static int has_xcrs; static int has_pit_state2; +static bool has_msr_mcg_ext_ctl; + int kvm_has_pit_state2(void) { return has_pit_state2; @@ -378,10 +380,12 @@ static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap, static void kvm_mce_inject(X86CPU *cpu, hwaddr paddr, int code) { + CPUState *cs = CPU(cpu); CPUX86State *env = &cpu->env; uint64_t status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S; uint64_t mcg_status = MCG_STATUS_MCIP; + int flags = 0; if (code == BUS_MCEERR_AR) { status |= MCI_STATUS_AR | 0x134; @@ -390,10 +394,19 @@ static void kvm_mce_inject(X86CPU *cpu, hwaddr paddr, int code) status |= 0xc0; mcg_status |= MCG_STATUS_RIPV; } + + flags = cpu_x86_support_mca_broadcast(env) ? MCE_INJECT_BROADCAST : 0; + /* We need to read back the value of MSR_EXT_MCG_CTL that was set by the + * guest kernel back into env->mcg_ext_ctl. + */ + cpu_synchronize_state(cs); + if (env->mcg_ext_ctl & MCG_EXT_CTL_LMCE_EN) { + mcg_status |= MCG_STATUS_LMCE; + flags = 0; + } + cpu_x86_inject_mce(NULL, cpu, 9, status, mcg_status, paddr, - (MCM_ADDR_PHYS << 6) | 0xc, - cpu_x86_support_mca_broadcast(env) ? - MCE_INJECT_BROADCAST : 0); + (MCM_ADDR_PHYS << 6) | 0xc, flags); } static void hardware_memory_error(void) @@ -878,7 +891,12 @@ int kvm_arch_init_vcpu(CPUState *cs) c = cpuid_find_entry(&cpuid_data.cpuid, 1, 0); if (c) { has_msr_feature_control = !!(c->ecx & CPUID_EXT_VMX) || - !!(c->ecx & CPUID_EXT_SMX); + !!(c->ecx & CPUID_EXT_SMX) || + !!(env->mcg_cap & MCG_LMCE_P); + } + + if (has_msr_feature_control && (env->mcg_cap & MCG_LMCE_P)) { + has_msr_mcg_ext_ctl = true; } c = cpuid_find_entry(&cpuid_data.cpuid, 0x80000007, 0); @@ -1702,6 +1720,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_add(cpu, MSR_MCG_STATUS, env->mcg_status); kvm_msr_entry_add(cpu, MSR_MCG_CTL, env->mcg_ctl); + if (has_msr_mcg_ext_ctl) { + kvm_msr_entry_add(cpu, MSR_MCG_EXT_CTL, env->mcg_ext_ctl); + } for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++) { kvm_msr_entry_add(cpu, MSR_MC0_CTL + i, env->mce_banks[i]); } @@ -2005,6 +2026,9 @@ static int kvm_get_msrs(X86CPU *cpu) if (env->mcg_cap) { kvm_msr_entry_add(cpu, MSR_MCG_STATUS, 0); kvm_msr_entry_add(cpu, MSR_MCG_CTL, 0); + if (has_msr_mcg_ext_ctl) { + kvm_msr_entry_add(cpu, MSR_MCG_EXT_CTL, 0); + } for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++) { kvm_msr_entry_add(cpu, MSR_MC0_CTL + i, 0); } @@ -2133,6 +2157,9 @@ static int kvm_get_msrs(X86CPU *cpu) case MSR_MCG_CTL: env->mcg_ctl = msrs[i].data; break; + case MSR_MCG_EXT_CTL: + env->mcg_ext_ctl = msrs[i].data; + break; case MSR_IA32_MISC_ENABLE: env->msr_ia32_misc_enable = msrs[i].data; break;