1
0
Fork 0
mirror of https://github.com/anrieff/libcpuid synced 2025-10-13 11:10:39 +00:00

Initial detection working

git-svn-id: https://svn.code.sf.net/p/libcpuid/code/HEAD/libcpuid@5 3b4be424-7ac5-41d7-8526-f4ddcb85d872
This commit is contained in:
Veselin Georgiev 2008-11-10 16:04:29 +00:00
commit 2d453e612c
10 changed files with 547 additions and 25 deletions

View file

@ -33,6 +33,8 @@
#include <stdio.h>
#include <string.h>
#define COUNT_OF(array) (sizeof(array) / sizeof(array[0]))
/* Implementation: */
static int _libcpiud_errno = ERR_OK;
@ -50,17 +52,19 @@ static int set_error(cpuid_error_t err)
return (int) err;
}
static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
{
return ERR_OK;
}
static void initialize_defaults(struct cpu_raw_data_t* raw)
static void raw_data_t_constructor(struct cpu_raw_data_t* raw)
{
memset(raw, 0, sizeof(struct cpu_raw_data_t));
}
static int parse_token(const char* expected_token, const char *token,
static void cpu_id_t_constructor(struct cpu_id_t* id)
{
memset(id, 0, sizeof(struct cpu_id_t));
id->l1_data_cache = id->l1_instruction_cache = id->l2_cache = id->l3_cache = -1;
id->l1_assoc = id->l2_assoc = id->l3_assoc = -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];
@ -83,6 +87,127 @@ static int parse_token(const char* expected_token, const char *token,
return 0;
}
struct feature_map_t {
unsigned bit;
cpu_feature_t feature;
};
static void match_features(const struct feature_map_t* matchtable, int count, uint32_t reg, struct cpu_id_t* data)
{
int i;
for (i = 0; i < count; i++)
if (reg & (1 << matchtable[i].bit))
data->flags[matchtable[i].feature] = 1;
}
static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
{
const struct feature_map_t matchtable_edx1[] = {
{ 0, CPU_FEATURE_FPU },
{ 1, CPU_FEATURE_VME },
{ 2, CPU_FEATURE_DEBUG },
{ 3, CPU_FEATURE_PSE },
{ 4, CPU_FEATURE_TSC },
{ 5, CPU_FEATURE_MSR },
{ 6, CPU_FEATURE_PAE },
{ 7, CPU_FEATURE_MCE },
{ 8, CPU_FEATURE_CX8 },
{ 9, CPU_FEATURE_APIC },
{ 12, CPU_FEATURE_MTRR },
{ 13, CPU_FEATURE_PGE },
{ 14, CPU_FEATURE_MCA },
{ 15, CPU_FEATURE_CMOV },
{ 16, CPU_FEATURE_PAT },
{ 17, CPU_FEATURE_PSE36 },
{ 19, CPU_FEATURE_CLFLUSH },
{ 23, CPU_FEATURE_MMX },
{ 24, CPU_FEATURE_FXSR },
{ 25, CPU_FEATURE_SSE },
{ 26, CPU_FEATURE_SSE2 },
{ 28, CPU_FEATURE_HT },
};
const struct feature_map_t matchtable_ecx1[] = {
{ 0, CPU_FEATURE_SSE3 },
{ 3, CPU_FEATURE_MON },
{ 9, CPU_FEATURE_SSSE3 },
{ 13, CPU_FEATURE_CX16 },
{ 19, CPU_FEATURE_SSE41 },
};
const struct feature_map_t matchtable_edx81[] = {
{ 29, CPU_FEATURE_LM },
};
const struct feature_map_t matchtable_ecx81[] = {
{ 0, CPU_FEATURE_LAHFSAHF },
};
if (raw->basic_cpuid[0][0] >= 1) {
match_features(matchtable_edx1, COUNT_OF(matchtable_edx1), raw->basic_cpuid[1][3], data);
match_features(matchtable_ecx1, COUNT_OF(matchtable_ecx1), raw->basic_cpuid[1][2], data);
}
if (raw->ext_cpuid[0][0] >= 1) {
match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data);
match_features(matchtable_ecx81, COUNT_OF(matchtable_ecx81), raw->ext_cpuid[1][2], data);
}
}
static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
{
int i, j;
memcpy(data->vendor_str + 0, &raw->basic_cpuid[0][1], 4);
memcpy(data->vendor_str + 4, &raw->basic_cpuid[0][3], 4);
memcpy(data->vendor_str + 8, &raw->basic_cpuid[0][2], 4);
data->vendor_str[12] = 0;
/* Determine vendor: */
const struct { cpu_vendor_t vendor; char match[16]; }
matchtable[NUM_VENDORS] = {
/* source: http://www.sandpile.org/ia32/cpuid.htm */
{ INTEL , "GenuineIntel" },
{ AMD , "AuthenticAMD" },
{ CYRIX , "CyrixInstead" },
{ NEXGEN , "NexGenDriven" },
{ TRANSMETA , "GenuineTMx86" },
{ UMC , "UMC UMC UMC " },
{ CENTAUR , "CentaurHauls" },
{ RISE , "RiseRiseRise" },
{ SIS , "SiS SiS SiS " },
{ NSC , "Geode by NSC" },
};
data->vendor = UNKNOWN;
for (i = 0; i < NUM_VENDORS; i++)
if (!strcmp(data->vendor_str, matchtable[i].match)) {
data->vendor = matchtable[i].vendor;
break;
}
if (data->vendor == UNKNOWN)
return set_error(ERR_CPU_UNKN);
int basic = raw->basic_cpuid[0][0];
if (basic >= 1) {
data->family = (raw->basic_cpuid[1][0] >> 8) & 0xf;
data->model = (raw->basic_cpuid[1][0] >> 4) & 0xf;
data->stepping = raw->basic_cpuid[1][0] & 0xf;
data->ext_model = (raw->basic_cpuid[1][0] >> 16) & 0xf;
data->ext_family = (raw->basic_cpuid[1][0] >> 20) & 0xff;
}
int ext = raw->ext_cpuid[0][0] - 0x8000000;
/* obtain the brand string, if present: */
char brandstr[64] = {0};
if (ext >= 4) {
for (i = 0; i < 3; i++)
for (j = 0; j < 4; j++)
memcpy(brandstr + i * 16 + j * 4,
&raw->ext_cpuid[2 + i][j], 4);
brandstr[48] = 0;
i = 0;
while (brandstr[i] == ' ') i++;
strncpy(data->brand_str, brandstr + i, sizeof(data->brand_str));
data->brand_str[48] = 0;
}
load_features_common(raw, data);
return set_error(ERR_OK);
}
/* Interface: */
int cpuid_present(void)
@ -110,7 +235,7 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data)
for (i = 0; i < 32; i++)
cpu_exec_cpuid(i, data->basic_cpuid[i]);
for (i = 0; i < 32; i++)
cpu_exec_cpuid(0x8000000 + i, data->ext_cpuid[i]);
cpu_exec_cpuid(0x80000000 + i, data->ext_cpuid[i]);
for (i = 0; i < 4; i++) {
memset(data->intel_fn4[i], 0, sizeof(data->intel_fn4[i]));
data->intel_fn4[i][0] = 4;
@ -128,17 +253,17 @@ int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename)
f = fopen(filename, "wt");
if (!f) return set_error(ERR_OPEN);
fprintf(f, "version = %s\n", VERSION);
fprintf(f, "version=%s\n", VERSION);
for (i = 0; i < MAX_CPUID_LEVEL; i++)
fprintf(f, "basic_cpuid[%d] = %08x %08x %08x %08x", i,
fprintf(f, "basic_cpuid[%d]=%08x %08x %08x %08x\n", i,
data->basic_cpuid[i][0], data->basic_cpuid[i][1],
data->basic_cpuid[i][2], data->basic_cpuid[i][3]);
for (i = 0; i < MAX_EXT_CPUID_LEVEL; i++)
fprintf(f, "ext_cpuid[%d] = %08x %08x %08x %08x", i,
fprintf(f, "ext_cpuid[%d]=%08x %08x %08x %08x\n", i,
data->ext_cpuid[i][0], data->ext_cpuid[i][1],
data->ext_cpuid[i][2], data->ext_cpuid[i][3]);
for (i = 0; i < MAX_INTELFN4_LEVEL; i++)
fprintf(f, "intel_fn4[%d] = %08x %08x %08x %08x", i,
fprintf(f, "intel_fn4[%d]=%08x %08x %08x %08x\n", i,
data->intel_fn4[i][0], data->intel_fn4[i][1],
data->intel_fn4[i][2], data->intel_fn4[i][3]);
@ -158,7 +283,7 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
int recognized;
FILE *f;
initialize_defaults(data);
raw_data_t_constructor(data);
f = fopen(filename, "rt");
if (!f) return set_error(ERR_OPEN);
@ -169,13 +294,13 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
if (line[len - 1] == '\n')
line[--len] = '\0';
for (i = 0; i < len && line[i] != '='; i++)
if (i >= len && i < 2 && len - i - 2 <= 0) {
if (i >= len && i < 1 && len - i - 1 <= 0) {
fclose(f);
return set_error(ERR_BADFMT);
}
strncpy(token, line, i - 1);
token[i - 1] = '\0';
value = &line[i + 2];
strncpy(token, line, i);
token[i] = '\0';
value = &line[i + 1];
// try to recognize the line
recognized = 0;
if (!strcmp(token, "version")) {
@ -206,6 +331,12 @@ 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)
{
int r;
struct cpu_raw_data_t myraw;
if (!raw) {
cpuid_get_raw_data(&myraw);
raw = &myraw;
}
cpu_id_t_constructor(data);
if ((r = cpuid_basic_identify(raw, data)) < 0)
return set_error(r);
switch (data->vendor) {
@ -223,12 +354,102 @@ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
const char* cpu_feature_str(cpu_feature_t feature)
{
return ""; // FIXME
const struct { cpu_feature_t feature; const char* name; }
matchtable[] = {
{ CPU_FEATURE_FPU, "fpu" },
{ CPU_FEATURE_VME, "vme" },
{ CPU_FEATURE_DEBUG, "debug" },
{ CPU_FEATURE_PSE, "pse" },
{ CPU_FEATURE_TSC, "tsc" },
{ CPU_FEATURE_MSR, "msr" },
{ CPU_FEATURE_PAE, "pae" },
{ CPU_FEATURE_MCE, "mce" },
{ CPU_FEATURE_CX8, "cx8" },
{ CPU_FEATURE_APIC, "apic" },
{ CPU_FEATURE_MTRR, "mtrr" },
{ CPU_FEATURE_PGE, "pge" },
{ CPU_FEATURE_MCA, "mca" },
{ CPU_FEATURE_CMOV, "cmov" },
{ CPU_FEATURE_PAT, "pat" },
{ CPU_FEATURE_PSE36, "pse36" },
{ CPU_FEATURE_PSN, "psn" },
{ CPU_FEATURE_CLFLUSH, "clflush" },
{ CPU_FEATURE_DTS, "dts" },
{ CPU_FEATURE_ACPI, "acpi" },
{ CPU_FEATURE_MMX, "mmx" },
{ CPU_FEATURE_FXSR, "fxsr" },
{ CPU_FEATURE_SSE, "sse" },
{ CPU_FEATURE_SSE2, "sse2" },
{ CPU_FEATURE_SS, "ss" },
{ CPU_FEATURE_HT, "ht" },
{ CPU_FEATURE_TM, "tm" },
{ CPU_FEATURE_IA64, "ia64" },
{ CPU_FEATURE_PBE, "pbe" },
{ CPU_FEATURE_SSE3, "sse3" },
{ CPU_FEATURE_PCLMUL, "pclmul" },
{ CPU_FEATURE_DTS64, "dts64" },
{ CPU_FEATURE_MON, "mon" },
{ CPU_FEATURE_DSCPL, "dscpl" },
{ CPU_FEATURE_VMX, "vmx" },
{ CPU_FEATURE_SMX, "smx" },
{ CPU_FEATURE_EST, "est" },
{ CPU_FEATURE_TM2, "tm2" },
{ CPU_FEATURE_SSSE3, "ssse3" },
{ CPU_FEATURE_CID, "cid" },
{ CPU_FEATURE_CX16, "cx16" },
{ CPU_FEATURE_ETPRD, "etprd" },
{ CPU_FEATURE_PDCM, "pdcm" },
{ CPU_FEATURE_DCA, "dca" },
{ CPU_FEATURE_SSE41, "sse41" },
{ CPU_FEATURE_SSE42, "sse42" },
{ CPU_FEATURE_MOVBE, "movbe" },
{ CPU_FEATURE_POPCNT, "popcnt" },
{ CPU_FEATURE_AES, "aes" },
{ CPU_FEATURE_XSAVE, "xsave" },
{ CPU_FEATURE_OSXSAVE, "osxsave" },
{ CPU_FEATURE_AVX, "avx" },
{ CPU_FEATURE_MMXEXT, "mmxext" },
{ CPU_FEATURE_3DNOW, "3dnow" },
{ CPU_FEATURE_3DNOWEXT, "3dnowext" },
{ CPU_FEATURE_NX, "nx" },
{ CPU_FEATURE_RDTSCP, "rdtscp" },
{ CPU_FEATURE_LM, "lm" },
{ CPU_FEATURE_LAHFSAHF, "lahfsahf" },
{ CPU_FEATURE_SVM, "svm" },
{ CPU_FEATURE_LZCNT, "lzcnt" },
{ CPU_FEATURE_3DNOWPREFETCH, "3dnowprefetch" },
{ CPU_FEATURE_OSVW, "osvw" },
{ CPU_FEATURE_IBS, "ibs" },
{ CPU_FEATURE_SSE51, "sse51" },
{ CPU_FEATURE_SKINIT, "skinit" },
{ CPU_FEATURE_WDT, "wdt" },
{ CPU_FEATURE_CONST_TSC, "const_tsc" },
};
unsigned i;
for (i = 0; i < COUNT_OF(matchtable); i++)
if (matchtable[i].feature == feature)
return matchtable[i].name;
return "";
}
const char* cpuid_error(void)
{
return ""; // FIXME
const struct { cpuid_error_t error; const char *description; }
matchtable[] = {
{ ERR_OK , "No error"},
{ ERR_NO_CPUID , "CPUID instruction is not supported"},
{ ERR_NO_RDTSC , "RDTSC instruction is not supported"},
{ ERR_NO_MEM , "Memory allocation failed"},
{ ERR_OPEN , "File open operation failed"},
{ ERR_BADFMT , "Bad file format"},
{ ERR_NOT_IMP , "Not implemented"},
{ ERR_CPU_UNKN , "Unsupported processor"},
};
unsigned i;
for (i = 0; i < COUNT_OF(matchtable); i++)
if (_libcpiud_errno == matchtable[i].error)
return matchtable[i].description;
return "Unknown error";
}
@ -236,3 +457,9 @@ const char* cpuid_lib_version(void)
{
return VERSION;
}
void set_warn_function(void (*warn_fun) (const char* msg))
{
_warn = warn_fun;
}