Skip to contentSkip to conversation

CPUID and FPU fixes

RFC PATCH Superseded Andy Lutomirski 3 participants 16 messages Dec 6, 2016 – Dec 7, 2016 x86

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover CPUID and FPU fixes

Our CPUID-less FPU detection code was terminally broken and, as far as I can tell, it's been broken for a long, long time. This series tries to improve the situation.

Thoughts?

Andy Lutomirski (5):
x86/cpu: Factor out application of forced cpu caps x86/cpu: Re-apply forced caps every time cpu caps are re-read x86/fpu: Fix "x86/fpu: Legacy x87 FPU detected" message x86/fpu: Fix CPUID-less FPU detection
x86/fpu: Fix the "Giving up, no FPU found" test

Borislav Petkov (1):
x86/CPU: Add X86_FEATURE_CPUID

 arch/x86/include/asm/cpufeatures.h |  2 +-
 arch/x86/kernel/cpu/common.c       | 35 ++++++++++++++++++++++++-----------
 arch/x86/kernel/fpu/init.c         | 30 +++++++++++++++++-------------
 arch/x86/kernel/fpu/xstate.c       |  7 ++++++-
 4 files changed, 48 insertions(+), 26 deletions(-)
Signature · 1 line
2.9.3
#1 lore raw

RFC PATCH 1/6 x86/CPU: Add X86_FEATURE_CPUID

From: Borislav Petkov <[email protected]>

Add a synthetic CPUID flag denoting whether the CPU sports the CPUID instruction or not. This will come useful later when accomodating CPUID-less CPUs.

---
 arch/x86/include/asm/cpufeatures.h | 2 +-
 arch/x86/kernel/cpu/common.c       | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)
arch/x86/include/asm/cpufeatures.h +1 -1
index a4f9aee62217..e6be43b2679a 100644
@@ -100,7 +100,7 @@
 #define X86_FEATURE_XTOPOLOGY	( 3*32+22) /* cpu topology enum extensions */
 #define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */
 #define X86_FEATURE_NONSTOP_TSC	( 3*32+24) /* TSC does not stop in C states */
-/* free, was #define X86_FEATURE_CLFLUSH_MONITOR ( 3*32+25) * "" clflush reqd with monitor */
+#define X86_FEATURE_CPUID	( 3*32+25) /* CPU has CPUID instruction itself */
 #define X86_FEATURE_EXTD_APICID	( 3*32+26) /* has extended APICID (8 bits) */
 #define X86_FEATURE_AMD_DCM     ( 3*32+27) /* multi-node processor */
 #define X86_FEATURE_APERFMPERF	( 3*32+28) /* APERFMPERF */
arch/x86/kernel/cpu/common.c +4 -3
index cc9e980c68ec..37f031f39e27 100644
@@ -800,14 +800,12 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 	c->extended_cpuid_level = 0;
 
-	if (!have_cpuid_p())
-		identify_cpu_without_cpuid(c);
-
 	/* cyrix could have cpuid enabled via c_identify()*/
 	if (have_cpuid_p()) {
 		cpu_detect(c);
 		get_cpu_vendor(c);
 		get_cpu_cap(c);
+		setup_force_cpu_cap(X86_FEATURE_CPUID);
 
 		if (this_cpu->c_early_init)
 			this_cpu->c_early_init(c);
@@ -817,6 +815,9 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 
 		if (this_cpu->c_bsp_init)
 			this_cpu->c_bsp_init(c);
+	 } else {
+		identify_cpu_without_cpuid(c);
+		setup_clear_cpu_cap(X86_FEATURE_CPUID);
 	}
 
 	setup_force_cpu_cap(X86_FEATURE_ALWAYS);
Signature · 1 line
2.9.3
#5 lore raw

RFC PATCH 3/6 x86/cpu: Re-apply forced caps every time cpu caps are re-read

In reply to Andy Lutomirski

Calling get_cpu_cap() will reset a bunch of CPU features. This will cause the system to lose track of force-set and force-cleared featueres in the words that are reset until the end of CPU initialization. This can cause X86_FEATURE_FPU, for example, to change back and forth during boot and potentially confuse CPU setup.

