diff mbox series

[v9,3/8] x86/split_lock: Introduce flag X86_FEATURE_SLD_FATAL and drop sld_state

Message ID 20200509110542.8159-4-xiaoyao.li@intel.com (mailing list archive)
State New, archived
Headers show
Series KVM: Add virtualization support of split lock detection | expand

Commit Message

Xiaoyao Li May 9, 2020, 11:05 a.m. UTC
Introduce a synthetic feature flag X86_FEATURE_SLD_FATAL, which means
kernel is in sld_fatal mode if set.

Now sld_state is not needed any more that the state of SLD can be
inferred from X86_FEATURE_SPLIT_LOCK_DETECT and X86_FEATURE_SLD_FATAL.

Suggested-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
 arch/x86/include/asm/cpufeatures.h |  1 +
 arch/x86/kernel/cpu/intel.c        | 16 ++++++----------
 2 files changed, 7 insertions(+), 10 deletions(-)

Comments

Andy Lutomirski May 10, 2020, 5:14 a.m. UTC | #1
On Fri, May 8, 2020 at 8:03 PM Xiaoyao Li <xiaoyao.li@intel.com> wrote:
>
> Introduce a synthetic feature flag X86_FEATURE_SLD_FATAL, which means
> kernel is in sld_fatal mode if set.
>
> Now sld_state is not needed any more that the state of SLD can be
> inferred from X86_FEATURE_SPLIT_LOCK_DETECT and X86_FEATURE_SLD_FATAL.

Is it too much to ask for Intel to actually allocate and define a
CPUID bit that means "this CPU *always* sends #AC on a split lock"?
This would be a pure documentation change, but it would make this
architectural rather than something that each hypervisor needs to hack
up.

Meanwhile, I don't see why adding a cpufeature flag is worthwhile to
avoid a less bizarre global variable.  There's no performance issue
here, and the old code looked a lot more comprehensible than the new
code.
Sean Christopherson May 11, 2020, 6:17 p.m. UTC | #2
On Sat, May 09, 2020 at 10:14:02PM -0700, Andy Lutomirski wrote:
> On Fri, May 8, 2020 at 8:03 PM Xiaoyao Li <xiaoyao.li@intel.com> wrote:
> >
> > Introduce a synthetic feature flag X86_FEATURE_SLD_FATAL, which means
> > kernel is in sld_fatal mode if set.
> >
> > Now sld_state is not needed any more that the state of SLD can be
> > inferred from X86_FEATURE_SPLIT_LOCK_DETECT and X86_FEATURE_SLD_FATAL.
> 
> Is it too much to ask for Intel to actually allocate and define a
> CPUID bit that means "this CPU *always* sends #AC on a split lock"?
> This would be a pure documentation change, but it would make this
> architectural rather than something that each hypervisor needs to hack
> up.

The original plan was to request a bit in MSR_TEST_CTRL be documented as
such.  Then we discovered that defining IA32_CORE_CAPABILITIES enumeration
as architectural was an SDM bug[*].  At that point, enumerating SLD to a
KVM guest through a KVM CPUID leaf is the least awful option.  Emulating the
model specific behavior doesn't provide userspace with a sane way to disable
SLD for a guest, and emulating IA32_CORE_CAPABILITIES behavior would be
tantamount to emulating model specific behavior.

Once paravirt is required for basic SLD enumeration, tacking on the "fatal"
indicator is a minor blip.

I agree that having to reinvent the wheel for every hypervisor is completely
ridiculous, but it provides well defined and controllable behavior.  We
could try to get two CPUID bits defined in the SDM, but pushing through all
the bureaucracy that gates SDM changes means we wouldn't have a resolution
for at least multiple months, assuming the proposal was even accepted.

[*] https://lkml.kernel.org/r/20200416205754.21177-3-tony.luck@intel.com
 
> Meanwhile, I don't see why adding a cpufeature flag is worthwhile to
> avoid a less bizarre global variable.  There's no performance issue
> here, and the old code looked a lot more comprehensible than the new
> code.

The flag has two main advantages:

  - Automatically available to modules, i.e. KVM.
  - Visible to userspace in /proc/cpuinfo.

Making the global variable available to KVM is ugly because it either
requires exporting the variable and the enums (which gets especially nasty
because kvm_intel can be built with CONFIG_CPU_SUP_INTEL=n), or requires
adding a dedicated is_sld_fatal() wrapper and thus more exported crud.

And IMO, the feature flag is the less bizarre option once it's "public"
knowledge, e.g. more in line with features that enumerate both basic support
and sub-features via CPUID bits.
diff mbox series

Patch

diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index db189945e9b0..260adfc6c61a 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -286,6 +286,7 @@ 
 #define X86_FEATURE_FENCE_SWAPGS_USER	(11*32+ 4) /* "" LFENCE in user entry SWAPGS path */
 #define X86_FEATURE_FENCE_SWAPGS_KERNEL	(11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
 #define X86_FEATURE_SPLIT_LOCK_DETECT	(11*32+ 6) /* #AC for split lock */
+#define X86_FEATURE_SLD_FATAL		(11*32+ 7) /* split lock detection in fatal mode */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX512_BF16		(12*32+ 5) /* AVX512 BFLOAT16 instructions */
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 4602dac14dcb..93b8ccf2fa11 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -40,12 +40,6 @@  enum split_lock_detect_state {
 	sld_fatal,
 };
 
-/*
- * Default to sld_off because most systems do not support split lock detection
- * split_lock_setup() will switch this to sld_warn on systems that support
- * split lock detect, unless there is a command line override.
- */
-static enum split_lock_detect_state sld_state __ro_after_init = sld_off;
 static u64 msr_test_ctrl_cache __ro_after_init;
 
 /*
@@ -1043,8 +1037,9 @@  static void __init split_lock_setup(void)
 		return;
 	}
 
-	sld_state = state;
 	setup_force_cpu_cap(X86_FEATURE_SPLIT_LOCK_DETECT);
+	if (state == sld_fatal)
+		setup_force_cpu_cap(X86_FEATURE_SLD_FATAL);
 }
 
 /*
@@ -1064,7 +1059,7 @@  static void sld_update_msr(bool on)
 
 static void split_lock_init(void)
 {
-	split_lock_verify_msr(sld_state != sld_off);
+	split_lock_verify_msr(boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT));
 }
 
 static void split_lock_warn(unsigned long ip)
@@ -1083,7 +1078,7 @@  static void split_lock_warn(unsigned long ip)
 
 bool handle_guest_split_lock(unsigned long ip)
 {
-	if (sld_state == sld_warn) {
+	if (!boot_cpu_has(X86_FEATURE_SLD_FATAL)) {
 		split_lock_warn(ip);
 		return true;
 	}
@@ -1100,7 +1095,8 @@  EXPORT_SYMBOL_GPL(handle_guest_split_lock);
 
 bool handle_user_split_lock(struct pt_regs *regs, long error_code)
 {
-	if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal)
+	if ((regs->flags & X86_EFLAGS_AC) ||
+	    boot_cpu_has(X86_FEATURE_SLD_FATAL))
 		return false;
 	split_lock_warn(regs->ip);
 	return true;