diff --git a/libcpuid/cpuid_main.c b/libcpuid/cpuid_main.c index 705efb9..5716745 100644 --- a/libcpuid/cpuid_main.c +++ b/libcpuid/cpuid_main.c @@ -35,6 +35,7 @@ #include #include #include +#include /* Implementation: */ @@ -310,6 +311,7 @@ static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* dat if (data->vendor == VENDOR_UNKNOWN) return set_error(ERR_CPU_UNKN); + data->architecture = ARCHITECTURE_X86; basic = raw->basic_cpuid[0][EAX]; if (basic >= 1) { data->family = (raw->basic_cpuid[1][EAX] >> 8) & 0xf; @@ -558,6 +560,8 @@ int cpu_ident_internal(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct raw = &myraw; } cpu_id_t_constructor(data); + internal->smt_id = -1; + internal->core_id = -1; if ((r = cpuid_basic_identify(raw, data)) < 0) return set_error(r); switch (data->vendor) { @@ -584,6 +588,42 @@ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) return cpu_ident_internal(raw, data, &throwaway); } +const char* cpu_architecture_str(cpu_architecture_t architecture) +{ + const struct { cpu_architecture_t architecture; const char* name; } + matchtable[] = { + { ARCHITECTURE_UNKNOWN, "unknown" }, + { ARCHITECTURE_X86, "x86" }, + { ARCHITECTURE_ARM, "ARM" }, + }; + unsigned i, n = COUNT_OF(matchtable); + if (n != NUM_CPU_ARCHITECTURES + 1) { + warnf("Warning: incomplete library, architecture matchtable size differs from the actual number of architectures.\n"); + } + for (i = 0; i < n; i++) + if (matchtable[i].architecture == architecture) + return matchtable[i].name; + return ""; +} + +const char* cpu_purpose_str(cpu_purpose_t purpose) +{ + const struct { cpu_purpose_t purpose; const char* name; } + matchtable[] = { + { PURPOSE_GENERAL, "general" }, + { PURPOSE_PERFORMANCE, "performance" }, + { PURPOSE_EFFICIENCY, "efficiency" }, + }; + unsigned i, n = COUNT_OF(matchtable); + if (n != NUM_CPU_PURPOSES) { + warnf("Warning: incomplete library, purpose matchtable size differs from the actual number of purposes.\n"); + } + for (i = 0; i < n; i++) + if (matchtable[i].purpose == purpose) + return matchtable[i].name; + return ""; +} + const char* cpu_feature_str(cpu_feature_t feature) { const struct { cpu_feature_t feature; const char* name; } diff --git a/libcpuid/exports.def b/libcpuid/exports.def index acd9da3..698e3f6 100644 --- a/libcpuid/exports.def +++ b/libcpuid/exports.def @@ -33,3 +33,5 @@ cpuid_get_vendor @29 cpu_rdmsr_range @30 cpuid_get_epc @31 msr_serialize_raw_data @32 +cpu_architecture_str @38 +cpu_purpose_str @39 diff --git a/libcpuid/libcpuid.h b/libcpuid/libcpuid.h index b59761d..ec8d5ec 100644 --- a/libcpuid/libcpuid.h +++ b/libcpuid/libcpuid.h @@ -90,6 +90,9 @@ * @brief LibCPUID provides CPU identification @{ */ +/* Include C99 booleans: */ +#include + /* Include some integer type specifications: */ #include "libcpuid_types.h" @@ -121,6 +124,30 @@ typedef enum { } cpu_vendor_t; #define NUM_CPU_VENDORS NUM_CPU_VENDORS +/** + * @brief CPU architecture + */ +typedef enum { + ARCHITECTURE_X86 = 0, /*!< x86 CPU */ + ARCHITECTURE_ARM, /*!< ARM CPU */ + + NUM_CPU_ARCHITECTURES, /*!< Valid CPU architecture ids: 0..NUM_CPU_ARCHITECTURES - 1 */ + ARCHITECTURE_UNKNOWN = -1, +} cpu_architecture_t; +#define NUM_CPU_ARCHITECTURES NUM_CPU_ARCHITECTURES + +/** + * @brief CPU purpose + */ +typedef enum { + PURPOSE_GENERAL = 0, /*!< general purpose CPU */ + PURPOSE_PERFORMANCE, /*!< performance CPU */ + PURPOSE_EFFICIENCY, /*!< efficiency CPU */ + + NUM_CPU_PURPOSES, /*!< Valid CPU purpose ids: 0..NUM_CPU_PURPOSES - 1 */ +} cpu_purpose_t; +#define NUM_CPU_PURPOSES NUM_CPU_PURPOSES + /** * @brief Contains just the raw CPUID data. * @@ -163,6 +190,26 @@ struct cpu_raw_data_t { uint32_t amd_fn8000001dh[MAX_AMDFN8000001DH_LEVEL][NUM_REGS]; }; +/** + * @brief Contains an array of raw CPUID data. + * + * This contains one \ref cpu_raw_data_t for each logical CPU. + */ +struct cpu_raw_data_array_t { + /** Indicates if \ref raw was obtained by using CPU affinity + * if false, \ref raw contains a single data from an old dump (versions 0.5.1 and below). + * if true, \ref raw contains data from a new dump (versions 0.6.0 and above). + * if true and if \ref num_raw is 1, it indicates only one logical core was detected on the system. + */ + bool with_affinity; + + /** \ref raw length */ + uint8_t num_raw; + + /** array of raw CPUID data */ + struct cpu_raw_data_t raw[CPU_RAW_MAX]; +}; + /** * @brief This contains information about SGX features of the processor * Example usage: @@ -231,6 +278,9 @@ struct cpu_sgx_t { * @brief This contains the recognized CPU features/info */ struct cpu_id_t { + /** contains the CPU architecture ID (e.g. ARCHITECTURE_X86) */ + cpu_architecture_t architecture; + /** contains the CPU vendor string, e.g. "GenuineIntel" */ char vendor_str[VENDOR_STR_MAX]; @@ -385,6 +435,23 @@ struct cpu_id_t { /** contains information about SGX features if the processor, if present */ struct cpu_sgx_t sgx; + + /** bitmask of the affinity ids this processor type is occupying */ + uint32_t affinity_mask; + + /** processor type purpose, relevant in case of hybrid CPU (e.g. PURPOSE_PERFORMANCE) */ + cpu_purpose_t purpose; +}; + +/** + * @brief This contains the recognized features/info for all CPUs on the system + */ +struct system_id_t { + /** count of different processor types in the system (e.g. performance, efficiency, ...) */ + uint8_t num_cpu_types; + + /** array of recognized CPU features/info for each different processor types in the system */ + struct cpu_id_t cpu_types[CPU_TYPE_MAX]; }; /** @@ -703,6 +770,20 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename */ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data); +/** + * @brief Returns the short textual representation of a CPU architecture + * @param architecture - the architecture, whose textual representation is wanted. + * @returns a constant string like "x86", "ARM", etc. + */ +const char* cpu_architecture_str(cpu_architecture_t architecture); + +/** + * @brief Returns the short textual representation of a CPU purpose + * @param purpose - the purpose, whose textual representation is wanted. + * @returns a constant string like "general", "performance", "efficiency", etc. + */ +const char* cpu_purpose_str(cpu_purpose_t purpose); + /** * @brief Returns the short textual representation of a CPU flag * @param feature - the feature, whose textual representation is wanted. diff --git a/libcpuid/libcpuid.sym b/libcpuid/libcpuid.sym index a55f753..e5ff9fa 100644 --- a/libcpuid/libcpuid.sym +++ b/libcpuid/libcpuid.sym @@ -30,3 +30,5 @@ cpuid_get_vendor cpu_rdmsr_range cpuid_get_epc msr_serialize_raw_data +cpu_architecture_str +cpu_purpose_str diff --git a/libcpuid/libcpuid_constants.h b/libcpuid/libcpuid_constants.h index f3efa5b..45203f6 100644 --- a/libcpuid/libcpuid_constants.h +++ b/libcpuid/libcpuid_constants.h @@ -44,6 +44,8 @@ #define MAX_AMDFN8000001DH_LEVEL 4 #define CPU_HINTS_MAX 16 #define SGX_FLAGS_MAX 14 +#define CPU_RAW_MAX 512 +#define CPU_TYPE_MAX 8 typedef enum { EAX, diff --git a/libcpuid/libcpuid_internal.h b/libcpuid/libcpuid_internal.h index 8d5db4d..647091e 100644 --- a/libcpuid/libcpuid_internal.h +++ b/libcpuid/libcpuid_internal.h @@ -59,6 +59,8 @@ struct internal_id_info_t { } code; uint64_t bits; int score; // detection (matchtable) score + int32_t smt_id; + int32_t core_id; }; #define LBIT(x) (((long long) 1) << x)