The existing functions work but the register clobbers are wrong, so
strange bugs results.

The original functions were taken from a very old version of Linux.
Update them from Linux 6.13

Signed-off-by: Simon Glass <s...@chromium.org>
---

(no changes since v3)

Changes in v3:
- Add new patch to update cpuid_eax et al to work on amd64

 arch/x86/include/asm/cpu.h | 75 +++++++++++++-------------------------
 1 file changed, 25 insertions(+), 50 deletions(-)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 1f1b545ea50..5d24c17f8a3 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -109,61 +109,36 @@ static inline struct cpuid_result cpuid_ext(int op, 
unsigned ecx)
        return result;
 }
 
-/*
- * CPUID functions returning a single datum
- */
-static inline unsigned int cpuid_eax(unsigned int op)
+static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
+                               unsigned int *ecx, unsigned int *edx)
 {
-       unsigned int eax;
-
-       __asm__("mov %%ebx, %%edi;"
-               "cpuid;"
-               "mov %%edi, %%ebx;"
-               : "=a" (eax)
-               : "0" (op)
-               : "ecx", "edx", "edi");
-       return eax;
+       /* ecx is often an input as well as an output. */
+       asm volatile("cpuid"
+           : "=a" (*eax),
+             "=b" (*ebx),
+             "=c" (*ecx),
+             "=d" (*edx)
+           : "0" (*eax), "2" (*ecx)
+           : "memory");
 }
 
-static inline unsigned int cpuid_ebx(unsigned int op)
-{
-       unsigned int eax, ebx;
-
-       __asm__("mov %%ebx, %%edi;"
-               "cpuid;"
-               "mov %%ebx, %%esi;"
-               "mov %%edi, %%ebx;"
-               : "=a" (eax), "=S" (ebx)
-               : "0" (op)
-               : "ecx", "edx", "edi");
-       return ebx;
+#define native_cpuid_reg(reg)                                  \
+static inline unsigned int cpuid_##reg(unsigned int op)        \
+{                                                              \
+       unsigned int eax = op, ebx, ecx = 0, edx;               \
+                                                               \
+       native_cpuid(&eax, &ebx, &ecx, &edx);                   \
+                                                               \
+       return reg;                                             \
 }
 
-static inline unsigned int cpuid_ecx(unsigned int op)
-{
-       unsigned int eax, ecx;
-
-       __asm__("mov %%ebx, %%edi;"
-               "cpuid;"
-               "mov %%edi, %%ebx;"
-               : "=a" (eax), "=c" (ecx)
-               : "0" (op)
-               : "edx", "edi");
-       return ecx;
-}
-
-static inline unsigned int cpuid_edx(unsigned int op)
-{
-       unsigned int eax, edx;
-
-       __asm__("mov %%ebx, %%edi;"
-               "cpuid;"
-               "mov %%edi, %%ebx;"
-               : "=a" (eax), "=d" (edx)
-               : "0" (op)
-               : "ecx", "edi");
-       return edx;
-}
+/*
+ * Native CPUID functions returning a single datum.
+ */
+native_cpuid_reg(eax)
+native_cpuid_reg(ebx)
+native_cpuid_reg(ecx)
+native_cpuid_reg(edx)
 
 #if CONFIG_IS_ENABLED(X86_64)
 static inline int flag_is_changeable_p(u32 flag)
-- 
2.43.0

Reply via email to