diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_x86.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_x86.h index faccfa84e..9abde468c 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_x86.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_x86.h @@ -10,6 +10,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 diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/cpuinfo_x86.c b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/cpuinfo_x86.c index 3f3061a98..5a053c751 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/cpuinfo_x86.c +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/cpuinfo_x86.c @@ -201,7 +201,6 @@ static bool HasYmmOsXSave(uint32_t xcr0_eax) return HasMask(xcr0_eax, MASK_XMM | MASK_YMM); } -#if !defined(CPU_FEATURES_OS_DARWIN) // Checks that operating system saves and restores zmm registers during context // switches. static bool HasZmmOsXSave(uint32_t xcr0_eax) @@ -209,7 +208,6 @@ static bool HasZmmOsXSave(uint32_t xcr0_eax) return HasMask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | MASK_ZMM16_31); } -#endif // Checks that operating system saves and restores AMX/TMUL state during context // switches. @@ -267,6 +265,11 @@ 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) @@ -1159,12 +1162,15 @@ 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) { @@ -1439,11 +1445,15 @@ 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; @@ -1466,9 +1476,9 @@ 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) { @@ -1487,11 +1497,24 @@ 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")) + if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL)) { - ParseLeaf2(max_cpuid_leaf, &info); - ParseLeaf4(max_cpuid_leaf, &info); + 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; } @@ -1500,7 +1523,7 @@ CacheInfo GetX86CacheInfo(void) 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)) { @@ -1605,7 +1628,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)) { @@ -1715,7 +1738,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)) { diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_x86_test.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_x86_test.cc index f4fa1a9d3..f02b15f55 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_x86_test.cc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_x86_test.cc @@ -449,6 +449,55 @@ 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) { @@ -653,6 +702,55 @@ 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) {