mirror of
https://github.com/gbowne1/ClassicOS.git
synced 2026-01-11 17:15:19 -08:00
Merge pull request #86 from gbowne1/gbowne1-cpuidfix-1
IImplement CPUID support check and CPU info printing
This commit is contained in:
90
kernel/cpu.c
90
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);
|
||||
|
||||
terminal_write("CPUID max leaf: ");
|
||||
print_hex(eax, false, false); // You must implement this (see below)
|
||||
uint32_t stepping = eax & 0xF;
|
||||
uint32_t model = (eax >> 4) & 0xF;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
36
kernel/cpu.h
36
kernel/cpu.h
@@ -2,8 +2,42 @@
|
||||
#define CPU_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);
|
||||
|
||||
// Helper to get the current CPU info after identification
|
||||
cpu_info_t* cpu_get_info(void);
|
||||
|
||||
#endif // CPU_H
|
||||
|
||||
Reference in New Issue
Block a user