Received: by 2002:ac0:aed5:0:0:0:0:0 with SMTP id t21csp910294imb; Fri, 1 Mar 2019 18:55:39 -0800 (PST) X-Google-Smtp-Source: AHgI3IbgoEs1tr4aM7Iwa8bFZKRZleUcuH+TtFVYRkK+tt6aj6q4yndlMV9dYhkNlASmloJ25v3c X-Received: by 2002:aa7:9102:: with SMTP id 2mr8831360pfh.179.1551495339536; Fri, 01 Mar 2019 18:55:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1551495339; cv=none; d=google.com; s=arc-20160816; b=salLFJn8U3ikyjPTYAZpyNQAbXj/JRpEz1c7IpDN+XEVSKVE9BtliDaLoa2xOs/DnP jAqeVMNDXiNuvH5/eV0WF4gOnT/0SxdV2R3BQ1gLplAORIlcP2U96x46Jk42gK2gsIbv YKDVK97g+O9TNHA9dtNnbjAOUyEXFUcqYK6Ru29832kE0QA3HH5Iu4JEe6NqFVJhAwOX NTumLo17+5LZzEXPi10gxP3FD2B8HYkWIEVTUtOXAJiq1AWFIOkhlYXF24zDSjKjKoSS s4kM+QTgoe9djh9amv6mUaRQE2g0TH+msbARRM5VnhlaiWu/MkdPCv2s6B6m9silUWlL cdXA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=hhR0ykOhQAJb7o5lHPxORriCSIDMk9i1EiHyad84UfM=; b=IQsIzwX16gPmJn0yOygys+a6YUWtK9XXTyKNwW/7JpVR0UQkfoAmR8XfSRUek5ljcI RStEm+XzUfGIaPl6FRGuaHXjTwpVhsjFVehOaUyIx0L01wUuhKL7d+z/u42YbgZfuQYe 0beq9yDpHu/52A5vQO/xYmlT0YZAljt9OtTze8tA7ONdFyx9xOAbBjx6UIvuv/IXtQq5 uJVgr5aIliCLgL1+G+BgZC4CuDG4A8oyn1rPQirCYI1/+Kzix7hDRWFZC1qHiL7yympY rO/b+3VENxfZl+0qhtTpdagCz+4zE1FnBjUUSe8PYfvaMpAlA1U2e2/aY0jnul2YUVqS Xarw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 97si12091832ple.392.2019.03.01.18.55.24; Fri, 01 Mar 2019 18:55:39 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728193AbfCBCxR (ORCPT + 99 others); Fri, 1 Mar 2019 21:53:17 -0500 Received: from mga04.intel.com ([192.55.52.120]:49771 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727836AbfCBCwb (ORCPT ); Fri, 1 Mar 2019 21:52:31 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 01 Mar 2019 18:52:29 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.58,430,1544515200"; d="scan'208";a="148572619" Received: from romley-ivt3.sc.intel.com ([172.25.110.60]) by fmsmga004.fm.intel.com with ESMTP; 01 Mar 2019 18:52:28 -0800 From: Fenghua Yu To: "Thomas Gleixner" , "Ingo Molnar" , "Borislav Petkov" , "H Peter Anvin" , "Paolo Bonzini" , "Dave Hansen" , "Ashok Raj" , "Peter Zijlstra" , "Ravi V Shankar" , "Xiaoyao Li " Cc: "linux-kernel" , "x86" , kvm@vger.kernel.org, Fenghua Yu Subject: [PATCH v4 11/17] x86/clearcpuid: Clear CPUID bit in CPUID faulting Date: Fri, 1 Mar 2019 18:45:05 -0800 Message-Id: <1551494711-213533-12-git-send-email-fenghua.yu@intel.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1551494711-213533-1-git-send-email-fenghua.yu@intel.com> References: <1551494711-213533-1-git-send-email-fenghua.yu@intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Peter Zijlstra After kernel clears a CPUID bit through clearcpuid or other kernel options, CPUID instruction executed from user space should see the same value for the bit. The CPUID faulting handler returns the cleared bit to user. Signed-off-by: Peter Zijlstra Signed-off-by: Fenghua Yu --- arch/x86/include/asm/cpufeature.h | 4 +++ arch/x86/kernel/cpu/common.c | 2 ++ arch/x86/kernel/cpu/cpuid-deps.c | 52 ++++++++++++++++++++++++++++++++++++ arch/x86/kernel/cpu/intel.c | 55 ++++++++++++++++++++++++++++++++++++--- arch/x86/kernel/cpu/scattered.c | 17 ++++++++++++ arch/x86/kernel/process.c | 3 +++ arch/x86/kernel/traps.c | 11 ++++++++ 7 files changed, 141 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 6792088525e3..c4ac787d9b85 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -227,5 +227,9 @@ static __always_inline __pure bool _static_cpu_has(u16 bit) #define CPU_FEATURE_TYPEVAL boot_cpu_data.x86_vendor, boot_cpu_data.x86, \ boot_cpu_data.x86_model +extern int cpuid_fault; +u32 scattered_cpuid_mask(u32 leaf, u32 count, enum cpuid_regs_idx reg); +u32 cpuid_cap_mask(u32 leaf, u32 count, enum cpuid_regs_idx reg); + #endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */ #endif /* _ASM_X86_CPUFEATURE_H */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 26723ea322fa..aa2658136fe0 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1502,6 +1502,8 @@ void print_cpu_info(struct cpuinfo_x86 *c) pr_cont(")\n"); } +int cpuid_fault; + /* * clearcpuid= was already parsed in fpu__init_parse_early_param. * But we need to keep a dummy __setup around otherwise it would diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c index b84b133d0ebd..f6c77dcf186d 100644 --- a/arch/x86/kernel/cpu/cpuid-deps.c +++ b/arch/x86/kernel/cpu/cpuid-deps.c @@ -113,9 +113,61 @@ static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature) { + if (boot_cpu_has(feature)) + cpuid_fault = 1; do_clear_cpu_cap(c, feature); } +u32 cpuid_cap_mask(u32 leaf, u32 count, enum cpuid_regs_idx reg) +{ + switch (leaf) { + case 0x1: + if (reg == CPUID_EDX) + return ~cpu_caps_cleared[CPUID_1_EDX]; + if (reg == CPUID_ECX) + return ~cpu_caps_cleared[CPUID_1_ECX]; + break; + + case 0x6: + if (reg == CPUID_EAX) + return ~cpu_caps_cleared[CPUID_6_EAX]; + break; + + case 0x7: + if (reg == CPUID_EDX) + return ~cpu_caps_cleared[CPUID_7_EDX]; + if (reg == CPUID_ECX) + return ~cpu_caps_cleared[CPUID_7_ECX]; + if (reg == CPUID_EBX && count == 0) + return ~cpu_caps_cleared[CPUID_7_0_EBX]; + break; + + case 0xD: + if (reg == CPUID_EAX) + return ~cpu_caps_cleared[CPUID_D_1_EAX]; + break; + + case 0xF: + if (reg == CPUID_EDX) { + if (count == 0) + return ~cpu_caps_cleared[CPUID_F_0_EDX]; + if (count == 1) + return ~cpu_caps_cleared[CPUID_F_0_EDX]; + } + break; + + case 0x80000007: + if (reg == CPUID_EDX) { + if (test_bit(X86_FEATURE_CONSTANT_TSC, + (unsigned long *)cpu_caps_cleared)) + return ~(1 << 8); + } + break; + } + + return scattered_cpuid_mask(leaf, count, reg); +} + void setup_clear_cpu_cap(unsigned int feature) { do_clear_cpu_cap(NULL, feature); diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 0c44c49f6005..1c1ec413a9a9 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #ifdef CONFIG_X86_64 #include @@ -626,13 +628,60 @@ static void intel_bsp_resume(struct cpuinfo_x86 *c) init_intel_energy_perf(c); } +bool fixup_cpuid_exception(struct pt_regs *regs) +{ + unsigned int leaf, count, eax, ebx, ecx, edx; + unsigned long seg_base = 0; + unsigned char buf[2]; + int not_copied; + + if (!cpuid_fault) + return false; + + if (test_thread_flag(TIF_NOCPUID)) + return false; + + if (!user_64bit_mode(regs)) + seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS); + + if (seg_base == -1L) + return false; + + not_copied = copy_from_user(buf, (void __user *)(seg_base + regs->ip), + sizeof(buf)); + if (not_copied) + return false; + + if (buf[0] != 0x0F || buf[1] != 0xA2) /* CPUID - OF A2 */ + return false; + + leaf = regs->ax; + count = regs->cx; + + cpuid_count(leaf, count, &eax, &ebx, &ecx, &edx); + + regs->ip += 2; + regs->ax = eax & cpuid_cap_mask(leaf, count, CPUID_EAX); + regs->bx = ebx & cpuid_cap_mask(leaf, count, CPUID_EBX); + regs->cx = ecx & cpuid_cap_mask(leaf, count, CPUID_ECX); + regs->dx = edx & cpuid_cap_mask(leaf, count, CPUID_EDX); + + return true; +} + static void init_cpuid_fault(struct cpuinfo_x86 *c) { u64 msr; - if (!rdmsrl_safe(MSR_PLATFORM_INFO, &msr)) { - if (msr & MSR_PLATFORM_INFO_CPUID_FAULT) - set_cpu_cap(c, X86_FEATURE_CPUID_FAULT); + if (rdmsrl_safe(MSR_PLATFORM_INFO, &msr)) + return; + + if (msr & MSR_PLATFORM_INFO_CPUID_FAULT) { + set_cpu_cap(c, X86_FEATURE_CPUID_FAULT); + if (cpuid_fault) { + this_cpu_or(msr_misc_features_shadow, + MSR_MISC_FEATURES_ENABLES_CPUID_FAULT); + } } } diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 94aa1c72ca98..353756c27096 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -62,3 +62,20 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c) set_cpu_cap(c, cb->feature); } } + +u32 scattered_cpuid_mask(u32 leaf, u32 count, enum cpuid_regs_idx reg) +{ + const struct cpuid_bit *cb; + u32 mask = ~0U; + + for (cb = cpuid_bits; cb->feature; cb++) { + if (cb->level == leaf && cb->sub_leaf == count && + cb->reg == reg) { + if (test_bit(cb->feature, + (unsigned long *)cpu_caps_cleared)) + mask &= ~BIT(cb->bit); + } + } + + return mask; +} diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 90ae0ca51083..1bba1a3c0b01 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -196,6 +196,9 @@ static void set_cpuid_faulting(bool on) { u64 msrval; + if (cpuid_fault) + return; + msrval = this_cpu_read(msr_misc_features_shadow); msrval &= ~MSR_MISC_FEATURES_ENABLES_CPUID_FAULT; msrval |= (on << MSR_MISC_FEATURES_ENABLES_CPUID_FAULT_BIT); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 9b7c4ca8f0a7..c43c2608332e 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -517,6 +517,12 @@ dotraplinkage void do_bounds(struct pt_regs *regs, long error_code) do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, 0, NULL); } +#ifdef CONFIG_CPU_SUP_INTEL +extern bool fixup_cpuid_exception(struct pt_regs *regs); +#else +static inline bool fixup_cpuid_exception(struct pt_regs *regs) { return false; } +#endif + dotraplinkage void do_general_protection(struct pt_regs *regs, long error_code) { @@ -531,6 +537,11 @@ do_general_protection(struct pt_regs *regs, long error_code) return; } + if (static_cpu_has(X86_FEATURE_CPUID_FAULT)) { + if (user_mode(regs) && fixup_cpuid_exception(regs)) + return; + } + if (v8086_mode(regs)) { local_irq_enable(); handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); -- 2.7.4