Re: [PATCH] x86/cpu/centaur: Disable X86_FEATURE_FSGSBASE on Zhaoxin C4600

From: Tony W Wang-oc

Date: Tue Mar 17 2026 - 03:41:55 EST



On 2026/3/12 23:52, Dave Hansen wrote:
On 3/11/26 19:14, Tony W Wang-oc wrote:

+       if (c->x86 == 6 && c->x86_model == 15 && c->x86_stepping >= 14) {
+               native_rdmsr(0x1232, dummy, chip_pf);
+               chip_pf = (chip_pf >> 15) & 0x7;
+               c->microcode = intel_get_microcode_revision();
+
+               if ((chip_pf == 0 && c->microcode < 0x20e) ||
+                       (chip_pf == 1 && c->microcode < 0x208)) {
+                       pr_warn_once("CPU has broken FSGSBASE support;
clear FSGSBASE feature\n");
+                       setup_clear_cpu_cap(X86_FEATURE_FSGSBASE);
+               }
+       }
So, I'm sorry but that's not really consistent how we're doing things
these days.

The model needs a symbolic name.

The MSR you're reading is completely undocumented and unnamed.
Sorry, MSR 0x1232 is a Zhaoxin private MSR. Currently, this MSR is not documented in any public specification. It is used to store CPU manufacturing information.

"chip_pf" is nonsensical and unexplained.
chip_pf retrieved from MSR 0x1232 represents the CPU product version.

Code is duplicated across the centaur and zhaoxin files.

Once you have all of that fixed, you should have a simple:

#define CENTAUR_MODEL_FOO VFM_MAKE(X86_VENDOR_CENTAUR, 6, 15)
#define ZHAOXIN_MODEL_BAR VFM_MAKE(X86_VENDOR_ZHAOXIN, 6, 25)

in a central header, plus:

struct x86_cpu_id *naughty_list[] = {
X86_MATCH_VFM_STEPS(CENTAUR_MODEL_FOO, 14, MAX_STEP, 0),
X86_MATCH_VFM_STEPS(ZHAOXIN_MODEL_BAR, MIN_STEP, 3, 0),
{}
};

void check_fsgsbase_bugs()
{
u32 fixed_ucode;

if (!cpu_feature_enabled(X86_FEATURE_FSGSBASE))
return;

c = x86_match_cpu(naughty_list);
if (!c)
return;

chip_pf = ...
if (chip_pf == 0)
fixed_ucode = 0x20e;
if (chip_pf == 1)
fixed_ucode = 0x208;

if (intel_get_microcode_revision() >= fixed_ucode)
return;

pr_warn_once("Broken FSGSBASE support, clearing feature\n");
setup_clear_cpu_cap(X86_FEATURE_FSGSBASE);
}

Then check_fsgsbase_bugs() can pretty much be called anywhere. It can
even be in generic code.

We are also getting some new matching fields in 'x86_cpu_id'. I suspect
'chip_pf' can be stored in there where Intel has the platform_id right
now. But you don't have to do that now.

Could you please go this route rather than copy-and-pasted chunks of
code sprinkled with a healthy dose of magic numbers?
Thank you for providing the example code.

Could you please take another look at the following patch to see if it's acceptable?

diff --git a/MAINTAINERS b/MAINTAINERS
index 364f0bec8748..42093a794056 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29168,6 +29168,7 @@ ZHAOXIN PROCESSOR SUPPORT
 M:    Tony W Wang-oc <TonyWWang-oc@xxxxxxxxxxx>
 L:    linux-kernel@xxxxxxxxxxxxxxx
 S:    Maintained
+F:    arch/x86/include/asm/zhaoxin.h
 F:    arch/x86/kernel/cpu/zhaoxin.c

 ZONED BLOCK DEVICE (BLOCK LAYER)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index be3e3cc963b2..dc71a4adc776 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -1306,5 +1306,7 @@
                         * disabling x2APIC will cause
                         * a #GP
                         */
+/* ZHAOXIN defined MSRs*/
+#define MSR_ZHAOXIN_MFGID        0x00001232

 #endif /* _ASM_X86_MSR_INDEX_H */
diff --git a/arch/x86/include/asm/zhaoxin.h b/arch/x86/include/asm/zhaoxin.h
new file mode 100644
index 000000000000..a3883bb149b4
--- /dev/null
+++ b/arch/x86/include/asm/zhaoxin.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_ZHAOXIN_H
+#define _ASM_X86_ZHAOXIN_H
+
+#include <asm/cpu_device_id.h>
+#include <asm/microcode.h>
+
+#define    ZHAOXIN_MODEL_ZXC    VFM_MAKE(X86_VENDOR_ZHAOXIN, 6, 25)
+#define    CENTAUR_MODEL_ZXC    VFM_MAKE(X86_VENDOR_CENTAUR, 6, 15)
+
+struct x86_cpu_id naughty_list[] = {
+    X86_MATCH_VFM_STEPS(ZHAOXIN_MODEL_ZXC, 0, 3, 0),
+    X86_MATCH_VFM_STEPS(CENTAUR_MODEL_ZXC, 14, 15, 0),
+    {}
+};
+
+void check_fsgsbase_bugs(void);
+
+void check_fsgsbase_bugs(void)
+{
+
+    u32 chip_pf, dummy, fixed_ucode;
+
+    if (!cpu_feature_enabled(X86_FEATURE_FSGSBASE))
+        return;
+
+    if (!x86_match_cpu(naughty_list))
+        return;
+
+    native_rdmsr(MSR_ZHAOXIN_MFGID, dummy, chip_pf);
+
+    /* chip_pf represents product version flag */
+    chip_pf = (chip_pf >> 15) & 0x7;
+
+    if (chip_pf == 0)
+        fixed_ucode = 0x20e;
+    if (chip_pf == 1)
+        fixed_ucode = 0x208;
+
+    if (intel_get_microcode_revision() >= fixed_ucode)
+        return;
+
+    pr_warn_once("Broken FSGSBASE support, clearing feature\n");
+    setup_clear_cpu_cap(X86_FEATURE_FSGSBASE);
+}
+
+#endif
+
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 1c3261cae40c..fe24830a47aa 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -73,6 +73,7 @@
 #include <asm/tdx.h>
 #include <asm/posted_intr.h>
 #include <asm/runtime-const.h>
+#include <asm/zhaoxin.h>

 #include "cpu.h"

@@ -2047,6 +2048,8 @@ static void identify_cpu(struct cpuinfo_x86 *c)
     setup_umip(c);
     setup_lass(c);

+    check_fsgsbase_bugs();
+
     /* Enable FSGSBASE instructions if available. */
     if (cpu_has(c, X86_FEATURE_FSGSBASE)) {
         cr4_set_bits(X86_CR4_FSGSBASE);