diff --git a/kernel/cpu.c b/kernel/cpu.c index a18041b..5982d72 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -2,36 +2,98 @@ #include "serial.h" #include "terminal.h" #include "utils.h" -#include "print.h" -void cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { - __asm__( - "cpuid" - : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) - : "a"(function) - ); +// Helper to print a labeled decimal value +void print_val(const char* label, uint32_t val) { + char buf[12]; + utoa(val, buf, 10); + 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() { + if (!check_cpuid_supported()) { + terminal_write("CPUID not supported. Likely a 386 or early 486.\n"); + return; + } + uint32_t eax, ebx, ecx, edx; char vendor[13]; + // Leaf 0: Vendor String & Max Leaf cpuid(0, &eax, &ebx, &ecx, &edx); - + uint32_t max_leaf = eax; *(uint32_t *)&vendor[0] = ebx; *(uint32_t *)&vendor[4] = edx; *(uint32_t *)&vendor[8] = ecx; vendor[12] = '\0'; - terminal_write("CPU Vendor: "); + terminal_write("Vendor: "); terminal_write(vendor); terminal_write("\n"); - serial_write("CPU Vendor: "); - serial_write(vendor); - serial_write("\n"); + // Leaf 1: Family, Model, Stepping + if (max_leaf >= 1) { + cpuid(1, &eax, &ebx, &ecx, &edx); + + uint32_t stepping = eax & 0xF; + uint32_t model = (eax >> 4) & 0xF; + uint32_t family = (eax >> 8) & 0xF; + uint32_t type = (eax >> 12) & 0x3; - terminal_write("CPUID max leaf: "); - print_hex(eax, false, false); // You must implement this (see below) - terminal_write("\n"); + // 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"); + } } diff --git a/kernel/cpu.h b/kernel/cpu.h index d2e165f..4eefd2e 100644 --- a/kernel/cpu.h +++ b/kernel/cpu.h @@ -2,8 +2,42 @@ #define CPU_H #include +#include -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); +// Helper to get the current CPU info after identification +cpu_info_t* cpu_get_info(void); + #endif // CPU_H