diff --git a/libcpuid/cpuid_main.c b/libcpuid/cpuid_main.c index f9938a0..aeb3d06 100644 --- a/libcpuid/cpuid_main.c +++ b/libcpuid/cpuid_main.c @@ -410,6 +410,12 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data) data->intel_fn14h[i][ECX] = i; cpu_exec_cpuid_ext(data->intel_fn14h[i]); } + for (i = 0; i < MAX_AMDFN8000001DH_LEVEL; i++) { + memset(data->amd_fn8000001dh[i], 0, sizeof(data->amd_fn8000001dh[i])); + data->amd_fn8000001dh[i][EAX] = 0x8000001d; + data->amd_fn8000001dh[i][ECX] = i; + cpu_exec_cpuid_ext(data->amd_fn8000001dh[i]); + } return set_error(ERR_OK); } @@ -449,6 +455,10 @@ int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename) fprintf(f, "intel_fn14h[%d]=%08x %08x %08x %08x\n", i, data->intel_fn14h[i][EAX], data->intel_fn14h[i][EBX], data->intel_fn14h[i][ECX], data->intel_fn14h[i][EDX]); + for (i = 0; i < MAX_AMDFN8000001DH_LEVEL; i++) + fprintf(f, "amd_fn8000001dh[%d]=%08x %08x %08x %08x\n", i, + data->amd_fn8000001dh[i][EAX], data->amd_fn8000001dh[i][EBX], + data->amd_fn8000001dh[i][ECX], data->amd_fn8000001dh[i][EDX]); if (strcmp(filename, "")) fclose(f); @@ -499,6 +509,7 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename syntax = syntax && parse_token("intel_fn11", token, value, data->intel_fn11, MAX_INTELFN11_LEVEL, &recognized); syntax = syntax && parse_token("intel_fn12h", token, value, data->intel_fn12h, MAX_INTELFN12H_LEVEL, &recognized); syntax = syntax && parse_token("intel_fn14h", token, value, data->intel_fn14h, MAX_INTELFN14H_LEVEL, &recognized); + syntax = syntax && parse_token("amd_fn8000001dh", token, value, data->amd_fn8000001dh, MAX_AMDFN8000001DH_LEVEL, &recognized); if (!syntax) { warnf("Error: %s:%d: Syntax error\n", filename, cur_line); fclose(f); diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index 337c78c..a76685c 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -151,6 +151,12 @@ struct cpu_raw_data_t { * this stores the result of CPUID with eax = 0x12 and * ecx = 0, 1, 2... */ uint32_t intel_fn14h[MAX_INTELFN14H_LEVEL][NUM_REGS]; + + /** when the CPU is AMD and supports leaf 8000001Dh + * (topology information for the DC) + * this stores the result of CPUID with eax = 8000001Dh and + * ecx = 0, 1, 2... */ + uint32_t amd_fn8000001dh[MAX_AMDFN8000001DH_LEVEL][NUM_REGS]; }; /** diff --git a/libcpuid/libcpuid_constants.h b/libcpuid/libcpuid_constants.h index 916cc32..f3efa5b 100644 --- a/libcpuid/libcpuid_constants.h +++ b/libcpuid/libcpuid_constants.h @@ -41,6 +41,7 @@ #define MAX_INTELFN11_LEVEL 4 #define MAX_INTELFN12H_LEVEL 4 #define MAX_INTELFN14H_LEVEL 4 +#define MAX_AMDFN8000001DH_LEVEL 4 #define CPU_HINTS_MAX 16 #define SGX_FLAGS_MAX 14 diff --git a/libcpuid/libcpuid_internal.h b/libcpuid/libcpuid_internal.h index 1895475..8d5db4d 100644 --- a/libcpuid/libcpuid_internal.h +++ b/libcpuid/libcpuid_internal.h @@ -30,6 +30,9 @@ * for the workings of the internal library infrastructure. */ +#define EXTRACTS_BIT(reg, bit) ((reg >> bit) & 0x1) +#define EXTRACTS_BITS(reg, highbit, lowbit) ((reg >> lowbit) & ((1ULL << (highbit - lowbit + 1)) - 1)) + enum _common_codes_t { NA = 0, NC, /* No code */ diff --git a/libcpuid/recog_amd.c b/libcpuid/recog_amd.c index fb3c374..8c40cf1 100644 --- a/libcpuid/recog_amd.c +++ b/libcpuid/recog_amd.c @@ -368,7 +368,7 @@ static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data) static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data) { - int l3_result; + int l3_result, l3_assoc; const int assoc_table[16] = { 0, 1, 2, 0, 4, 0, 8, 0, 16, 16, 32, 48, 64, 96, 128, 255 }; @@ -389,9 +389,22 @@ static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* d if (l3_result > 0) { l3_result = 512 * l3_result; /* AMD spec says it's a range, but we take the lower bound */ + l3_assoc = (raw->ext_cpuid[6][EDX] >> 12) & 0xf; data->l3_cache = l3_result; - data->l3_assoc = assoc_table[(raw->ext_cpuid[6][EDX] >> 12) & 0xf]; - data->l3_cacheline = (raw->ext_cpuid[6][EDX]) & 0xff; + + if(l3_assoc == 0x9) { + /* Since Zen 2, CPUID_Fn80000006_EDX[15:12] is invalid (0x9) + According to page 74 on + Processor Programming Reference (PPR) for AMD Family 17h Model 71h, Revision B0 Processors: + "There are insufficient available encodings to represent all possible L3 + associativities. Please refer to Core::X86::Cpuid::CachePropEbx3[CacheNumWays]." + Note: we do not read CPUID_Fn80000001_ECX[22] (AKA TopologyExtensions) to allow retrocompatibility with existing tests */ + data->l3_assoc = EXTRACTS_BITS(raw->amd_fn8000001dh[0x3][EBX], 31, 22) + 1; // Cache number of ways is CacheNumWays + 1 + data->l3_cacheline = EXTRACTS_BITS(raw->amd_fn8000001dh[0x3][EBX], 11, 0) + 1; // Cache line size in bytes is CacheLineSize + 1 + } else { + data->l3_assoc = assoc_table[l3_assoc]; + data->l3_cacheline = (raw->ext_cpuid[6][EDX]) & 0xff; + } } else { data->l3_cache = 0; }