From 1cd5b71911a10a9d1122f3327cb6b194151712fd Mon Sep 17 00:00:00 2001 From: Philippe Aubertin <39178965+phaubertin@users.noreply.github.com> Date: Sat, 11 Jan 2025 00:31:48 -0500 Subject: [PATCH] Get CPU brand string (#106) Get and log the CPU brand string from CPUID leafs 0x80000002-0x80000004. --- include/ctype.h | 12 ++ .../kernel/infrastructure/i686/asm/cpuid.h | 23 ++-- include/kernel/infrastructure/i686/cpuinfo.h | 1 + .../kernel/infrastructure/i686/isa/instrs.h | 4 + kernel/infrastructure/i686/cpuinfo.c | 114 +++++++++++++++++- 5 files changed, 141 insertions(+), 13 deletions(-) diff --git a/include/ctype.h b/include/ctype.h index 1177ead2..87e52c2a 100644 --- a/include/ctype.h +++ b/include/ctype.h @@ -40,4 +40,16 @@ static inline int isxdigit(int c) { return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } +static inline int isblank(int c) { + return c == ' ' || c == '\t'; +} + +static inline int isspace(int c) { + return isblank(c) || c == '\n' || c == '\r' || c == '\v'; +} + +static inline int isprint(int c) { + return c >= ' ' && c <= '~'; +} + #endif diff --git a/include/kernel/infrastructure/i686/asm/cpuid.h b/include/kernel/infrastructure/i686/asm/cpuid.h index f5963988..bb815698 100644 --- a/include/kernel/infrastructure/i686/asm/cpuid.h +++ b/include/kernel/infrastructure/i686/asm/cpuid.h @@ -32,6 +32,18 @@ #ifndef JINUE_KERNEL_INFRASTRUCTURE_I686_ASM_CPUID_H #define JINUE_KERNEL_INFRASTRUCTURE_I686_ASM_CPUID_H +/* Basic leaf 0 (0x00000001) ebx, ecx, edx */ + +#define CPUID_VENDOR_AMD_DW0 0x68747541 /* Auth */ +#define CPUID_VENDOR_AMD_DW1 0x69746e65 /* enti */ +#define CPUID_VENDOR_AMD_DW2 0x444d4163 /* cAMD */ + +#define CPUID_VENDOR_INTEL_DW0 0x756e6547 /* Genu */ +#define CPUID_VENDOR_INTEL_DW1 0x49656e69 /* ineI */ +#define CPUID_VENDOR_INTEL_DW2 0x6c65746e /* ntel */ + +/* Basic leaf 1 (0x00000001) edx */ + #define CPUID_FEATURE_FPU (1<<0) #define CPUID_FEATURE_PSE (1<<3) @@ -46,19 +58,12 @@ #define CPUID_FEATURE_CLFLUSH (1<<19) -#define CPUID_FEATURE_NXE (1<<20) - #define CPUID_FEATURE_HTT (1<<28) +/* Extended leaf 1 (0x8000001) edx */ #define CPUID_EXT_FEATURE_SYSCALL (1<<11) -#define CPUID_VENDOR_AMD_DW0 0x68747541 /* Auth */ -#define CPUID_VENDOR_AMD_DW1 0x69746e65 /* enti */ -#define CPUID_VENDOR_AMD_DW2 0x444d4163 /* cAMD */ - -#define CPUID_VENDOR_INTEL_DW0 0x756e6547 /* Genu */ -#define CPUID_VENDOR_INTEL_DW1 0x49656e69 /* ineI */ -#define CPUID_VENDOR_INTEL_DW2 0x6c65746e /* ntel */ +#define CPUID_FEATURE_NXE (1<<20) #endif diff --git a/include/kernel/infrastructure/i686/cpuinfo.h b/include/kernel/infrastructure/i686/cpuinfo.h index a91d7e6d..f4f3182a 100644 --- a/include/kernel/infrastructure/i686/cpuinfo.h +++ b/include/kernel/infrastructure/i686/cpuinfo.h @@ -44,6 +44,7 @@ typedef struct { unsigned int family; unsigned int model; unsigned int stepping; + char brand_string[49]; } cpuinfo_t; extern cpuinfo_t bsp_cpuinfo; diff --git a/include/kernel/infrastructure/i686/isa/instrs.h b/include/kernel/infrastructure/i686/isa/instrs.h index 20ac5372..687d0182 100644 --- a/include/kernel/infrastructure/i686/isa/instrs.h +++ b/include/kernel/infrastructure/i686/isa/instrs.h @@ -46,7 +46,11 @@ typedef struct { x86_cpuid_regs_t basic1; x86_cpuid_regs_t ext0; x86_cpuid_regs_t ext1; + x86_cpuid_regs_t ext2; + x86_cpuid_regs_t ext3; + x86_cpuid_regs_t ext4; x86_cpuid_regs_t ext8; + bool ext4_valid; bool ext8_valid; } x86_cpuid_leafs; diff --git a/kernel/infrastructure/i686/cpuinfo.c b/kernel/infrastructure/i686/cpuinfo.c index 0c6fb535..3471dbd7 100644 --- a/kernel/infrastructure/i686/cpuinfo.c +++ b/kernel/infrastructure/i686/cpuinfo.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -96,6 +97,17 @@ static void call_cpuid(x86_cpuid_leafs *leafs) { (void)cpuid(&leafs->ext1); } + leafs->ext4_valid = ext_max >= ext_base + 4; + + if(leafs->ext4_valid) { + leafs->ext2.eax = ext_base + 2; + leafs->ext3.eax = ext_base + 3; + leafs->ext4.eax = ext_base + 4; + (void)cpuid(&leafs->ext2); + (void)cpuid(&leafs->ext3); + (void)cpuid(&leafs->ext4); + } + leafs->ext8_valid = ext_max >= ext_base + 8; if(leafs->ext8_valid) { @@ -176,6 +188,95 @@ static void identify_model(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) { } } +typedef enum { + CLEAN_STATE_START, + CLEAN_STATE_IDLE, + CLEAN_STATE_SPACE, +} clean_state_t; + +/** + * Clean the CPU brand string + * + * Remove leading and trailing whitespace characters, coalesce sequences of + * whitespace charaters and remove non-printable characters. + * + * @param buffer string buffer containing brand string + */ +static void clean_brand_string(char *buffer) { + clean_state_t state = CLEAN_STATE_START; + + int dest = 0; + int src = 0; + + /* Invariant: dest is always at or before src, so what happens at dest + * never affects the condition of this loop. */ + while(true) { + int c = buffer[src]; + + if(c == '\0') { + /* Add a single space character if there is a pending space. This + * ensure space/tab sequences are coalesced into a single space + * charater and leading spaces are trimmed. */ + if(state == CLEAN_STATE_SPACE) { + buffer[dest++] = ' '; + } + + buffer[dest++] = '\0'; + break; + } else if(isblank(c)) { + /* Transition to the space state only if at least one printable + * character was encountered since the start of the string. */ + if(state == CLEAN_STATE_IDLE) { + state = CLEAN_STATE_SPACE; + } + } else if(isprint(c) && !isspace(c)) { + if(state == CLEAN_STATE_SPACE) { + buffer[dest++] = ' '; + } + + buffer[dest++] = c; + state = CLEAN_STATE_IDLE; + } + + ++src; + } +} + +/** + * Get the CPU brand string + * + * Sets an empty string if the brand string cannot be retrieved. + * + * @param cpuinfo structure in which to set the brand string (OUT) + * @param leafs CPUID leafs structure filled by a call_cpuid() + */ +static void get_brand_string(cpuinfo_t *cpuinfo, const x86_cpuid_leafs *leafs) { + if(! leafs->ext4_valid) { + cpuinfo->brand_string[0] = '\0'; + return; + } + + snprintf( + cpuinfo->brand_string, + sizeof(cpuinfo->brand_string), + "%.4s%.4s%.4s%.4s%.4s%.4s%.4s%.4s%.4s%.4s%.4s%.4s", + (const char *)&leafs->ext2.eax, + (const char *)&leafs->ext2.ebx, + (const char *)&leafs->ext2.ecx, + (const char *)&leafs->ext2.edx, + (const char *)&leafs->ext3.eax, + (const char *)&leafs->ext3.ebx, + (const char *)&leafs->ext3.ecx, + (const char *)&leafs->ext3.edx, + (const char *)&leafs->ext4.eax, + (const char *)&leafs->ext4.ebx, + (const char *)&leafs->ext4.ecx, + (const char *)&leafs->ext4.edx + ); + + clean_brand_string(cpuinfo->brand_string); +} + /** * Identify the data cache alignment * @@ -342,7 +443,7 @@ static void dump_features(const cpuinfo_t *cpuinfo) { (cpuinfo->features & CPUINFO_FEATURE_SYSENTER) ? " sysenter" : "" ); - info("CPU features:%s", buffer); + info(" Features:%s", buffer); } /** @@ -368,8 +469,10 @@ static const char *get_vendor_string(const cpuinfo_t *cpuinfo) { * @param cpuinfo CPU information structure */ static void dump_cpu_features(const cpuinfo_t *cpuinfo) { + info("CPU information:"); + info( - "CPU vendor: %s family: %u model: %u stepping: %u", + " Vendor: %s family: %u model: %u stepping: %u", get_vendor_string(cpuinfo), cpuinfo->family, cpuinfo->model, @@ -378,8 +481,9 @@ static void dump_cpu_features(const cpuinfo_t *cpuinfo) { dump_features(cpuinfo); - info("CPU data cache alignment: %u bytes", cpuinfo->dcache_alignment); - info("CPU physical address size: %u bits", cpuinfo->maxphyaddr); + info(" Brand string: %s", cpuinfo->brand_string); + info(" Data cache alignment: %u bytes", cpuinfo->dcache_alignment); + info(" Physical address size: %u bits", cpuinfo->maxphyaddr); } /** @@ -395,6 +499,8 @@ void detect_cpu_features(void) { identify_model(&bsp_cpuinfo, &cpuid_leafs); + get_brand_string(&bsp_cpuinfo, &cpuid_leafs); + identify_dcache_alignment(&bsp_cpuinfo, &cpuid_leafs); enumerate_features(&bsp_cpuinfo, &cpuid_leafs);