1
0
Fork 0
mirror of https://github.com/anrieff/libcpuid synced 2024-12-16 16:35:45 +00:00

Add cpuid_get_all_raw_data, cpuid_serialize_all_raw_data and cpuid_deserialize_all_raw_data functions

This commit is contained in:
Xorg 2022-09-04 19:54:16 +02:00
parent 7b185baec8
commit 5667e1401c
No known key found for this signature in database
GPG key ID: 1E55EE2EFF18BC1A
5 changed files with 280 additions and 118 deletions

View file

@ -65,29 +65,8 @@ static void cpu_id_t_constructor(struct cpu_id_t* id)
id->l1_assoc = id->l1_data_assoc = id->l1_instruction_assoc = id->l2_assoc = id->l3_assoc = id->l4_assoc = -1;
id->l1_cacheline = id->l1_data_cacheline = id->l1_instruction_cacheline = id->l2_cacheline = id->l3_cacheline = id->l4_cacheline = -1;
id->sse_size = -1;
}
static int parse_token(const char* expected_token, const char *token,
const char *value, uint32_t array[][4], int limit, int *recognized)
{
char format[32];
int veax, vebx, vecx, vedx;
int index;
if (*recognized) return 1; /* already recognized */
if (strncmp(token, expected_token, strlen(expected_token))) return 1; /* not what we search for */
sprintf(format, "%s[%%d]", expected_token);
*recognized = 1;
if (1 == sscanf(token, format, &index) && index >=0 && index < limit) {
if (4 == sscanf(value, "%x%x%x%x", &veax, &vebx, &vecx, &vedx)) {
array[index][0] = veax;
array[index][1] = vebx;
array[index][2] = vecx;
array[index][3] = vedx;
return 1;
}
}
return 0;
id->affinity_mask = 0x00000000;
id->purpose = PURPOSE_GENERAL;
}
/* get_total_cpus() system specific code: uses OS routines to determine total number of CPUs */
@ -270,6 +249,196 @@ static int set_cpu_affinity(uint32_t logical_cpu)
}
#endif /* SET_CPU_AFFINITY */
static int cpuid_serialize_raw_data_internal(struct cpu_raw_data_t* single_raw, struct cpu_raw_data_array_t *raw_array, const char* filename)
{
int i;
const bool raw_is_init = (raw_array != NULL) && raw_array->num_raw > 0;
int8_t logical_cpu = raw_is_init ? 0 : -1;
struct cpu_raw_data_t* raw_ptr = raw_is_init ? &raw_array->raw[0] : single_raw;
FILE *f;
/* Open file descriptor */
f = !strcmp(filename, "") ? stdin : fopen(filename, "wt");
if (!f)
return set_error(ERR_OPEN);
debugf(1, "Writing RAW dump to '%s'\n", f == stdin ? "stdin" : filename);
/* Write RAW data to output file */
fprintf(f, "version=%s\n", VERSION);
while ((raw_is_init && (logical_cpu < raw_array->num_raw)) || (!raw_is_init && (logical_cpu < 0))) {
if (raw_is_init) {
debugf(2, "Writing RAW dump for logical CPU %i\n", logical_cpu);
fprintf(f, "\n_________________ Logical CPU #%i _________________\n", logical_cpu);
raw_ptr = &raw_array->raw[logical_cpu];
}
for (i = 0; i < MAX_CPUID_LEVEL; i++)
fprintf(f, "basic_cpuid[%d]=%08x %08x %08x %08x\n", i,
raw_ptr->basic_cpuid[i][EAX], raw_ptr->basic_cpuid[i][EBX],
raw_ptr->basic_cpuid[i][ECX], raw_ptr->basic_cpuid[i][EDX]);
for (i = 0; i < MAX_EXT_CPUID_LEVEL; i++)
fprintf(f, "ext_cpuid[%d]=%08x %08x %08x %08x\n", i,
raw_ptr->ext_cpuid[i][EAX], raw_ptr->ext_cpuid[i][EBX],
raw_ptr->ext_cpuid[i][ECX], raw_ptr->ext_cpuid[i][EDX]);
for (i = 0; i < MAX_INTELFN4_LEVEL; i++)
fprintf(f, "intel_fn4[%d]=%08x %08x %08x %08x\n", i,
raw_ptr->intel_fn4[i][EAX], raw_ptr->intel_fn4[i][EBX],
raw_ptr->intel_fn4[i][ECX], raw_ptr->intel_fn4[i][EDX]);
for (i = 0; i < MAX_INTELFN11_LEVEL; i++)
fprintf(f, "intel_fn11[%d]=%08x %08x %08x %08x\n", i,
raw_ptr->intel_fn11[i][EAX], raw_ptr->intel_fn11[i][EBX],
raw_ptr->intel_fn11[i][ECX], raw_ptr->intel_fn11[i][EDX]);
for (i = 0; i < MAX_INTELFN12H_LEVEL; i++)
fprintf(f, "intel_fn12h[%d]=%08x %08x %08x %08x\n", i,
raw_ptr->intel_fn12h[i][EAX], raw_ptr->intel_fn12h[i][EBX],
raw_ptr->intel_fn12h[i][ECX], raw_ptr->intel_fn12h[i][EDX]);
for (i = 0; i < MAX_INTELFN14H_LEVEL; i++)
fprintf(f, "intel_fn14h[%d]=%08x %08x %08x %08x\n", i,
raw_ptr->intel_fn14h[i][EAX], raw_ptr->intel_fn14h[i][EBX],
raw_ptr->intel_fn14h[i][ECX], raw_ptr->intel_fn14h[i][EDX]);
for (i = 0; i < MAX_AMDFN8000001DH_LEVEL; i++)
fprintf(f, "amd_fn8000001dh[%d]=%08x %08x %08x %08x\n", i,
raw_ptr->amd_fn8000001dh[i][EAX], raw_ptr->amd_fn8000001dh[i][EBX],
raw_ptr->amd_fn8000001dh[i][ECX], raw_ptr->amd_fn8000001dh[i][EDX]);
logical_cpu++;
}
/* Close file descriptor */
if (strcmp(filename, ""))
fclose(f);
return set_error(ERR_OK);
}
#define RAW_ASSIGN_LINE(__line) __line[EAX] = eax ; __line[EBX] = ebx ; __line[ECX] = ecx ; __line[EDX] = edx
static int cpuid_deserialize_raw_data_internal(struct cpu_raw_data_t* single_raw, struct cpu_raw_data_array_t *raw_array, const char* filename)
{
int i;
int cur_line = 0;
int assigned = 0;
int subleaf = 0;
bool is_libcpuid_dump = true;
bool is_aida64_dump = false;
const bool raw_is_init = (raw_array != NULL);
int16_t logical_cpu = -1;
uint32_t addr, eax, ebx, ecx, edx;
char version[8];
char line[100];
struct cpu_raw_data_t* raw_ptr = raw_is_init ? &raw_array->raw[0] : single_raw;
FILE *f;
/* Open file descriptor */
f = !strcmp(filename, "") ? stdin : fopen(filename, "rt");
if (!f)
return set_error(ERR_OPEN);
debugf(1, "Opening RAW dump from '%s'\n", f == stdin ? "stdin" : filename);
if (raw_is_init) {
raw_array->with_affinity = false;
raw_array->num_raw = raw_array->with_affinity ? 0 : 1;
raw_data_t_constructor(raw_ptr);
}
/* Parse file and store data in cpu_raw_data_t */
while (fgets(line, sizeof(line), f) != NULL) {
line[strcspn(line, "\n")] = '\0';
cur_line++;
if (cur_line == 1) {
if (sscanf(line, "version=%s", version) >= 1) {
is_libcpuid_dump = true;
is_aida64_dump = false;
debugf(2, "Recognized version '%s' from RAW dump\n", version);
continue;
}
else if (!strcmp(line, "------[ Versions ]------") || !strcmp(line, "------[ Logical CPU #0 ]------") || !strcmp(line, "------[ CPUID Registers / Logical CPU #0 ]------")) {
is_libcpuid_dump = false;
is_aida64_dump = true;
debugf(2, "Recognized AIDA64 RAW dump\n");
}
}
if (is_libcpuid_dump) {
if (raw_is_init && (sscanf(line, "_________________ Logical CPU #%hi _________________", &logical_cpu) >= 1)) {
if (raw_array->num_raw >= CPU_RAW_MAX) {
warnf("RAW dump contains more than %d logical CPU, cannot parse more.\n", CPU_RAW_MAX);
return set_error(ERR_NO_MEM);
}
debugf(2, "Parsing RAW dump for logical CPU %i\n", logical_cpu);
raw_ptr = &raw_array->raw[logical_cpu];
raw_array->with_affinity = true;
raw_array->num_raw = logical_cpu + 1;
raw_data_t_constructor(raw_ptr);
}
else if ((sscanf(line, "basic_cpuid[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_CPUID_LEVEL)) {
RAW_ASSIGN_LINE(raw_ptr->basic_cpuid[i]);
}
else if ((sscanf(line, "ext_cpuid[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_EXT_CPUID_LEVEL)) {
RAW_ASSIGN_LINE(raw_ptr->ext_cpuid[i]);
}
else if ((sscanf(line, "intel_fn4[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_INTELFN4_LEVEL)) {
RAW_ASSIGN_LINE(raw_ptr->intel_fn4[i]);
}
else if ((sscanf(line, "intel_fn11[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_INTELFN11_LEVEL)) {
RAW_ASSIGN_LINE(raw_ptr->intel_fn11[i]);
}
else if ((sscanf(line, "intel_fn12h[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_INTELFN12H_LEVEL)) {
RAW_ASSIGN_LINE(raw_ptr->intel_fn12h[i]);
}
else if ((sscanf(line, "intel_fn14h[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_INTELFN14H_LEVEL)) {
RAW_ASSIGN_LINE(raw_ptr->intel_fn14h[i]);
}
else if ((sscanf(line, "amd_fn8000001dh[%d]=%x %x %x %x", &i, &eax, &ebx, &ecx, &edx) >= 5) && (i >= 0) && (i < MAX_AMDFN8000001DH_LEVEL)) {
RAW_ASSIGN_LINE(raw_ptr->amd_fn8000001dh[i]);
}
else if (line[0] != '\0') {
warnf("Warning: file '%s', line %d: '%s' not understood!\n", filename, cur_line, line);
}
}
else if (is_aida64_dump) {
if (raw_is_init && ((sscanf(line, "------[Logical CPU #%hi ]------", &logical_cpu) >= 1) || \
(sscanf(line, "------[ CPUID Registers / Logical CPU #%hi ]------", &logical_cpu) >= 1))) {
if (raw_array->num_raw >= CPU_RAW_MAX) {
warnf("AIDA64 RAW dump contains more than %d logical CPU, cannot parse more.\n", CPU_RAW_MAX);
return set_error(ERR_NO_MEM);
}
debugf(2, "Parsing AIDA64 RAW dump for logical CPU %i\n", logical_cpu);
raw_ptr = &raw_array->raw[logical_cpu];
raw_array->with_affinity = true;
raw_array->num_raw = logical_cpu + 1;
raw_data_t_constructor(raw_ptr);
continue;
}
subleaf = 0;
assigned = sscanf(line, "CPUID %x: %x-%x-%x-%x [SL %02i]", &addr, &eax, &ebx, &ecx, &edx, &subleaf);
debugf(3, "RAW line %d: %i items assigned for string '%s'\n", cur_line, assigned, line);
if ((assigned >= 5) && (subleaf == 0)) {
if (addr < MAX_CPUID_LEVEL) {
i = (int) addr;
RAW_ASSIGN_LINE(raw_ptr->basic_cpuid[i]);
}
else if ((addr >= ADDRESS_EXT_CPUID_START) && (addr < ADDRESS_EXT_CPUID_END)) {
i = (int) addr - ADDRESS_EXT_CPUID_START;
RAW_ASSIGN_LINE(raw_ptr->ext_cpuid[i]);
}
}
if (assigned >= 6) {
i = subleaf;
switch (addr) {
case 0x00000004: RAW_ASSIGN_LINE(raw_ptr->intel_fn4[i]); break;
case 0x0000000B: RAW_ASSIGN_LINE(raw_ptr->intel_fn11[i]); break;
case 0x00000012: RAW_ASSIGN_LINE(raw_ptr->intel_fn12h[i]); break;
case 0x00000014: RAW_ASSIGN_LINE(raw_ptr->intel_fn14h[i]); break;
case 0x8000001D: RAW_ASSIGN_LINE(raw_ptr->amd_fn8000001dh[i]); break;
default: break;
}
}
}
}
/* Close file descriptor */
if (strcmp(filename, ""))
fclose(f);
return set_error(ERR_OK);
}
#undef RAW_ASSIGN_LINE
static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
{
@ -542,110 +711,53 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data)
return set_error(ERR_OK);
}
int cpuid_get_all_raw_data(struct cpu_raw_data_array_t *data)
{
int cur_error = set_error(ERR_OK);
int ret_error = set_error(ERR_OK);
struct cpu_raw_data_t* raw_ptr = NULL;
if (data == NULL)
return set_error(ERR_HANDLE);
data->with_affinity = true;
data->num_raw = 0;
while (set_cpu_affinity(data->num_raw) == 0) {
if (data->num_raw >= CPU_RAW_MAX) {
warnf("System has more than %d logical CPU, cannot get more RAW.\n", CPU_RAW_MAX);
return set_error(ERR_NO_MEM);
}
debugf(2, "Getting RAW dump for logical CPU %i\n", data->num_raw);
raw_ptr = &data->raw[data->num_raw];
raw_data_t_constructor(raw_ptr);
cur_error = cpuid_get_raw_data(raw_ptr);
if (ret_error == ERR_OK)
ret_error = cur_error;
data->num_raw++;
}
return ret_error;
}
int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename)
{
int i;
FILE *f;
return cpuid_serialize_raw_data_internal(data, NULL, filename);
}
if (!strcmp(filename, ""))
f = stdout;
else
f = fopen(filename, "wt");
if (!f) return set_error(ERR_OPEN);
fprintf(f, "version=%s\n", VERSION);
for (i = 0; i < MAX_CPUID_LEVEL; i++)
fprintf(f, "basic_cpuid[%d]=%08x %08x %08x %08x\n", i,
data->basic_cpuid[i][EAX], data->basic_cpuid[i][EBX],
data->basic_cpuid[i][ECX], data->basic_cpuid[i][EDX]);
for (i = 0; i < MAX_EXT_CPUID_LEVEL; i++)
fprintf(f, "ext_cpuid[%d]=%08x %08x %08x %08x\n", i,
data->ext_cpuid[i][EAX], data->ext_cpuid[i][EBX],
data->ext_cpuid[i][ECX], data->ext_cpuid[i][EDX]);
for (i = 0; i < MAX_INTELFN4_LEVEL; i++)
fprintf(f, "intel_fn4[%d]=%08x %08x %08x %08x\n", i,
data->intel_fn4[i][EAX], data->intel_fn4[i][EBX],
data->intel_fn4[i][ECX], data->intel_fn4[i][EDX]);
for (i = 0; i < MAX_INTELFN11_LEVEL; i++)
fprintf(f, "intel_fn11[%d]=%08x %08x %08x %08x\n", i,
data->intel_fn11[i][EAX], data->intel_fn11[i][EBX],
data->intel_fn11[i][ECX], data->intel_fn11[i][EDX]);
for (i = 0; i < MAX_INTELFN12H_LEVEL; i++)
fprintf(f, "intel_fn12h[%d]=%08x %08x %08x %08x\n", i,
data->intel_fn12h[i][EAX], data->intel_fn12h[i][EBX],
data->intel_fn12h[i][ECX], data->intel_fn12h[i][EDX]);
for (i = 0; i < MAX_INTELFN14H_LEVEL; i++)
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);
return set_error(ERR_OK);
int cpuid_serialize_all_raw_data(struct cpu_raw_data_array_t *data, const char* filename)
{
return cpuid_serialize_raw_data_internal(NULL, data, filename);
}
int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename)
{
int i, len;
char line[100];
char token[100];
char *value;
int syntax;
int cur_line = 0;
int recognized;
FILE *f;
raw_data_t_constructor(data);
return cpuid_deserialize_raw_data_internal(data, NULL, filename);
}
if (!strcmp(filename, ""))
f = stdin;
else
f = fopen(filename, "rt");
if (!f) return set_error(ERR_OPEN);
while (fgets(line, sizeof(line), f)) {
++cur_line;
len = (int) strlen(line);
if (len < 2) continue;
if (line[len - 1] == '\n')
line[--len] = '\0';
for (i = 0; i < len && line[i] != '='; i++)
if (i >= len && i < 1 && len - i - 1 <= 0) {
fclose(f);
return set_error(ERR_BADFMT);
}
strncpy(token, line, i);
token[i] = '\0';
value = &line[i + 1];
/* try to recognize the line */
recognized = 0;
if (!strcmp(token, "version") || !strcmp(token, "build_date")) {
recognized = 1;
}
syntax = 1;
syntax = syntax && parse_token("basic_cpuid", token, value, data->basic_cpuid, MAX_CPUID_LEVEL, &recognized);
syntax = syntax && parse_token("ext_cpuid", token, value, data->ext_cpuid, MAX_EXT_CPUID_LEVEL, &recognized);
syntax = syntax && parse_token("intel_fn4", token, value, data->intel_fn4, MAX_INTELFN4_LEVEL, &recognized);
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);
return set_error(ERR_BADFMT);
}
if (!recognized) {
warnf("Warning: %s:%d not understood!\n", filename, cur_line);
}
}
if (strcmp(filename, ""))
fclose(f);
return set_error(ERR_OK);
int cpuid_deserialize_all_raw_data(struct cpu_raw_data_array_t *data, const char* filename)
{
return cpuid_deserialize_raw_data_internal(NULL, data, filename);
}
int cpu_ident_internal(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)

View file

@ -33,6 +33,9 @@ cpuid_get_vendor @29
cpu_rdmsr_range @30
cpuid_get_epc @31
msr_serialize_raw_data @32
cpuid_get_all_raw_data @33
cpuid_serialize_all_raw_data @34
cpuid_deserialize_all_raw_data @35
cpu_identify_all @36
cpu_request_core_type @37
cpu_architecture_str @38

View file

@ -713,6 +713,15 @@ void cpu_exec_cpuid_ext(uint32_t* regs);
*/
int cpuid_get_raw_data(struct cpu_raw_data_t* data);
/**
* @brief Obtains the raw CPUID data from all CPUs
* @param data - a pointer to cpu_raw_data_array_t structure
* @returns zero if successful, and some negative number on error.
* The error message can be obtained by calling \ref cpuid_error.
* @see cpu_error_t
*/
int cpuid_get_all_raw_data(struct cpu_raw_data_array_t* data);
/**
* @brief Writes the raw CPUID data to a text file
* @param data - a pointer to cpu_raw_data_t structure
@ -732,6 +741,25 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data);
*/
int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
/**
* @brief Writes all the raw CPUID data to a text file
* @param data - a pointer to cpu_raw_data_array_t structure
* @param filename - the path of the file, where the serialized data for all CPUs
* should be written. If empty, stdout will be used.
* @note This is intended primarily for debugging. On some processor, which is
* not currently supported or not completely recognized by cpu_identify_all,
* one can still successfully get the raw data and write it to a file.
* libcpuid developers can later import this file and debug the detection
* code as if running on the actual hardware.
* The file is simple text format of "something=value" pairs. Version info
* is also written, but the format is not intended to be neither backward-
* nor forward compatible.
* @returns zero if successful, and some negative number on error.
* The error message can be obtained by calling \ref cpuid_error.
* @see cpu_error_t
*/
int cpuid_serialize_all_raw_data(struct cpu_raw_data_array_t *data, const char* filename);
/**
* @brief Reads raw CPUID data from file
* @param data - a pointer to cpu_raw_data_t structure. The deserialized data will
@ -746,6 +774,20 @@ int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
*/
int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
/**
* @brief Reads all raw CPUID data from file
* @param data - a pointer to cpu_raw_data_array_t structure. The deserialized array data will
* be written here.
* @param filename - the path of the file, containing the serialized raw data.
* If empty, stdin will be used.
* @note This function may fail, if the file is created by different version of
* the library. Also, see the notes on cpuid_serialize_all_raw_data.
* @returns zero if successful, and some negative number on error.
* The error message can be obtained by calling \ref cpuid_error.
* @see cpu_error_t
*/
int cpuid_deserialize_all_raw_data(struct cpu_raw_data_array_t *data, const char* filename);
/**
* @brief Identifies the CPU
* @param raw - Input - a pointer to the raw CPUID data, which is obtained

View file

@ -30,6 +30,9 @@ cpuid_get_vendor
cpu_rdmsr_range
cpuid_get_epc
msr_serialize_raw_data
cpuid_get_all_raw_data
cpuid_serialize_all_raw_data
cpuid_deserialize_all_raw_data
cpu_identify_all
cpu_request_core_type
cpu_architecture_str

View file

@ -46,6 +46,8 @@
#define SGX_FLAGS_MAX 14
#define CPU_RAW_MAX 512
#define CPU_TYPE_MAX 8
#define ADDRESS_EXT_CPUID_START 0x80000000
#define ADDRESS_EXT_CPUID_END ADDRESS_EXT_CPUID_START + MAX_EXT_CPUID_LEVEL
typedef enum {
EAX,