To minimize the chance of confusion, re-apply forced caps every time get_cpu_cap() is called.

---
 arch/x86/kernel/cpu/common.c | 7 +++++++
 1 file changed, 7 insertions(+)
arch/x86/kernel/cpu/common.c +7 -0
index 347ae0a19380..24e1e4004d42 100644
@@ -758,6 +758,13 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
 		c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
 
 	init_scattered_cpuid_features(c);
+
+	/*
+	 * Clear/Set all flags overridden by options, after probe.
+	 * This needs to happen each time we re-probe, which may happen
+	 * several times during CPU initialization.
+	 */
+	apply_forced_caps(c);
 }
 
 static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
Signature · 1 line
2.9.3
#3 lore raw

RFC PATCH 2/6 x86/cpu: Factor out application of forced cpu caps

In reply to Andy Lutomirski

There are multiple call sites that apply forced CPU caps. Factor them into a helper.

---
 arch/x86/kernel/cpu/common.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/common.c +13 -8
index 37f031f39e27..347ae0a19380 100644
@@ -655,6 +655,17 @@ void cpu_detect(struct cpuinfo_x86 *c)
 	}
 }
 
+static void apply_forced_caps(struct cpuinfo_x86 *c)
+{
+	int i;
+
+	for (i = 0; i < NCAPINTS; i++) {
+		c->x86_capability[i] &= ~cpu_caps_cleared[i];
+		c->x86_capability[i] |= cpu_caps_set[i];
+	}
+
+}
+
 void get_cpu_cap(struct cpuinfo_x86 *c)
 {
 	u32 eax, ebx, ecx, edx;
@@ -1042,10 +1053,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 		this_cpu->c_identify(c);
 
 	/* Clear/Set all flags overridden by options, after probe */
-	for (i = 0; i < NCAPINTS; i++) {
-		c->x86_capability[i] &= ~cpu_caps_cleared[i];
-		c->x86_capability[i] |= cpu_caps_set[i];
-	}
+	apply_forced_caps(c);
 
 #ifdef CONFIG_X86_64
 	c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
@@ -1104,10 +1112,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 	 * Clear/Set all flags overridden by options, need do it
 	 * before following smp all cpus cap AND.
 	 */
-	for (i = 0; i < NCAPINTS; i++) {
-		c->x86_capability[i] &= ~cpu_caps_cleared[i];
-		c->x86_capability[i] |= cpu_caps_set[i];
-	}
+	apply_forced_caps(c);
 
 	/*
 	 * On SMP, boot_cpu_data holds the common feature set between
Signature · 1 line
2.9.3
#11 lore raw

RFC PATCH 5/6 x86/fpu: Fix CPUID-less FPU detection

In reply to Andy Lutomirski

The old code didn't work at all because it adjusted the current caps instead of the forced caps. Anything it did would be undone later during cpu identification. Fix that and, while we're at it, improve the logging and don't bother running it if CPUID is available.

---
 arch/x86/kernel/fpu/init.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)
arch/x86/kernel/fpu/init.c +16 -12
index 60dece392b3a..75e1bf3b0319 100644
@@ -50,29 +50,33 @@ void fpu__init_cpu(void)
 
 /*
  * The earliest FPU detection code.
- *
- * Set the X86_FEATURE_FPU CPU-capability bit based on
- * trying to execute an actual sequence of FPU instructions:
  */
 static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
 {
-	unsigned long cr0;
-	u16 fsw, fcw;
+	if (!boot_cpu_has(X86_FEATURE_CPUID) &&
+	    !test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
+		/*
+		 * Set the X86_FEATURE_FPU CPU-capability bit based on
+		 * trying to execute an actual sequence of FPU instructions:
+		 */
 
-	fsw = fcw = 0xffff;
+		unsigned long cr0;
+		u16 fsw, fcw;
 
-	cr0 = read_cr0();
-	cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
-	write_cr0(cr0);
+		fsw = fcw = 0xffff;
+
+		cr0 = read_cr0();
+		cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
+		write_cr0(cr0);
 
-	if (!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
 		asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
 			     : "+m" (fsw), "+m" (fcw));
+		pr_info("x86/fpu: FSW=0x%04hx FCW=0x%04hx\n", fsw, fcw);
 
 		if (fsw == 0 && (fcw & 0x103f) == 0x003f)
-			set_cpu_cap(c, X86_FEATURE_FPU);
+			setup_force_cpu_cap(X86_FEATURE_FPU);
 		else
-			clear_cpu_cap(c, X86_FEATURE_FPU);
+			setup_clear_cpu_cap(X86_FEATURE_FPU);
 	}
 
 #ifndef CONFIG_MATH_EMULATION
Signature · 1 line
2.9.3
#15 lore raw

RFC PATCH 6/6 x86/fpu: Fix the "Giving up, no FPU found" test

In reply to Andy Lutomirski

We would never print "Giving up, no FPU found" because X86_FEATURE_FPU was in REQUIRED_MASK on non-FPU-emulating builds, so the boot_cpu_has() test didn't do anything.

---
 arch/x86/kernel/fpu/init.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/fpu/init.c +1 -1
index 75e1bf3b0319..d41924a72576 100644
@@ -80,7 +80,7 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
 	}
 
 #ifndef CONFIG_MATH_EMULATION
-	if (!boot_cpu_has(X86_FEATURE_FPU)) {
+	if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_FPU)) {
 		pr_emerg("x86/fpu: Giving up, no FPU found and no math emulation present\n");
 		for (;;)
 			asm volatile("hlt");
Signature · 1 line
2.9.3
#7 lore raw

RFC PATCH 4/6 x86/fpu: Fix "x86/fpu: Legacy x87 FPU detected" message

In reply to Andy Lutomirski

That message isn't at all clear -- what does "Legacy x87" even mean?

Clarify it. If there's no FPU, say "x86/fpu: No FPU detected". If there's an FPU that doesn't have XSAVE, say "x86/fpu: Pre-XSAVE x87 FPU detected".

---
 arch/x86/kernel/fpu/xstate.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/kernel/fpu/xstate.c +6 -1
index 1d7770447b3e..2d592b1c75e4 100644
@@ -705,8 +705,13 @@ void __init fpu__init_system_xstate(void)
 	WARN_ON_FPU(!on_boot_cpu);
 	on_boot_cpu = 0;
 
+	if (!boot_cpu_has(X86_FEATURE_FPU)) {
+		pr_info("x86/fpu: No FPU detected.\n");
+		return;
+	}
+
 	if (!boot_cpu_has(X86_FEATURE_XSAVE)) {
-		pr_info("x86/fpu: Legacy x87 FPU detected.\n");
+		pr_info("x86/fpu: Pre-XSAVE x87 FPU detected.\n");
 		return;
 	}
 
Signature · 1 line
2.9.3
maintainer
#2 lore raw

Re: [RFC PATCH 1/6] x86/CPU: Add X86_FEATURE_CPUID

In reply to Andy Lutomirski
Quoted 47 lines · Andy Lutomirski

From: Borislav Petkov <[email protected]>

Add a synthetic CPUID flag denoting whether the CPU sports the CPUID instruction or not. This will come useful later when accomodating CPUID-less CPUs.

---
 arch/x86/include/asm/cpufeatures.h | 2 +-
 arch/x86/kernel/cpu/common.c       | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)
