[v0.82][BUGFIX] Using 0x80000006 in new AMD CPUs outputs wrong L3 size since it reports the full size instead the size of a single L3. Use old method just when is necessary

This commit is contained in:
Dr-Noob
2020-11-21 16:37:51 +01:00
parent b978ddc83d
commit e4a4e13d56

View File

@@ -326,63 +326,78 @@ struct cpuInfo* get_cpu_info() {
return cpu; return cpu;
} }
bool get_cache_topology_amd(struct topology* topo) { bool get_cache_topology_amd(struct cpuInfo* cpu, struct topology* topo) {
uint32_t i, eax, ebx, ecx, edx, num_sharing_cache, cache_type, cache_level; if(cpu->maxExtendedLevels >= 0x8000001D) {
uint32_t i, eax, ebx, ecx, edx, num_sharing_cache, cache_type, cache_level;
i = 0; i = 0;
do { do {
eax = 0x8000001D; eax = 0x8000001D;
ebx = 0; ebx = 0;
ecx = i; // cache id ecx = i; // cache id
edx = 0; edx = 0;
cpuid(&eax, &ebx, &ecx, &edx); cpuid(&eax, &ebx, &ecx, &edx);
cache_type = eax & 0x1F; cache_type = eax & 0x1F;
if(cache_type > 0) { if(cache_type > 0) {
num_sharing_cache = ((eax >> 14) & 0xFFF) + 1; num_sharing_cache = ((eax >> 14) & 0xFFF) + 1;
cache_level = (eax >>= 5) & 0x7; cache_level = (eax >>= 5) & 0x7;
switch (cache_type) { switch (cache_type) {
case 1: // Data Cache (We assume this is L1d) case 1: // Data Cache (We assume this is L1d)
if(cache_level != 1) { if(cache_level != 1) {
printBug("Found data cache at level %d (expected 1)", cache_level); printBug("Found data cache at level %d (expected 1)", cache_level);
return false; return false;
} }
topo->cach->L1d->num_caches = topo->logical_cores / num_sharing_cache; topo->cach->L1d->num_caches = topo->logical_cores / num_sharing_cache;
break; break;
case 2: // Instruction Cache (We assume this is L1i) case 2: // Instruction Cache (We assume this is L1i)
if(cache_level != 1) { if(cache_level != 1) {
printBug("Found instruction cache at level %d (expected 1)", cache_level); printBug("Found instruction cache at level %d (expected 1)", cache_level);
return false; return false;
} }
topo->cach->L1i->num_caches = topo->logical_cores / num_sharing_cache; topo->cach->L1i->num_caches = topo->logical_cores / num_sharing_cache;
break; break;
case 3: // Unified Cache (This may be L2 or L3) case 3: // Unified Cache (This may be L2 or L3)
if(cache_level == 2) { if(cache_level == 2) {
topo->cach->L2->num_caches = topo->logical_cores / num_sharing_cache; topo->cach->L2->num_caches = topo->logical_cores / num_sharing_cache;
} }
else if(cache_level == 3) { else if(cache_level == 3) {
topo->cach->L3->num_caches = topo->logical_cores / num_sharing_cache; topo->cach->L3->num_caches = topo->logical_cores / num_sharing_cache;
} }
else { else {
printBug("Found unified cache at level %d (expected == 2 or 3)", cache_level); printBug("Found unified cache at level %d (expected == 2 or 3)", cache_level);
return false; return false;
} }
break; break;
default: // Unknown Type Cache default: // Unknown Type Cache
printBug("Unknown Type Cache found at ID %d", i); printBug("Unknown Type Cache found at ID %d", i);
return false; return false;
} }
} }
i++; i++;
} while (cache_type > 0); } while (cache_type > 0);
}
else {
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X). Guessing cache sizes", 0x8000001D, cpu->maxExtendedLevels);
topo->cach->L1i->num_caches = topo->physical_cores;
topo->cach->L1d->num_caches = topo->physical_cores;
if(topo->cach->L3->exists) {
topo->cach->L2->num_caches = topo->physical_cores;
topo->cach->L3->num_caches = 1;
}
else {
topo->cach->L2->num_caches = 1;
}
}
return true; return true;
} }
@@ -465,23 +480,7 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) {
else else
topo->sockets = topo->total_cores / topo->physical_cores; topo->sockets = topo->total_cores / topo->physical_cores;
if(cpu->maxExtendedLevels >= 0x8000001D) { get_cache_topology_amd(cpu, topo);
if(!get_cache_topology_amd(topo))
return NULL;
}
else {
printWarn("Can't read topology information from cpuid (needed extended level is 0x%.8X, max is 0x%.8X). Guessing cache sizes", 0x8000001D, cpu->maxExtendedLevels);
topo->cach->L1i->num_caches = topo->physical_cores;
topo->cach->L1d->num_caches = topo->physical_cores;
if(topo->cach->L3->exists) {
topo->cach->L2->num_caches = topo->physical_cores;
topo->cach->L3->num_caches = 1;
}
else {
topo->cach->L2->num_caches = 1;
}
}
break; break;
@@ -493,15 +492,15 @@ struct topology* get_topology_info(struct cpuInfo* cpu, struct cache* cach) {
return topo; return topo;
} }
struct cache* get_cache_info_amd(struct cache* cach) { struct cache* get_cache_info_amd_fallback(struct cache* cach) {
uint32_t eax = 0x80000005; uint32_t eax = 0x80000005;
uint32_t ebx = 0; uint32_t ebx = 0;
uint32_t ecx = 0; uint32_t ecx = 0;
uint32_t edx = 0; uint32_t edx = 0;
cpuid(&eax, &ebx, &ecx, &edx); cpuid(&eax, &ebx, &ecx, &edx);
cach->L1i->size = (ecx >> 24) * 1024; cach->L1d->size = (ecx >> 24) * 1024;
cach->L1d->size = (edx >> 24) * 1024; cach->L1i->size = (edx >> 24) * 1024;
eax = 0x80000006; eax = 0x80000006;
cpuid(&eax, &ebx, &ecx, &edx); cpuid(&eax, &ebx, &ecx, &edx);
@@ -522,24 +521,24 @@ struct cache* get_cache_info_amd(struct cache* cach) {
return cach; return cach;
} }
struct cache* get_cache_info_intel(struct cache* cach) { struct cache* get_cache_info_general(struct cache* cach, uint32_t level) {
uint32_t eax = 0; uint32_t eax = 0;
uint32_t ebx = 0; uint32_t ebx = 0;
uint32_t ecx = 0; uint32_t ecx = 0;
uint32_t edx = 0; uint32_t edx = 0;
int i=0; int i=0;
int32_t cache_type; int32_t cache_type;
do { do {
eax = 0x00000004; // get cache info eax = level; // get cache info
ebx = 0; ebx = 0;
ecx = i; // cache id ecx = i; // cache id
edx = 0; edx = 0;
cpuid(&eax, &ebx, &ecx, &edx); cpuid(&eax, &ebx, &ecx, &edx);
cache_type = eax & 0x1F; cache_type = eax & 0x1F;
// If its 0, we tried fetching a non existing cache // If its 0, we tried fetching a non existing cache
if (cache_type > 0) { if (cache_type > 0) {
int32_t cache_level = (eax >>= 5) & 0x7; int32_t cache_level = (eax >>= 5) & 0x7;
@@ -547,11 +546,11 @@ struct cache* get_cache_info_intel(struct cache* cach) {
uint32_t cache_coherency_line_size = (ebx & 0xFFF) + 1; uint32_t cache_coherency_line_size = (ebx & 0xFFF) + 1;
uint32_t cache_physical_line_partitions = ((ebx >>= 12) & 0x3FF) + 1; uint32_t cache_physical_line_partitions = ((ebx >>= 12) & 0x3FF) + 1;
uint32_t cache_ways_of_associativity = ((ebx >>= 10) & 0x3FF) + 1; uint32_t cache_ways_of_associativity = ((ebx >>= 10) & 0x3FF) + 1;
int32_t cache_total_size = cache_ways_of_associativity * cache_physical_line_partitions * cache_coherency_line_size * cache_sets; int32_t cache_total_size = cache_ways_of_associativity * cache_physical_line_partitions * cache_coherency_line_size * cache_sets;
cach->max_cache_level++; cach->max_cache_level++;
switch (cache_type) { switch (cache_type) {
case 1: // Data Cache (We assume this is L1d) case 1: // Data Cache (We assume this is L1d)
if(cache_level != 1) { if(cache_level != 1) {
printBug("Found data cache at level %d (expected 1)", cache_level); printBug("Found data cache at level %d (expected 1)", cache_level);
@@ -560,7 +559,7 @@ struct cache* get_cache_info_intel(struct cache* cach) {
cach->L1d->size = cache_total_size; cach->L1d->size = cache_total_size;
cach->L1d->exists = true; cach->L1d->exists = true;
break; break;
case 2: // Instruction Cache (We assume this is L1i) case 2: // Instruction Cache (We assume this is L1i)
if(cache_level != 1) { if(cache_level != 1) {
printBug("Found instruction cache at level %d (expected 1)", cache_level); printBug("Found instruction cache at level %d (expected 1)", cache_level);
@@ -569,9 +568,9 @@ struct cache* get_cache_info_intel(struct cache* cach) {
cach->L1i->size = cache_total_size; cach->L1i->size = cache_total_size;
cach->L1i->exists = true; cach->L1i->exists = true;
break; break;
case 3: // Unified Cache (This may be L2 or L3) case 3: // Unified Cache (This may be L2 or L3)
if(cache_level == 2) { if(cache_level == 2) {
cach->L2->size = cache_total_size; cach->L2->size = cache_total_size;
cach->L2->exists = true; cach->L2->exists = true;
} }
@@ -584,45 +583,57 @@ struct cache* get_cache_info_intel(struct cache* cach) {
return NULL; return NULL;
} }
break; break;
default: // Unknown Type Cache default: // Unknown Type Cache
printBug("Unknown Type Cache found at ID %d", i); printBug("Unknown Type Cache found at ID %d", i);
return NULL; return NULL;
} }
} }
i++; i++;
} while (cache_type > 0); } while (cache_type > 0);
return cach; return cach;
} }
struct cache* get_cache_info(struct cpuInfo* cpu) { struct cache* get_cache_info(struct cpuInfo* cpu) {
struct cache* cach = malloc(sizeof(struct cache)); struct cache* cach = malloc(sizeof(struct cache));
init_cache_struct(cach); init_cache_struct(cach);
uint32_t level; uint32_t level;
// We use standart 0x00000004 for Intel // We use standart 0x00000004 for Intel
// We use extended 0x80000006 for AMD // We use extended 0x8000001D for AMD
// or 0x80000005/6 for old AMD
if(cpu->cpu_vendor == CPU_VENDOR_INTEL) { if(cpu->cpu_vendor == CPU_VENDOR_INTEL) {
level = 0x00000004; level = 0x00000004;
if(cpu->maxLevels < level) { if(cpu->maxLevels < level) {
printErr("Can't read cache information from cpuid (needed level is %d, max is %d)", level, cpu->maxLevels); printErr("Can't read cache information from cpuid (needed level is %d, max is %d)", level, cpu->maxLevels);
return NULL; return NULL;
} }
get_cache_info_intel(cach); else {
cach = get_cache_info_general(cach, level);
}
} }
else { else {
level = 0x80000006; level = 0x8000001D;
if(cpu->maxExtendedLevels < level) { if(cpu->maxExtendedLevels < level) {
printErr("Can't read cache information from cpuid (needed extended level is %d, max is %d)", level, cpu->maxExtendedLevels); printWarn("Can't read cache information from cpuid (needed extended level is %d, max is %d)", level, cpu->maxExtendedLevels);
return NULL; level = 0x80000006;
if(cpu->maxExtendedLevels < level) {
printErr("Can't read cache information from cpuid using old method (needed extended level is %d, max is %d)", level, cpu->maxExtendedLevels);
return NULL;
}
printWarn("Fallback to old method using %d and %d", level-1, level);
cach = get_cache_info_amd_fallback(cach);
}
else {
cach = get_cache_info_general(cach, level);
} }
get_cache_info_amd(cach);
} }
// Sanity checks. If we read values greater than this, they can't be valid ones // Sanity checks. If we read values greater than this, they can't be valid ones
// Values were chosen by me // The values were chosen by me
if(cach->L1i->size > 64 * 1024) { if(cach->L1i->size > 64 * 1024) {
printBug("Invalid L1i size: %dKB", cach->L1i->size/1024); printBug("Invalid L1i size: %dKB", cach->L1i->size/1024);
return NULL; return NULL;