git: 89d7b30c652c - main - i386,amd64: Explicitly set ECX=0 in do_cpuid() to be future-proof

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Fri, 20 Feb 2026 15:29:20 UTC
The branch main has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=89d7b30c652c98ea12abc5eb9424464cbfb45953

commit 89d7b30c652c98ea12abc5eb9424464cbfb45953
Author:     Aaron LI <aly@aaronly.me>
AuthorDate: 2026-02-16 04:00:12 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2026-02-20 15:26:20 +0000

    i386,amd64: Explicitly set ECX=0 in do_cpuid() to be future-proof
    
    In principle, do_cpuid() should only be used for CPUID leaves without
    sub-leaves.  Even accessing sub-leaf zero (ECX=0), one must use
    cpuid_count(ax, 0) rather than cpuid(ax).
    
    However, one might assume do_cpuid(ax) is equivalent to
    cpuid_count(ax, 0), but the old do_cpuid() did not initialize ECX before
    executing the CPUID instruction.  If ECX contained a non-zero value, the
    instruction could return unexpected results, potentially leading to
    subtle and hard-to-debug issues, especially in ported code.
    
    To be future-proof and to help port code, adjust do_cpuid(ax) to be
    cpuid_count(ax, 0) to explicitly set ECX=0.
    
    It's believed that this change does not fix any real bugs in FreeBSD.
    
    See also the DragonFly commit:
    https://github.com/DragonFlyBSD/DragonFlyBSD/commit/0087a1d163488a57787a9a6431dd94070b1988d4
    
    Signed-off-by: Aaron LI <aly@aaronly.me>
    Reviewed by: kib
    Pull Request: https://github.com/freebsd/freebsd-src/pull/2027
---
 sys/amd64/include/cpufunc.h | 10 ++++------
 sys/i386/include/cpufunc.h  | 24 +++++-------------------
 2 files changed, 9 insertions(+), 25 deletions(-)

diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h
index 9a4c82275a99..e52c55dc80f0 100644
--- a/sys/amd64/include/cpufunc.h
+++ b/sys/amd64/include/cpufunc.h
@@ -100,19 +100,17 @@ disable_intr(void)
 }
 
 static __inline void
-do_cpuid(u_int ax, u_int *p)
+cpuid_count(u_int ax, u_int cx, u_int *p)
 {
 	__asm __volatile("cpuid"
 	    : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
-	    :  "0" (ax));
+	    :  "0" (ax), "c" (cx));
 }
 
 static __inline void
-cpuid_count(u_int ax, u_int cx, u_int *p)
+do_cpuid(u_int ax, u_int *p)
 {
-	__asm __volatile("cpuid"
-	    : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
-	    :  "0" (ax), "c" (cx));
+	cpuid_count(ax, 0, p);
 }
 
 static __inline void
diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h
index b200588b0739..5ee516656d72 100644
--- a/sys/i386/include/cpufunc.h
+++ b/sys/i386/include/cpufunc.h
@@ -91,14 +91,6 @@ disable_intr(void)
 }
 
 #ifdef _KERNEL
-static __inline void
-do_cpuid(u_int ax, u_int *p)
-{
-	__asm __volatile("cpuid"
-	    : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
-	    :  "0" (ax));
-}
-
 static __inline void
 cpuid_count(u_int ax, u_int cx, u_int *p)
 {
@@ -108,7 +100,7 @@ cpuid_count(u_int ax, u_int cx, u_int *p)
 }
 #else
 static __inline void
-do_cpuid(u_int ax, u_int *p)
+cpuid_count(u_int ax, u_int cx, u_int *p)
 {
 	__asm __volatile(
 	    "pushl\t%%ebx\n\t"
@@ -116,21 +108,15 @@ do_cpuid(u_int ax, u_int *p)
 	    "movl\t%%ebx,%1\n\t"
 	    "popl\t%%ebx"
 	    : "=a" (p[0]), "=DS" (p[1]), "=c" (p[2]), "=d" (p[3])
-	    :  "0" (ax));
+	    :  "0" (ax), "c" (cx));
 }
+#endif
 
 static __inline void
-cpuid_count(u_int ax, u_int cx, u_int *p)
+do_cpuid(u_int ax, u_int *p)
 {
-	__asm __volatile(
-	    "pushl\t%%ebx\n\t"
-	    "cpuid\n\t"
-	    "movl\t%%ebx,%1\n\t"
-	    "popl\t%%ebx"
-	    : "=a" (p[0]), "=DS" (p[1]), "=c" (p[2]), "=d" (p[3])
-	    :  "0" (ax), "c" (cx));
+	cpuid_count(ax, 0, p);
 }
-#endif
 
 static __inline void
 enable_intr(void)