mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-12-14 04:00:34 +00:00
cpufeatures: Fixes wrong cache detection of old processors
This commit is contained in:
parent
1c67ca1627
commit
3db583ff24
@ -1134,32 +1134,31 @@ static CacheLevelInfo GetCacheLevelInfo(const uint32_t reg)
|
||||
}
|
||||
}
|
||||
|
||||
static void GetByteArrayFromRegister(uint32_t result[4], const uint32_t reg)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
result[i] = ExtractBitRange(reg, (i + 1) * 8, i * 8);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
uint32_t registers[] = {leaf.eax, leaf.ebx, leaf.ecx, leaf.edx};
|
||||
for (int i = 0; i < 4; ++i)
|
||||
// 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.
|
||||
leaf.eax &= 0xFFFFFF00; // Zeroing out AL. 0 is the empty descriptor.
|
||||
// The most significant bit (bit 31) of each register indicates whether the
|
||||
// register contains valid information (set to 0) or is reserved (set to 1).
|
||||
if (IsBitSet(leaf.eax, 31)) leaf.eax = 0;
|
||||
if (IsBitSet(leaf.ebx, 31)) leaf.ebx = 0;
|
||||
if (IsBitSet(leaf.ecx, 31)) leaf.ecx = 0;
|
||||
if (IsBitSet(leaf.edx, 31)) leaf.edx = 0;
|
||||
|
||||
uint8_t data[16];
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
_Static_assert(sizeof(Leaf) == sizeof(data), "Leaf must be 16 bytes");
|
||||
#endif
|
||||
memcpy(&data, &leaf, sizeof(data));
|
||||
for (size_t i = 0; i < sizeof(data); ++i)
|
||||
{
|
||||
if (registers[i] & (1U << 31))
|
||||
{
|
||||
continue; // register does not contains valid information
|
||||
}
|
||||
uint32_t bytes[4];
|
||||
GetByteArrayFromRegister(bytes, registers[i]);
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
if (bytes[j] == 0xFF)
|
||||
break; // leaf 4 should be used to fetch cache information
|
||||
info->levels[info->size] = GetCacheLevelInfo(bytes[j]);
|
||||
}
|
||||
const uint8_t descriptor = data[i];
|
||||
if (descriptor == 0) continue;
|
||||
info->levels[info->size] = GetCacheLevelInfo(descriptor);
|
||||
info->size++;
|
||||
}
|
||||
}
|
||||
@ -1169,23 +1168,18 @@ static void ParseLeaf2(const int max_cpuid_leaf, CacheInfo* info)
|
||||
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, leaf_id, cache_id);
|
||||
CacheType cache_type = ExtractBitRange(leaf.eax, 4, 0);
|
||||
if (cache_type == CPU_FEATURE_CACHE_NULL)
|
||||
{
|
||||
info->levels[cache_id] = kEmptyCacheLevelInfo;
|
||||
continue;
|
||||
}
|
||||
if (cache_type == CPU_FEATURE_CACHE_NULL) continue;
|
||||
int level = ExtractBitRange(leaf.eax, 7, 5);
|
||||
int line_size = ExtractBitRange(leaf.ebx, 11, 0) + 1;
|
||||
int partitioning = ExtractBitRange(leaf.ebx, 21, 12) + 1;
|
||||
int ways = ExtractBitRange(leaf.ebx, 31, 22) + 1;
|
||||
int tlb_entries = leaf.ecx + 1;
|
||||
int cache_size = (ways * partitioning * line_size * (tlb_entries));
|
||||
info->levels[cache_id] = (CacheLevelInfo){.level = level,
|
||||
info->levels[info->size] = (CacheLevelInfo){.level = level,
|
||||
.cache_type = cache_type,
|
||||
.cache_size = cache_size,
|
||||
.ways = ways,
|
||||
@ -1501,6 +1495,7 @@ CacheInfo GetX86CacheInfo(void)
|
||||
const Leaf leaf_0 = CpuId(0);
|
||||
if (IsVendor(leaf_0, CPU_FEATURES_VENDOR_GENUINE_INTEL))
|
||||
{
|
||||
info.size = 0;
|
||||
ParseLeaf2(leaf_0.eax, &info);
|
||||
ParseCacheInfo(leaf_0.eax, 4, &info);
|
||||
}
|
||||
|
@ -167,6 +167,7 @@ TEST_F(CpuidX86Test, SandyBridge)
|
||||
EXPECT_FALSE(features.adx);
|
||||
}
|
||||
|
||||
const int UNDEF = -1;
|
||||
const int KiB = 1024;
|
||||
const int MiB = 1024 * KiB;
|
||||
|
||||
@ -956,6 +957,59 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||
#endif // !defined(CPU_FEATURES_OS_WINDOWS)
|
||||
}
|
||||
|
||||
// https://www.felixcloutier.com/x86/cpuid#example-3-1--example-of-cache-and-tlb-interpretation
|
||||
TEST_F(CpuidX86Test, P4_CacheInfo)
|
||||
{
|
||||
cpu().SetLeaves({
|
||||
{{0x00000000, 0}, Leaf{0x00000002, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||
{{0x00000001, 0}, Leaf{0x00000F0A, 0x00010808, 0x00000000, 0x3FEBFBFF}},
|
||||
{{0x00000002, 0}, Leaf{0x665B5001, 0x00000000, 0x00000000, 0x007A7000}},
|
||||
});
|
||||
|
||||
const auto info = GetX86CacheInfo();
|
||||
EXPECT_EQ(info.size, 5);
|
||||
|
||||
EXPECT_EQ(info.levels[0].level, UNDEF);
|
||||
EXPECT_EQ(info.levels[0].cache_type, CPU_FEATURE_CACHE_TLB);
|
||||
EXPECT_EQ(info.levels[0].cache_size, 4 * KiB);
|
||||
EXPECT_EQ(info.levels[0].ways, UNDEF);
|
||||
EXPECT_EQ(info.levels[0].line_size, UNDEF);
|
||||
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||
EXPECT_EQ(info.levels[0].partitioning, 0);
|
||||
|
||||
EXPECT_EQ(info.levels[1].level, UNDEF);
|
||||
EXPECT_EQ(info.levels[1].cache_type, CPU_FEATURE_CACHE_TLB);
|
||||
EXPECT_EQ(info.levels[1].cache_size, 4 * KiB);
|
||||
EXPECT_EQ(info.levels[1].ways, UNDEF);
|
||||
EXPECT_EQ(info.levels[1].line_size, UNDEF);
|
||||
EXPECT_EQ(info.levels[1].tlb_entries, 64);
|
||||
EXPECT_EQ(info.levels[1].partitioning, 0);
|
||||
|
||||
EXPECT_EQ(info.levels[2].level, 1);
|
||||
EXPECT_EQ(info.levels[2].cache_type, CPU_FEATURE_CACHE_DATA);
|
||||
EXPECT_EQ(info.levels[2].cache_size, 8 * KiB);
|
||||
EXPECT_EQ(info.levels[2].ways, 4);
|
||||
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||
EXPECT_EQ(info.levels[2].tlb_entries, UNDEF);
|
||||
EXPECT_EQ(info.levels[2].partitioning, 0);
|
||||
|
||||
EXPECT_EQ(info.levels[3].level, 1);
|
||||
EXPECT_EQ(info.levels[3].cache_type, CPU_FEATURE_CACHE_INSTRUCTION);
|
||||
EXPECT_EQ(info.levels[3].cache_size, 12 * KiB);
|
||||
EXPECT_EQ(info.levels[3].ways, 8);
|
||||
EXPECT_EQ(info.levels[3].line_size, UNDEF);
|
||||
EXPECT_EQ(info.levels[3].tlb_entries, UNDEF);
|
||||
EXPECT_EQ(info.levels[3].partitioning, 0);
|
||||
|
||||
EXPECT_EQ(info.levels[4].level, 2);
|
||||
EXPECT_EQ(info.levels[4].cache_type, CPU_FEATURE_CACHE_DATA);
|
||||
EXPECT_EQ(info.levels[4].cache_size, 256 * KiB);
|
||||
EXPECT_EQ(info.levels[4].ways, 8);
|
||||
EXPECT_EQ(info.levels[4].line_size, 64);
|
||||
EXPECT_EQ(info.levels[4].tlb_entries, UNDEF);
|
||||
EXPECT_EQ(info.levels[4].partitioning, 2);
|
||||
}
|
||||
|
||||
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
|
||||
TEST_F(CpuidX86Test, P3)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user