mirror of
https://github.com/google/cpu_features.git
synced 2025-04-27 23:22:31 +02:00
[NFC][x86] Read all cpuid leaves at once (#213)
This patch reads the most important cpuid leaves and stores the data in a struct. A followup patch will inline micro architecture detection and brand string inside X86Info so we don't have to call `ReadLeaves` multiple times. This wil allow further simplification of `HasSecondFMA` and help fix https://github.com/google/cpu_features/issues/200.
This commit is contained in:
parent
69d39934e8
commit
5ed8ef4bbe
@ -73,8 +73,6 @@ uint32_t GetXCR0Eax(void) { return (uint32_t)_xgetbv(0); }
|
||||
#error "Unsupported compiler, x86 cpuid requires either GCC, Clang or MSVC."
|
||||
#endif
|
||||
|
||||
static Leaf CpuId(uint32_t leaf_id) { return GetCpuidLeaf(leaf_id, 0); }
|
||||
|
||||
static const Leaf kEmptyLeaf;
|
||||
|
||||
static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
|
||||
@ -85,8 +83,40 @@ static Leaf SafeCpuIdEx(uint32_t max_cpuid_leaf, uint32_t leaf_id, int ecx) {
|
||||
}
|
||||
}
|
||||
|
||||
static Leaf SafeCpuId(uint32_t max_cpuid_leaf, uint32_t leaf_id) {
|
||||
return SafeCpuIdEx(max_cpuid_leaf, leaf_id, 0);
|
||||
typedef struct {
|
||||
uint32_t max_cpuid_leaf;
|
||||
Leaf leaf_0; // Root
|
||||
Leaf leaf_1; // Family, Model, Stepping
|
||||
Leaf leaf_2; // Intel cache info + features
|
||||
Leaf leaf_7; // Features
|
||||
Leaf leaf_7_1; // Features
|
||||
uint32_t max_cpuid_leaf_ext;
|
||||
Leaf leaf_80000000; // Root for extended leaves
|
||||
Leaf leaf_80000001; // AMD features features and cache
|
||||
Leaf leaf_80000002; // brand string
|
||||
Leaf leaf_80000003; // brand string
|
||||
Leaf leaf_80000004; // brand string
|
||||
} Leaves;
|
||||
|
||||
static Leaves ReadLeaves() {
|
||||
const Leaf leaf_0 = GetCpuidLeaf(0, 0);
|
||||
const uint32_t max_cpuid_leaf = leaf_0.eax;
|
||||
const Leaf leaf_80000000 = GetCpuidLeaf(0x80000000, 0);
|
||||
const uint32_t max_cpuid_leaf_ext = leaf_80000000.eax;
|
||||
return (Leaves){
|
||||
.max_cpuid_leaf = max_cpuid_leaf,
|
||||
.leaf_0 = leaf_0,
|
||||
.leaf_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000001, 0),
|
||||
.leaf_2 = SafeCpuIdEx(max_cpuid_leaf, 0x00000002, 0),
|
||||
.leaf_7 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 0),
|
||||
.leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 0x00000007, 1),
|
||||
.max_cpuid_leaf_ext = max_cpuid_leaf_ext,
|
||||
.leaf_80000000 = leaf_80000000,
|
||||
.leaf_80000001 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000001, 0),
|
||||
.leaf_80000002 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000002, 0),
|
||||
.leaf_80000003 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000003, 0),
|
||||
.leaf_80000004 = SafeCpuIdEx(max_cpuid_leaf_ext, 0x80000004, 0),
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -155,17 +185,16 @@ static int IsVendorByX86Info(const X86Info* info, const char* const name) {
|
||||
}
|
||||
|
||||
void FillX86BrandString(char brand_string[49]) {
|
||||
const Leaf leaf_ext_0 = CpuId(0x80000000);
|
||||
const uint32_t max_cpuid_leaf_ext = leaf_ext_0.eax;
|
||||
const Leaf leaves[3] = {
|
||||
SafeCpuId(max_cpuid_leaf_ext, 0x80000002),
|
||||
SafeCpuId(max_cpuid_leaf_ext, 0x80000003),
|
||||
SafeCpuId(max_cpuid_leaf_ext, 0x80000004),
|
||||
const Leaves leaves = ReadLeaves();
|
||||
const Leaf packed[3] = {
|
||||
leaves.leaf_80000002,
|
||||
leaves.leaf_80000003,
|
||||
leaves.leaf_80000004,
|
||||
};
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
_Static_assert(sizeof(leaves) == 48, "Leaves must be packed");
|
||||
_Static_assert(sizeof(packed) == 48, "Leaves must be packed");
|
||||
#endif
|
||||
copy(brand_string, (const char*)(leaves), 48);
|
||||
copy(brand_string, (const char*)(packed), 48);
|
||||
brand_string[48] = '\0';
|
||||
}
|
||||
|
||||
@ -217,11 +246,11 @@ static void OverrideOsPreserves(OsPreserves* os_preserves);
|
||||
static void DetectFeaturesFromOs(X86Features* features);
|
||||
|
||||
// Reference https://en.wikipedia.org/wiki/CPUID.
|
||||
static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
|
||||
static void ParseCpuId(const Leaves* leaves, X86Info* info,
|
||||
OsPreserves* os_preserves) {
|
||||
const Leaf leaf_1 = SafeCpuId(max_cpuid_leaf, 1);
|
||||
const Leaf leaf_7 = SafeCpuId(max_cpuid_leaf, 7);
|
||||
const Leaf leaf_7_1 = SafeCpuIdEx(max_cpuid_leaf, 7, 1);
|
||||
const Leaf leaf_1 = leaves->leaf_1;
|
||||
const Leaf leaf_7 = leaves->leaf_7;
|
||||
const Leaf leaf_7_1 = leaves->leaf_7_1;
|
||||
|
||||
const bool have_xsave = IsBitSet(leaf_1.ecx, 26);
|
||||
const bool have_osxsave = IsBitSet(leaf_1.ecx, 27);
|
||||
@ -333,15 +362,9 @@ static void ParseCpuId(const uint32_t max_cpuid_leaf, X86Info* info,
|
||||
}
|
||||
}
|
||||
|
||||
// Reference
|
||||
// https://en.wikipedia.org/wiki/CPUID#EAX=80000000h:_Get_Highest_Extended_Function_Implemented.
|
||||
static Leaf GetLeafByIdAMD(uint32_t leaf_id) {
|
||||
uint32_t max_extended = CpuId(0x80000000).eax;
|
||||
return SafeCpuId(max_extended, leaf_id);
|
||||
}
|
||||
|
||||
static void ParseExtraAMDCpuId(X86Info* info, OsPreserves os_preserves) {
|
||||
const Leaf leaf_80000001 = GetLeafByIdAMD(0x80000001);
|
||||
static void ParseExtraAMDCpuId(const Leaves* leaves, X86Info* info,
|
||||
OsPreserves os_preserves) {
|
||||
const Leaf leaf_80000001 = leaves->leaf_80000001;
|
||||
|
||||
X86Features* const features = &info->features;
|
||||
|
||||
@ -359,17 +382,19 @@ static const OsPreserves kEmptyOsPreserves;
|
||||
|
||||
X86Info GetX86Info(void) {
|
||||
X86Info info = kEmptyX86Info;
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
const bool is_intel = IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL);
|
||||
const bool is_amd = IsVendor(leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
|
||||
const bool is_hygon = IsVendor(leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
|
||||
SetVendor(leaf_0, info.vendor);
|
||||
const Leaves leaves = ReadLeaves();
|
||||
const bool is_intel =
|
||||
IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL);
|
||||
const bool is_amd =
|
||||
IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD);
|
||||
const bool is_hygon =
|
||||
IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE);
|
||||
SetVendor(leaves.leaf_0, info.vendor);
|
||||
if (is_intel || is_amd || is_hygon) {
|
||||
OsPreserves os_preserves = kEmptyOsPreserves;
|
||||
const uint32_t max_cpuid_leaf = leaf_0.eax;
|
||||
ParseCpuId(max_cpuid_leaf, &info, &os_preserves);
|
||||
ParseCpuId(&leaves, &info, &os_preserves);
|
||||
if (is_amd || is_hygon) {
|
||||
ParseExtraAMDCpuId(&info, os_preserves);
|
||||
ParseExtraAMDCpuId(&leaves, &info, os_preserves);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
@ -1510,8 +1535,8 @@ static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
|
||||
}
|
||||
|
||||
// From https://www.felixcloutier.com/x86/cpuid#tbl-3-12
|
||||
static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) {
|
||||
Leaf leaf = SafeCpuId(max_cpuid_leaf, 2);
|
||||
static void ParseLeaf2(const Leaves* leaves, CacheInfo* info) {
|
||||
Leaf leaf = leaves->leaf_2;
|
||||
// The least-significant byte in register EAX (register AL) will always return
|
||||
// 01H. Software should ignore this value and not interpret it as an
|
||||
// informational descriptor.
|
||||
@ -1580,20 +1605,17 @@ static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id,
|
||||
|
||||
CacheInfo GetX86CacheInfo(void) {
|
||||
CacheInfo info = kEmptyCacheInfo;
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL)) {
|
||||
ParseLeaf2(leaf_0.eax, &info);
|
||||
ParseCacheInfo(leaf_0.eax, 4, &info);
|
||||
} else if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) ||
|
||||
IsVendor(leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
|
||||
const uint32_t max_ext = CpuId(0x80000000).eax;
|
||||
const uint32_t cpuid_ext = SafeCpuId(max_ext, 0x80000001).ecx;
|
||||
|
||||
const Leaves leaves = ReadLeaves();
|
||||
if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL)) {
|
||||
ParseLeaf2(&leaves, &info);
|
||||
ParseCacheInfo(leaves.max_cpuid_leaf, 4, &info);
|
||||
} else if (IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_AUTHENTIC_AMD) ||
|
||||
IsVendor(leaves.leaf_0, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
|
||||
// If CPUID Fn8000_0001_ECX[TopologyExtensions]==0
|
||||
// then CPUID Fn8000_0001_E[D,C,B,A]X is reserved.
|
||||
// https://www.amd.com/system/files/TechDocs/25481.pdf
|
||||
if (IsBitSet(cpuid_ext, 22)) {
|
||||
ParseCacheInfo(max_ext, 0x8000001D, &info);
|
||||
if (IsBitSet(leaves.leaf_80000001.ecx, 22)) {
|
||||
ParseCacheInfo(leaves.max_cpuid_leaf_ext, 0x8000001D, &info);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
|
Loading…
x
Reference in New Issue
Block a user