aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron LI <aly@aaronly.me>2026-02-16 04:00:12 +0000
committerEd Maste <emaste@FreeBSD.org>2026-02-20 15:26:20 +0000
commit89d7b30c652c98ea12abc5eb9424464cbfb45953 (patch)
treec54ba0748b0c129a9221cfbd26049747ac1740f0
parent836ac989933bcd5b662979bfdec429a201c123a6 (diff)
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
-rw-r--r--sys/amd64/include/cpufunc.h10
-rw-r--r--sys/i386/include/cpufunc.h24
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
@@ -92,14 +92,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)
{
__asm __volatile("cpuid"
@@ -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)