Merge pull request #86 from gbowne1/gbowne1-cpuidfix-1

IImplement CPUID support check and CPU info printing
This commit is contained in:
2026-01-09 11:59:52 -08:00
committed by GitHub
2 changed files with 112 additions and 16 deletions

View File

@@ -2,36 +2,98 @@
#include "serial.h" #include "serial.h"
#include "terminal.h" #include "terminal.h"
#include "utils.h" #include "utils.h"
#include "print.h"
void cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { // Helper to print a labeled decimal value
__asm__( void print_val(const char* label, uint32_t val) {
"cpuid" char buf[12];
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) utoa(val, buf, 10);
: "a"(function) terminal_write(label);
); terminal_write(buf);
terminal_write(" ");
}
// Safely check if CPUID is supported by attempting to flip bit 21 of EFLAGS
int check_cpuid_supported() {
uint32_t f1, f2;
__asm__ volatile (
"pushfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"movl %0, %1\n\t"
"xorl $0x200000, %0\n\t"
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"popfl\n\t"
: "=&r" (f1), "=&r" (f2));
return ((f1 ^ f2) & 0x200000) != 0;
} }
void identify_cpu() { void identify_cpu() {
if (!check_cpuid_supported()) {
terminal_write("CPUID not supported. Likely a 386 or early 486.\n");
return;
}
uint32_t eax, ebx, ecx, edx; uint32_t eax, ebx, ecx, edx;
char vendor[13]; char vendor[13];
// Leaf 0: Vendor String & Max Leaf
cpuid(0, &eax, &ebx, &ecx, &edx); cpuid(0, &eax, &ebx, &ecx, &edx);
uint32_t max_leaf = eax;
*(uint32_t *)&vendor[0] = ebx; *(uint32_t *)&vendor[0] = ebx;
*(uint32_t *)&vendor[4] = edx; *(uint32_t *)&vendor[4] = edx;
*(uint32_t *)&vendor[8] = ecx; *(uint32_t *)&vendor[8] = ecx;
vendor[12] = '\0'; vendor[12] = '\0';
terminal_write("CPU Vendor: "); terminal_write("Vendor: ");
terminal_write(vendor); terminal_write(vendor);
terminal_write("\n"); terminal_write("\n");
serial_write("CPU Vendor: "); // Leaf 1: Family, Model, Stepping
serial_write(vendor); if (max_leaf >= 1) {
serial_write("\n"); cpuid(1, &eax, &ebx, &ecx, &edx);
terminal_write("CPUID max leaf: "); uint32_t stepping = eax & 0xF;
print_hex(eax, false, false); // You must implement this (see below) uint32_t model = (eax >> 4) & 0xF;
terminal_write("\n"); uint32_t family = (eax >> 8) & 0xF;
uint32_t type = (eax >> 12) & 0x3;
// Handle Extended Family/Model (Required for Pentium 4 and newer)
if (family == 0xF) {
family += (eax >> 20) & 0xFF;
model += ((eax >> 16) & 0xF) << 4;
}
print_val("Family:", family);
print_val("Model:", model);
print_val("Step:", stepping);
terminal_write("\n");
}
// Leaf 2: Cache Descriptors
if (max_leaf >= 2) {
cpuid(2, &eax, &ebx, &ecx, &edx);
terminal_write("Cache Descriptors: ");
// Note: Leaf 2 returns a list of 1-byte descriptors in the registers.
// We look for common Intel ones:
uint32_t regs[4] = {eax, ebx, ecx, edx};
for (int i = 0; i < 4; i++) {
if (regs[i] & 0x80000000) continue; // Reserved bit
for (int j = 0; j < 4; j++) {
uint8_t desc = (regs[i] >> (j * 8)) & 0xFF;
if (desc == 0) continue;
// Example decoding for specific chips you mentioned:
if (desc == 0x06) terminal_write("8KB L1 I-Cache ");
if (desc == 0x0A) terminal_write("8KB L1 D-Cache ");
if (desc == 0x41) terminal_write("128KB L2 ");
if (desc == 0x43) terminal_write("512KB L2 ");
if (desc == 0x2C) terminal_write("32KB L1 D-Cache ");
}
}
terminal_write("\n");
}
} }

View File

@@ -2,8 +2,42 @@
#define CPU_H #define CPU_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
void cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); // Specific Intel Model Definitions for your targets
#define INTEL_FAM4_486_DX 0x00 // Also 0x01
#define INTEL_FAM4_486_SX 0x02
#define INTEL_FAM4_486_DX2 0x03
#define INTEL_FAM4_486_DX4 0x08
#define INTEL_FAM5_PENTIUM 0x01 // P5
#define INTEL_FAM5_PENTIUM_MMX 0x04 // P55C
#define INTEL_FAM6_PENTIUM_PRO 0x01 // P6
#define INTEL_FAM6_PENTIUM_II 0x05 // Deschutes
#define INTEL_FAM6_PENTIUM_III 0x07 // Katmai/Coppermine
#define INTEL_FAM15_P4_WILLY 0x00 // Willamette
#define INTEL_FAM15_P4_NORTH 0x02 // Northwood
#define INTEL_FAM15_P4_PRES 0x03 // Prescott
typedef struct {
char vendor[13];
uint32_t family;
uint32_t model;
uint32_t stepping;
uint32_t type;
uint32_t max_leaf;
// Feature flags (optional, but very helpful later)
bool has_fpu;
bool has_mmx;
bool has_sse;
} cpu_info_t;
// Function Prototypes
void cpuid(uint32_t leaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
bool cpu_check_cpuid_support(void);
void identify_cpu(void); void identify_cpu(void);
// Helper to get the current CPU info after identification
cpu_info_t* cpu_get_info(void);
#endif // CPU_H #endif // CPU_H