mirror of
https://github.com/google/cpu_features.git
synced 2025-04-27 23:22:31 +02:00
Add cache info for new AMD CPUs (0x8000001D) (#171)
This commit is contained in:
parent
2939ece4d2
commit
0925f6953c
@ -21,6 +21,11 @@
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
// CPUID Vendors
|
||||
#define CPU_FEATURES_VENDOR_GENUINE_INTEL "GenuineIntel"
|
||||
#define CPU_FEATURES_VENDOR_AUTHENTIC_AMD "AuthenticAMD"
|
||||
#define CPU_FEATURES_VENDOR_HYGON_GENUINE "HygonGenuine"
|
||||
|
||||
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
|
||||
// The field names are based on the short name provided in the wikipedia tables.
|
||||
typedef struct {
|
||||
|
@ -256,6 +256,10 @@ static int IsVendor(const Leaf leaf, const char* const name) {
|
||||
return leaf.ebx == ebx && leaf.ecx == ecx && leaf.edx == edx;
|
||||
}
|
||||
|
||||
static int IsVendorByX86Info(const X86Info* info, const char* const name) {
|
||||
return memcmp(info->vendor, name, sizeof(info->vendor)) == 0;
|
||||
}
|
||||
|
||||
static const CacheLevelInfo kEmptyCacheLevelInfo;
|
||||
|
||||
static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg) {
|
||||
@ -1140,10 +1144,13 @@ static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ParseLeaf4(const int max_cpuid_leaf, CacheInfo* info) {
|
||||
// For newer Intel CPUs uses "CPUID, eax=0x00000004".
|
||||
// For newer AMD CPUs uses "CPUID, eax=0x8000001D"
|
||||
static void ParseCacheInfo(const int max_cpuid_leaf, uint32_t leaf_id,
|
||||
CacheInfo* info) {
|
||||
info->size = 0;
|
||||
for (int cache_id = 0; cache_id < CPU_FEATURES_MAX_CACHE_LEVEL; cache_id++) {
|
||||
const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, 4, cache_id);
|
||||
const Leaf leaf = SafeCpuIdEx(max_cpuid_leaf, leaf_id, cache_id);
|
||||
CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
|
||||
if (cache_type == CPU_FEATURE_CACHE_NULL) {
|
||||
info->levels[cache_id] = kEmptyCacheLevelInfo;
|
||||
@ -1402,10 +1409,13 @@ 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_80000000 = CpuId(0x80000000);
|
||||
const uint32_t max_extended_cpuid_leaf = leaf_80000000.eax;
|
||||
const Leaf leaf_80000001 = SafeCpuId(max_extended_cpuid_leaf, 0x80000001);
|
||||
const Leaf leaf_80000001 = GetLeafByIdAMD(0x80000001);
|
||||
|
||||
X86Features* const features = &info->features;
|
||||
|
||||
@ -1425,9 +1435,9 @@ static const OsPreserves kEmptyOsPreserves;
|
||||
X86Info GetX86Info(void) {
|
||||
X86Info info = kEmptyX86Info;
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
const bool is_intel = IsVendor(leaf_0, "GenuineIntel");
|
||||
const bool is_amd = IsVendor(leaf_0, "AuthenticAMD");
|
||||
const bool is_hygon = IsVendor(leaf_0, "HygonGenuine");
|
||||
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);
|
||||
if (is_intel || is_amd || is_hygon) {
|
||||
OsPreserves os_preserves = kEmptyOsPreserves;
|
||||
@ -1443,10 +1453,20 @@ X86Info GetX86Info(void) {
|
||||
CacheInfo GetX86CacheInfo(void) {
|
||||
CacheInfo info = kEmptyCacheInfo;
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
const uint32_t max_cpuid_leaf = leaf_0.eax;
|
||||
if (IsVendor(leaf_0, "GenuineIntel")) {
|
||||
ParseLeaf2(max_cpuid_leaf, &info);
|
||||
ParseLeaf4(max_cpuid_leaf, &info);
|
||||
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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
@ -1454,7 +1474,7 @@ CacheInfo GetX86CacheInfo(void) {
|
||||
#define CPUID(FAMILY, MODEL) ((((FAMILY)&0xFF) << 8) | ((MODEL)&0xFF))
|
||||
|
||||
X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
|
||||
if (memcmp(info->vendor, "GenuineIntel", sizeof(info->vendor)) == 0) {
|
||||
if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_GENUINE_INTEL)) {
|
||||
switch (CPUID(info->family, info->model)) {
|
||||
case CPUID(0x06, 0x1C): // Intel(R) Atom(TM) CPU 230 @ 1.60GHz
|
||||
case CPUID(0x06, 0x35):
|
||||
@ -1553,7 +1573,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (memcmp(info->vendor, "AuthenticAMD", sizeof(info->vendor)) == 0) {
|
||||
if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_AUTHENTIC_AMD)) {
|
||||
switch (CPUID(info->family, info->model)) {
|
||||
// https://en.wikichip.org/wiki/amd/cpuid
|
||||
case CPUID(0xF, 0x04):
|
||||
@ -1661,7 +1681,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info) {
|
||||
return X86_UNKNOWN;
|
||||
}
|
||||
}
|
||||
if (memcmp(info->vendor, "HygonGenuine", sizeof(info->vendor)) == 0) {
|
||||
if (IsVendorByX86Info(info, CPU_FEATURES_VENDOR_HYGON_GENUINE)) {
|
||||
switch (CPUID(info->family, info->model)) {
|
||||
case CPUID(0x18, 0x00):
|
||||
return AMD_ZEN;
|
||||
|
@ -435,6 +435,54 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI) {
|
||||
EXPECT_STREQ(brand_string, "AMD Opteron(tm) Processor 6376 ");
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F20_K15_AbuDhabi_CPUID0.txt
|
||||
TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI_CACHE_INFO) {
|
||||
g_fake_cpu->SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x00000001, 0}, Leaf{0x00600F20, 0x00100800, 0x3E98320B, 0x178BFBFF}},
|
||||
{{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||
{{0x80000001, 0}, Leaf{0x00600F20, 0x30000000, 0x01EBBFFF, 0x2FD3FBFF}},
|
||||
{{0x8000001D, 0}, Leaf{0x00000121, 0x00C0003F, 0x0000003F, 0x00000000}},
|
||||
{{0x8000001D, 1}, Leaf{0x00004122, 0x0040003F, 0x000001FF, 0x00000000}},
|
||||
{{0x8000001D, 2}, Leaf{0x00004143, 0x03C0003F, 0x000007FF, 0x00000001}},
|
||||
{{0x8000001D, 3}, Leaf{0x0001C163, 0x0BC0003F, 0x000007FF, 0x00000001}},
|
||||
});
|
||||
const auto info = GetX86CacheInfo();
|
||||
|
||||
EXPECT_EQ(info.size, 4);
|
||||
EXPECT_EQ(info.levels[0].level, 1);
|
||||
EXPECT_EQ(info.levels[0].cache_type, 1);
|
||||
EXPECT_EQ(info.levels[0].cache_size, 16 * KiB);
|
||||
EXPECT_EQ(info.levels[0].ways, 4);
|
||||
EXPECT_EQ(info.levels[0].line_size, 64);
|
||||
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||
EXPECT_EQ(info.levels[0].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[1].level, 1);
|
||||
EXPECT_EQ(info.levels[1].cache_type, 2);
|
||||
EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
|
||||
EXPECT_EQ(info.levels[1].ways, 2);
|
||||
EXPECT_EQ(info.levels[1].line_size, 64);
|
||||
EXPECT_EQ(info.levels[1].tlb_entries, 512);
|
||||
EXPECT_EQ(info.levels[1].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[2].level, 2);
|
||||
EXPECT_EQ(info.levels[2].cache_type, 3);
|
||||
EXPECT_EQ(info.levels[2].cache_size, 2 * MiB);
|
||||
EXPECT_EQ(info.levels[2].ways, 16);
|
||||
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||
EXPECT_EQ(info.levels[2].tlb_entries, 2048);
|
||||
EXPECT_EQ(info.levels[2].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[3].level, 3);
|
||||
EXPECT_EQ(info.levels[3].cache_type, 3);
|
||||
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
|
||||
EXPECT_EQ(info.levels[3].ways, 48);
|
||||
EXPECT_EQ(info.levels[3].line_size, 64);
|
||||
EXPECT_EQ(info.levels[3].tlb_entries, 2048);
|
||||
EXPECT_EQ(info.levels[3].partitioning, 1);
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0600F12_K15_Interlagos_CPUID3.txt
|
||||
TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS) {
|
||||
g_fake_cpu->SetLeaves({
|
||||
@ -631,6 +679,54 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA) {
|
||||
EXPECT_STREQ(brand_string, "Hygon C86 3185 8-core Processor ");
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/HygonGenuine/HygonGenuine0900F02_Hygon_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA_CACHE_INFO) {
|
||||
g_fake_cpu->SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x0000000D, 0x6F677948, 0x656E6975, 0x6E65476E}},
|
||||
{{0x00000001, 0}, Leaf{0x00900F02, 0x00100800, 0x74D83209, 0x178BFBFF}},
|
||||
{{0x80000000, 0}, Leaf{0x8000001F, 0x6F677948, 0x656E6975, 0x6E65476E}},
|
||||
{{0x80000001, 0}, Leaf{0x00900F02, 0x60000000, 0x35C233FF, 0x2FD3FBFF}},
|
||||
{{0x8000001D, 0}, Leaf{0x00004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||
{{0x8000001D, 1}, Leaf{0x00004122, 0x00C0003F, 0x000000FF, 0x00000000}},
|
||||
{{0x8000001D, 2}, Leaf{0x00004143, 0x01C0003F, 0x000003FF, 0x00000002}},
|
||||
{{0x8000001D, 3}, Leaf{0x0001C163, 0x03C0003F, 0x00001FFF, 0x00000001}},
|
||||
});
|
||||
const auto info = GetX86CacheInfo();
|
||||
|
||||
EXPECT_EQ(info.size, 4);
|
||||
EXPECT_EQ(info.levels[0].level, 1);
|
||||
EXPECT_EQ(info.levels[0].cache_type, 1);
|
||||
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
|
||||
EXPECT_EQ(info.levels[0].ways, 8);
|
||||
EXPECT_EQ(info.levels[0].line_size, 64);
|
||||
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||
EXPECT_EQ(info.levels[0].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[1].level, 1);
|
||||
EXPECT_EQ(info.levels[1].cache_type, 2);
|
||||
EXPECT_EQ(info.levels[1].cache_size, 64 * KiB);
|
||||
EXPECT_EQ(info.levels[1].ways, 4);
|
||||
EXPECT_EQ(info.levels[1].line_size, 64);
|
||||
EXPECT_EQ(info.levels[1].tlb_entries, 256);
|
||||
EXPECT_EQ(info.levels[1].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[2].level, 2);
|
||||
EXPECT_EQ(info.levels[2].cache_type, 3);
|
||||
EXPECT_EQ(info.levels[2].cache_size, 512 * KiB);
|
||||
EXPECT_EQ(info.levels[2].ways, 8);
|
||||
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||
EXPECT_EQ(info.levels[2].tlb_entries, 1024);
|
||||
EXPECT_EQ(info.levels[2].partitioning, 1);
|
||||
|
||||
EXPECT_EQ(info.levels[3].level, 3);
|
||||
EXPECT_EQ(info.levels[3].cache_type, 3);
|
||||
EXPECT_EQ(info.levels[3].cache_size, 8 * MiB);
|
||||
EXPECT_EQ(info.levels[3].ways, 16);
|
||||
EXPECT_EQ(info.levels[3].line_size, 64);
|
||||
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
|
||||
EXPECT_EQ(info.levels[3].partitioning, 1);
|
||||
}
|
||||
|
||||
// http://users.atw.hu/instlatx64/AuthenticAMD/AuthenticAMD0A20F10_K19_Vermeer2_CPUID.txt
|
||||
TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER) {
|
||||
g_fake_cpu->SetLeaves({
|
||||
|
Loading…
x
Reference in New Issue
Block a user