arch/x86/include/asm/cpufeatures.h +1 -1
index a4f9aee62217..e6be43b2679a 100644
@@ -100,7 +100,7 @@
 #define X86_FEATURE_XTOPOLOGY	( 3*32+22) /* cpu topology enum extensions */
 #define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */
 #define X86_FEATURE_NONSTOP_TSC	( 3*32+24) /* TSC does not stop in C states */
-/* free, was #define X86_FEATURE_CLFLUSH_MONITOR ( 3*32+25) * "" clflush reqd with monitor */
+#define X86_FEATURE_CPUID	( 3*32+25) /* CPU has CPUID instruction itself */
 #define X86_FEATURE_EXTD_APICID	( 3*32+26) /* has extended APICID (8 bits) */
 #define X86_FEATURE_AMD_DCM     ( 3*32+27) /* multi-node processor */
 #define X86_FEATURE_APERFMPERF	( 3*32+28) /* APERFMPERF */
arch/x86/kernel/cpu/common.c +1 -3
index cc9e980c68ec..37f031f39e27 100644
@@ -800,14 +800,12 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 	memset(&c->x86_capability, 0, sizeof c->x86_capability);
 	c->extended_cpuid_level = 0;
 
-	if (!have_cpuid_p())
-		identify_cpu_without_cpuid(c);
-
 	/* cyrix could have cpuid enabled via c_identify()*/
 	if (have_cpuid_p()) {
 		cpu_detect(c);
 		get_cpu_vendor(c);
 		get_cpu_cap(c);
+		setup_force_cpu_cap(X86_FEATURE_CPUID);
 
 		if (this_cpu->c_early_init)
 			this_cpu->c_early_init(c);

arch/x86/kernel/cpu/common.c static void __init early_identify_cpu(struct cpuinfo_x86 *c) · line 820

Quoted 6 lines
arch/x86/kernel/cpu/common.c +3 -0
@@ -817,6 +815,9 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 
 		if (this_cpu->c_bsp_init)
 			this_cpu->c_bsp_init(c);
+	 } else {
+		identify_cpu_without_cpuid(c);
+		setup_clear_cpu_cap(X86_FEATURE_CPUID);

checkpatch complains here:

WARNING: Statements should start on a tabstop
#68: FILE: arch/x86/kernel/cpu/common.c:818:
+ } else {

Please reflow tabs.

Signature · 4 lines
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.
maintainer
#4 lore raw

Re: [RFC PATCH 2/6] x86/cpu: Factor out application of forced cpu caps

In reply to Andy Lutomirski
Quoted 15 lines · Andy Lutomirski

There are multiple call sites that apply forced CPU caps. Factor them into a helper.

---
 arch/x86/kernel/cpu/common.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/common.c +0 -0
index 37f031f39e27..347ae0a19380 100644
@@ -655,6 +655,17 @@ void cpu_detect(struct cpuinfo_x86 *c)
 	}
 }

