From: Ewan <[email protected]>
The __get_cpuid() and __get_cpuid_count() functions use
"__leaf & 0x80000000" to determine the CPUID range base, which only
distinguishes between Basic (0x0) and Extended (0x80000000) ranges.
This causes queries to the Centaur/Zhaoxin range (0xC0000000) to be
incorrectly mapped to the Extended range, and always return 0 (failure)
on Centaur/Zhaoxin processors that support CPUID 0xC000xxxx
leaves (e.g. PadLock feature detection via leaf 0xC0000001).
Replace the bitmask with explicit range checks that correctly identify
all four CPUID ranges: Basic (0x0), Hypervisor (0x40000000), Extended
(0x80000000), and Centaur/Zhaoxin (0xC0000000).
Additionally, the Hypervisor range (0x40000000) is also handled as an
extra improvement, since the original bitmask incorrectly mapped it to
the Basic range (0x0).
Also update the __get_cpuid_max() comment to document the newly
supported range base values.
gcc/ChangeLog:
* config/i386/cpuid.h (__get_cpuid_max): Update comment to
document 0x40000000 and 0xC0000000 as valid ext values.
(__get_cpuid): Replace "__leaf & 0x80000000" with explicit
range checks for Basic, Hypervisor, Extended, and
Centaur/Zhaoxin CPUID ranges.
(__get_cpuid_count): Likewise.
Signed-off-by: Ewanhaioc <[email protected]>
---
gcc/config/i386/cpuid.h | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index f493360b1e8..083e4f62498 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -264,8 +264,9 @@
/* Return highest supported input value for cpuid instruction. ext can
- be either 0x0 or 0x80000000 to return highest supported value for
- basic or extended cpuid information. Function returns 0 if cpuid
+ be either 0x0, 0x40000000, 0x80000000, or 0xC0000000 to return
+ highest supported value for basic, hypervisor, extended, or
+ Centaur/Zhaoxin cpuid information. Function returns 0 if cpuid
is not supported or whatever cpuid returns in eax register. If sig
pointer is non-null, then first four bytes of the signature
(as found in ebx register) are returned in location pointed by sig. */
@@ -330,7 +331,17 @@ __get_cpuid (unsigned int __leaf,
unsigned int *__eax, unsigned int *__ebx,
unsigned int *__ecx, unsigned int *__edx)
{
- unsigned int __ext = __leaf & 0x80000000;
+ unsigned int __ext;
+
+ if (__leaf >= 0xC0000000)
+ __ext = 0xC0000000;
+ else if (__leaf >= 0x80000000)
+ __ext = 0x80000000;
+ else if (__leaf >= 0x40000000)
+ __ext = 0x40000000;
+ else
+ __ext = 0x00000000;
+
unsigned int __maxlevel = __get_cpuid_max (__ext, 0);
if (__maxlevel == 0 || __maxlevel < __leaf)
@@ -347,7 +358,17 @@ __get_cpuid_count (unsigned int __leaf, unsigned int
__subleaf,
unsigned int *__eax, unsigned int *__ebx,
unsigned int *__ecx, unsigned int *__edx)
{
- unsigned int __ext = __leaf & 0x80000000;
+ unsigned int __ext;
+
+ if (__leaf >= 0xC0000000)
+ __ext = 0xC0000000;
+ else if (__leaf >= 0x80000000)
+ __ext = 0x80000000;
+ else if (__leaf >= 0x40000000)
+ __ext = 0x40000000;
+ else
+ __ext = 0x00000000;
+
unsigned int __maxlevel = __get_cpuid_max (__ext, 0);
if (__builtin_expect (__maxlevel == 0, 0) || __maxlevel < __leaf)
--
2.34.1