arch/x86/kernel/cpu/common.c void cpu_detect(struct cpuinfo_x86 *c) · line 666

Quoted 10 lines
arch/x86/kernel/cpu/common.c +9 -0
 
+static void apply_forced_caps(struct cpuinfo_x86 *c)
+{
+	int i;
+
+	for (i = 0; i < NCAPINTS; i++) {
+		c->x86_capability[i] &= ~cpu_caps_cleared[i];
+		c->x86_capability[i] |= cpu_caps_set[i];
+	}
+

Superfluous newline.

Quoted 1 line
arch/x86/kernel/cpu/common.c +1 -0
+}
Signature · 4 lines
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.
maintainer
#6 lore raw

Re: [RFC PATCH 3/6] x86/cpu: Re-apply forced caps every time cpu caps are re-read

In reply to Andy Lutomirski
Quoted 19 lines · Andy Lutomirski

Calling get_cpu_cap() will reset a bunch of CPU features. This will cause the system to lose track of force-set and force-cleared featueres in the words that are reset until the end of CPU initialization. This can cause X86_FEATURE_FPU, for example, to change back and forth during boot and potentially confuse CPU setup.

To minimize the chance of confusion, re-apply forced caps every time get_cpu_cap() is called.

---
 arch/x86/kernel/cpu/common.c | 7 +++++++
 1 file changed, 7 insertions(+)
arch/x86/kernel/cpu/common.c +0 -0
index 347ae0a19380..24e1e4004d42 100644

arch/x86/kernel/cpu/common.c void get_cpu_cap(struct cpuinfo_x86 *c) · line 767

Quoted 10 lines
arch/x86/kernel/cpu/common.c +7 -0
@@ -758,6 +758,13 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
 		c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
 
 	init_scattered_cpuid_features(c);
+
+	/*
+	 * Clear/Set all flags overridden by options, after probe.
+	 * This needs to happen each time we re-probe, which may happen
+	 * several times during CPU initialization.
+	 */
+	apply_forced_caps(c);

I guess...

Although I have to say all that early capabilities detection has grown a lot of cruft during the years and is nuts. And calling get_cpu_cap() multiple times is simply plain wrong.

What we should do is read CPUID *once*, filter out caps and set our internal representation bits and be done with it.

Stuff like setup_pku() which *sets* CPUID bits will then have to run *before* we do the detection and that's it.

But I guess that's future work.

Signature · 4 lines
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.
maintainer
#8 lore raw

Re: [RFC PATCH 4/6] x86/fpu: Fix "x86/fpu: Legacy x87 FPU detected" message

In reply to Andy Lutomirski
Quoted 18 lines · Andy Lutomirski

That message isn't at all clear -- what does "Legacy x87" even mean?

Clarify it. If there's no FPU, say "x86/fpu: No FPU detected". If there's an FPU that doesn't have XSAVE, say "x86/fpu: Pre-XSAVE x87 FPU detected".

---
 arch/x86/kernel/fpu/xstate.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/kernel/fpu/xstate.c +0 -0
index 1d7770447b3e..2d592b1c75e4 100644
@@ -705,8 +705,13 @@ void __init fpu__init_system_xstate(void)
 	WARN_ON_FPU(!on_boot_cpu);

arch/x86/kernel/fpu/xstate.c void __init fpu__init_system_xstate(void) · line 714

Quoted 10 lines
arch/x86/kernel/fpu/xstate.c +6 -1
 	on_boot_cpu = 0;
 
+	if (!boot_cpu_has(X86_FEATURE_FPU)) {
+		pr_info("x86/fpu: No FPU detected.\n");
+		return;
+	}
+
 	if (!boot_cpu_has(X86_FEATURE_XSAVE)) {
-		pr_info("x86/fpu: Legacy x87 FPU detected.\n");
+		pr_info("x86/fpu: Pre-XSAVE x87 FPU detected.\n");

Well, there's also FXSAVE and FSAVE. The legacy thing kinda made sense to me here.

Maybe say something like this:

pr_info("x86/fpu: FPU detected: FSAVE|FXSAVE|XSAVE support\n", ...

and use X86_FEATURE_XSAVE and X86_FEATURE_FXSR to print the respective *SAVE string...? FSAVE we issue by default.

Hmm.

Signature · 4 lines
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.
maintainer
#12 lore raw

Re: [RFC PATCH 5/6] x86/fpu: Fix CPUID-less FPU detection

In reply to Andy Lutomirski
Quoted 18 lines · Andy Lutomirski

The old code didn't work at all because it adjusted the current caps instead of the forced caps. Anything it did would be undone later during cpu identification. Fix that and, while we're at it, improve the logging and don't bother running it if CPUID is available.

---
 arch/x86/kernel/fpu/init.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)
arch/x86/kernel/fpu/init.c +0 -0
index 60dece392b3a..75e1bf3b0319 100644
@@ -50,29 +50,33 @@ void fpu__init_cpu(void)
 
 /*
  * The earliest FPU detection code.

arch/x86/kernel/fpu/init.c void fpu__init_cpu(void) · line 57

Quoted 10 lines
arch/x86/kernel/fpu/init.c +2 -5
- *
- * Set the X86_FEATURE_FPU CPU-capability bit based on
- * trying to execute an actual sequence of FPU instructions:
  */
 static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
 {
-	unsigned long cr0;
-	u16 fsw, fcw;
+	if (!boot_cpu_has(X86_FEATURE_CPUID) &&
+	    !test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {

Flip test and save an indentation level.

Quoted 12 lines
arch/x86/kernel/fpu/init.c +6 -4
+		/*
+		 * Set the X86_FEATURE_FPU CPU-capability bit based on
+		 * trying to execute an actual sequence of FPU instructions:
+		 */
 
-	fsw = fcw = 0xffff;
+		unsigned long cr0;
+		u16 fsw, fcw;
 
-	cr0 = read_cr0();
-	cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
-	write_cr0(cr0);

arch/x86/kernel/fpu/init.c void fpu__init_cpu(void) · line 74

Quoted 10 lines
arch/x86/kernel/fpu/init.c +6 -1
+		fsw = fcw = 0xffff;
+
+		cr0 = read_cr0();
+		cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
+		write_cr0(cr0);
 
-	if (!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
 		asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
 			     : "+m" (fsw), "+m" (fcw));
+		pr_info("x86/fpu: FSW=0x%04hx FCW=0x%04hx\n", fsw, fcw);

Why do we want those in dmesg? Maybe KERN_DEBUG?

Signature · 4 lines
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.
#13 lore raw

Re: [RFC PATCH 5/6] x86/fpu: Fix CPUID-less FPU detection

Quoted 17 lines · Borislav Petkov
Quoted 16 lines · Andy Lutomirski

The old code didn't work at all because it adjusted the current caps instead of the forced caps. Anything it did would be undone later during cpu identification. Fix that and, while we're at it, improve the logging and don't bother running it if CPUID is available.

---
 arch/x86/kernel/fpu/init.c | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)
arch/x86/kernel/fpu/init.c +0 -0
index 60dece392b3a..75e1bf3b0319 100644
@@ -50,29 +50,33 @@ void fpu__init_cpu(void)
 
Quoted 14 lines

arch/x86/kernel/fpu/init.c void fpu__init_cpu(void) · line 57

Quoted 12 lines
arch/x86/kernel/fpu/init.c +2 -5
 /*
  * The earliest FPU detection code.
- *
- * Set the X86_FEATURE_FPU CPU-capability bit based on
- * trying to execute an actual sequence of FPU instructions:
  */
 static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
 {
-     unsigned long cr0;
-     u16 fsw, fcw;
+     if (!boot_cpu_has(X86_FEATURE_CPUID) &&
+         !test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {

Flip test and save an indentation level.

How? There's that bit at the bottom to worry about.

Quoted 19 lines
Quoted 19 lines
arch/x86/kernel/fpu/init.c +11 -4
+             /*
+              * Set the X86_FEATURE_FPU CPU-capability bit based on
+              * trying to execute an actual sequence of FPU instructions:
+              */
 
-     fsw = fcw = 0xffff;
+             unsigned long cr0;
+             u16 fsw, fcw;
 
-     cr0 = read_cr0();
-     cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
-     write_cr0(cr0);
+             fsw = fcw = 0xffff;
+
+             cr0 = read_cr0();
+             cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
+             write_cr0(cr0);
 
Quoted 6 lines

arch/x86/kernel/fpu/init.c void fpu__init_cpu(void) · line 74

Quoted 4 lines
arch/x86/kernel/fpu/init.c +1 -1
-     if (!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
              asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
                           : "+m" (fsw), "+m" (fcw));
+             pr_info("x86/fpu: FSW=0x%04hx FCW=0x%04hx\n", fsw, fcw);

Why do we want those in dmesg? Maybe KERN_DEBUG?

For debugging, since this code appears busted in every version of Linux I looked at. It's certainly been busted for quite a few years. And this line won't print on any CPU with CPUID, so it's not going to cause widespread spam. I kind of line the idea of being able to ask users of these ancient CPUs to just send in their logs.

--Andy

#9 lore raw

Re: [RFC PATCH 4/6] x86/fpu: Fix "x86/fpu: Legacy x87 FPU detected" message

In reply to Borislav Petkov
Quoted 33 lines · Borislav Petkov
Quoted 18 lines · Andy Lutomirski

That message isn't at all clear -- what does "Legacy x87" even mean?

Clarify it. If there's no FPU, say "x86/fpu: No FPU detected". If there's an FPU that doesn't have XSAVE, say "x86/fpu: Pre-XSAVE x87 FPU detected".

---
 arch/x86/kernel/fpu/xstate.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/kernel/fpu/xstate.c +0 -0
index 1d7770447b3e..2d592b1c75e4 100644
@@ -705,8 +705,13 @@ void __init fpu__init_system_xstate(void)
      WARN_ON_FPU(!on_boot_cpu);

arch/x86/kernel/fpu/xstate.c void __init fpu__init_system_xstate(void) · line 714

Quoted 10 lines
arch/x86/kernel/fpu/xstate.c +6 -1
      on_boot_cpu = 0;
 
+     if (!boot_cpu_has(X86_FEATURE_FPU)) {
+             pr_info("x86/fpu: No FPU detected.\n");
+             return;
+     }
+
      if (!boot_cpu_has(X86_FEATURE_XSAVE)) {
-             pr_info("x86/fpu: Legacy x87 FPU detected.\n");
+             pr_info("x86/fpu: Pre-XSAVE x87 FPU detected.\n");

Well, there's also FXSAVE and FSAVE. The legacy thing kinda made sense to me here.

Quoted 6 lines

Maybe say something like this:

pr_info("x86/fpu: FPU detected: FSAVE|FXSAVE|XSAVE support\n", ...

and use X86_FEATURE_XSAVE and X86_FEATURE_FXSR to print the respective *SAVE string...? FSAVE we issue by default.

I did something like this for FSAVE vs FXSAVE. XSAVE has its own pile of printouts and I don't feel like I need to add another.

Quoted 8 lines

Hmm.

--
Regards/Gruss,
Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

Signature · 2 lines
Andy Lutomirski
AMA Capital Management, LLC
maintainer
#10 lore raw

Re: [RFC PATCH 4/6] x86/fpu: Fix "x86/fpu: Legacy x87 FPU detected" message

Quoted 2 lines · Andy Lutomirski

I did something like this for FSAVE vs FXSAVE. XSAVE has its own pile of printouts and I don't feel like I need to add another.

So frankly, replacing "legacy" with "pre-XSAVE" is not making it any clearer - it is just calling it differently. IMO.

Dumping those three makes it exact.

But I don't care too much about it - it is in /proc/cpuinfo anyway.

Signature · 4 lines
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.
maintainer
#14 lore raw

Re: [RFC PATCH 5/6] x86/fpu: Fix CPUID-less FPU detection

In reply to Andy Lutomirski
Quoted 1 line · Andy Lutomirski

How? There's that bit at the bottom to worry about.

Even better: carve it out into a separate function. It was begging for it already. Diff ontop of yours:

---

arch/x86/kernel/fpu/init.c +24 -18
Index: b/arch/x86/kernel/fpu/init.c
===================================================================
@@ -49,31 +49,37 @@ void fpu__init_cpu(void)
 }
 
 /*
- * The earliest FPU detection code.
+ * Try to execute an actual sequence of FPU instructions. Our last resort for
+ * FPU detection in case the respective CPUID bit is not set or we don't
+ * support CPUID at all.
  */
-static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
+static bool __fpu__init_poke_fpu(void)
 {
-	if (!boot_cpu_has(X86_FEATURE_CPUID) &&
-	    !test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
-		/*
-		 * Set the X86_FEATURE_FPU CPU-capability bit based on
-		 * trying to execute an actual sequence of FPU instructions:
-		 */
+	unsigned long cr0;
+	u16 fsw, fcw;
 
-		unsigned long cr0;
-		u16 fsw, fcw;
+	fsw = fcw = 0xffff;
 
-		fsw = fcw = 0xffff;
+	cr0 = read_cr0();
+	cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
+	write_cr0(cr0);
 
-		cr0 = read_cr0();
-		cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
-		write_cr0(cr0);
+	asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
+		     : "+m" (fsw), "+m" (fcw));
 
-		asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
-			     : "+m" (fsw), "+m" (fcw));
-		pr_info("x86/fpu: FSW=0x%04hx FCW=0x%04hx\n", fsw, fcw);
+	pr_info("x86/fpu: FSW=0x%04hx FCW=0x%04hx\n", fsw, fcw);
 
-		if (fsw == 0 && (fcw & 0x103f) == 0x003f)
+	return fsw == 0 && (fcw & 0x103f) == 0x003f;
+}
+
+/*
+ * The earliest FPU detection code.
+ */
+static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
+{
+	if (!boot_cpu_has(X86_FEATURE_CPUID) &&
+	    !test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
+		if (__fpu__init_poke_fpu())
 			setup_force_cpu_cap(X86_FEATURE_FPU);
 		else
 			setup_clear_cpu_cap(X86_FEATURE_FPU);
Quoted 2 lines

I kind of line the idea of being able to ask users of these ancient CPUs to just send in their logs.

Prudent :)

Signature · 4 lines
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.