Skip to content

Commit

Permalink
kernel: detect CPU features
Browse files Browse the repository at this point in the history
  • Loading branch information
mosmeh committed Jul 5, 2024
1 parent d73a164 commit c4ff122
Show file tree
Hide file tree
Showing 9 changed files with 516 additions and 24 deletions.
1 change: 1 addition & 0 deletions kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ OBJS := \
console/tty.o \
console/virtual_console.o \
console/vt.o \
cpu.o \
drivers/ac97.o \
drivers/drivers.o \
drivers/graphics/bochs.o \
Expand Down
12 changes: 12 additions & 0 deletions kernel/asm_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,15 @@ static inline void cpuid(uint32_t function, uint32_t* eax, uint32_t* ebx,
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
: "a"(function));
}

static inline uint64_t rdmsr(uint32_t msr) {
uint32_t lo;
uint32_t hi;
__asm__ volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr));
return ((uint64_t)hi << 32) | lo;
}

static inline void wrmsr(uint32_t msr, uint64_t value) {
__asm__ volatile("wrmsr" ::"a"((uint32_t)value),
"d"((uint32_t)(value >> 32)), "c"(msr));
}
10 changes: 0 additions & 10 deletions kernel/boot.S
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,10 @@ paging_enabled:
movl $kernel_page_directory_start, %edx
movl %edx, %cr3

movl %cr4, %edx
orl $0x80, %edx # PGE
movl %edx, %cr4

movl $stack_top, %esp
pushl %ebx # Multiboot info struct
pushl %eax # Multiboot magic

movl $0x277, %ecx # IA32_PAT
rdmsr
andl $~0x7, %edx
orl $1, %edx # PAT4 = WC
wrmsr

call start

cli
Expand Down
271 changes: 271 additions & 0 deletions kernel/cpu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
#include "cpu.h"
#include "asm_wrapper.h"

static struct cpu cpu;

static void set_feature(int feature) {
cpu.features[feature >> 5] |= 1 << (feature & 31);
}

static void detect_features(void) {
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;

uint32_t* vendor_id = (uint32_t*)cpu.vendor_id;
cpuid(0, &eax, vendor_id, vendor_id + 2, vendor_id + 1);
if (eax < 1) {
// CPUID is not supported
return;
}

cpuid(1, &eax, &ebx, &ecx, &edx);
cpu.stepping = eax & 0xf;
cpu.model = (eax >> 4) & 0xf;
cpu.family = (eax >> 8) & 0xf;
switch (cpu.family) {
case 0xf:
cpu.family += (eax >> 20) & 0xff;
// falls through
case 0x6:
cpu.model += ((eax >> 16) & 0xf) << 4;
}

#define F(reg, bit, name) \
if ((reg) & (1 << (bit))) \
set_feature(X86_FEATURE_##name);

F(ecx, 0, XMM3)
F(ecx, 1, PCLMULQDQ)
F(ecx, 2, DTES64)
F(ecx, 3, MWAIT)
F(ecx, 4, DSCPL)
F(ecx, 5, VMX)
F(ecx, 6, SMX)
F(ecx, 7, EST)
F(ecx, 8, TM2)
F(ecx, 9, SSSE3)
F(ecx, 10, CID)
F(ecx, 11, SDBG)
F(ecx, 12, FMA)
F(ecx, 13, CX16)
F(ecx, 14, XTPR)
F(ecx, 15, PDCM)
F(ecx, 17, PCID)
F(ecx, 18, DCA)
F(ecx, 19, XMM4_1)
F(ecx, 20, XMM4_2)
F(ecx, 21, X2APIC)
F(ecx, 22, MOVBE)
F(ecx, 23, POPCNT)
F(ecx, 24, TSC_DEADLINE_TIMER)
F(ecx, 25, AES)
F(ecx, 26, XSAVE)
F(ecx, 27, OSXSAVE)
F(ecx, 28, AVX)
F(ecx, 29, F16C)
F(ecx, 30, RDRAND)
F(ecx, 31, HYPERVISOR)

F(edx, 0, FPU)
F(edx, 1, VME)
F(edx, 2, DE)
F(edx, 3, PSE)
F(edx, 4, TSC)
F(edx, 5, MSR)
F(edx, 6, PAE)
F(edx, 7, MCE)
F(edx, 8, CX8)
F(edx, 9, APIC)
F(edx, 11, SEP)
F(edx, 12, MTRR)
F(edx, 13, PGE)
F(edx, 14, MCA)
F(edx, 15, CMOV)
F(edx, 16, PAT)
F(edx, 17, PSE36)
F(edx, 18, PN)
F(edx, 19, CLFLUSH)
F(edx, 21, DS)
F(edx, 22, ACPI)
F(edx, 23, MMX)
F(edx, 24, FXSR)
F(edx, 25, XMM)
F(edx, 26, XMM2)
F(edx, 27, SELFSNOOP)
F(edx, 28, HT)
F(edx, 29, ACC)
F(edx, 30, IA64)
F(edx, 31, PBE)

cpuid(7, &eax, &ebx, &ecx, &edx);

F(ebx, 0, FSGSBASE)
F(ebx, 1, TSC_ADJUST)
F(ebx, 2, SGX)
F(ebx, 3, BMI1)
F(ebx, 4, HLE)
F(ebx, 5, AVX2)
F(ebx, 6, FDP_EXCPTN_ONLY)
F(ebx, 7, SMEP)
F(ebx, 8, BMI2)
F(ebx, 9, ERMS)
F(ebx, 10, INVPCID)
F(ebx, 11, RTM)
F(ebx, 12, CQM)
F(ebx, 13, ZERO_FCS_FDS)
F(ebx, 14, MPX)
F(ebx, 15, RDT_A)
F(ebx, 16, AVX512F)
F(ebx, 17, AVX512DQ)
F(ebx, 18, RDSEED)
F(ebx, 19, ADX)
F(ebx, 20, SMAP)
F(ebx, 21, AVX512IFMA)
F(ebx, 23, CLFLUSHOPT)
F(ebx, 24, CLWB)
F(ebx, 25, INTEL_PT)
F(ebx, 26, AVX512PF)
F(ebx, 27, AVX512ER)
F(ebx, 28, AVX512CD)
F(ebx, 29, SHA_NI)
F(ebx, 30, AVX512BW)
F(ebx, 31, AVX512VL)

F(ecx, 1, AVX512VBMI)
F(ecx, 2, UMIP)
F(ecx, 3, PKU)
F(ecx, 4, OSPKE)
F(ecx, 5, WAITPKG)
F(ecx, 6, AVX512_VBMI2)
F(ecx, 7, SHSTK)
F(ecx, 8, GFNI)
F(ecx, 9, VAES)
F(ecx, 10, VPCLMULQDQ)
F(ecx, 11, AVX512_VNNI)
F(ecx, 12, AVX512_BITALG)
F(ecx, 13, TME)
F(ecx, 14, AVX512_VPOPCNTDQ)
F(ecx, 16, LA57)
F(ecx, 22, RDPID)
F(ecx, 23, BUS_LOCK_DETECT)
F(ecx, 25, CLDEMOTE)
F(ecx, 27, MOVDIRI)
F(ecx, 28, MOVDIR64B)
F(ecx, 29, ENQCMD)
F(ecx, 30, SGX_LC)

F(edx, 2, AVX512_4VNNIW)
F(edx, 3, AVX512_4FMAPS)
F(edx, 4, FSRM)
F(edx, 8, AVX512_VP2INTERSECT)
F(edx, 9, SRBDS_CTRL)
F(edx, 10, MD_CLEAR)
F(edx, 11, TSX_FORCE_ABORT)
F(edx, 13, TSX_FORCE_ABORT)
F(edx, 14, SERIALIZE)
F(edx, 15, HYBRID_CPU)
F(edx, 16, TSXLDTRK)
F(edx, 18, PCONFIG)
F(edx, 19, ARCH_LBR)
F(edx, 20, IBT)
F(edx, 22, AMX_BF16)
F(edx, 23, AVX512_FP16)
F(edx, 24, AMX_TILE)
F(edx, 25, AMX_INT8)
F(edx, 26, SPEC_CTRL)
F(edx, 27, INTEL_STIBP)
F(edx, 28, FLUSH_L1D)
F(edx, 29, ARCH_CAPABILITIES)
F(edx, 30, CORE_CAPABILITIES)
F(edx, 31, SPEC_CTRL_SSBD)

uint32_t max_ext_func;
cpuid(0x80000000, &max_ext_func, &ebx, &ecx, &edx);
if (max_ext_func >= 0x80000001) {
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);

F(ecx, 0, LAHF_LM)
F(ecx, 1, CMP_LEGACY)
F(ecx, 2, SVM)
F(ecx, 3, EXTAPIC)
F(ecx, 4, CR8_LEGACY)
F(ecx, 5, ABM)
F(ecx, 6, SSE4A)
F(ecx, 7, MISALIGNSSE)
F(ecx, 8, 3DNOWPREFETCH)
F(ecx, 9, OSVW)
F(ecx, 10, IBS)
F(ecx, 11, XOP)
F(ecx, 12, SKINIT)
F(ecx, 13, WDT)
F(ecx, 15, LWP)
F(ecx, 16, FMA4)
F(ecx, 17, TCE)
F(ecx, 19, NODEID_MSR)
F(ecx, 21, TBM)
F(ecx, 22, TOPOEXT)
F(ecx, 23, PERFCTR_CORE)
F(ecx, 24, PERFCTR_NB)
F(ecx, 26, BPEXT)
F(ecx, 27, PTSC)
F(ecx, 28, PERFCTR_LLC)
F(ecx, 29, MWAITX)

F(edx, 11, SYSCALL)
F(edx, 19, MP)
F(edx, 20, NX)
F(edx, 22, MMXEXT)
F(edx, 23, RDTSCP)
F(edx, 25, FXSR_OPT)
F(edx, 26, GBPAGES)
F(edx, 27, RDTSCP)
F(edx, 29, LM)
F(edx, 30, 3DNOWEXT)
F(edx, 31, 3DNOW)
}
if (max_ext_func >= 0x80000004) {
uint32_t* p = (uint32_t*)cpu.model_name;
for (int i = 0; i < 3; ++i, p += 4)
cpuid(0x80000002 + i, p, p + 1, p + 2, p + 3);
}
if (max_ext_func >= 0x80000007) {
cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
if (edx & (1 << 8)) {
set_feature(X86_FEATURE_CONSTANT_TSC);
set_feature(X86_FEATURE_NONSTOP_TSC);
}
}
if (max_ext_func >= 0x80000008) {
cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
cpu.phys_addr_bits = eax & 0xff;
cpu.virt_addr_bits = (eax >> 8) & 0xff;
} else {
cpu.phys_addr_bits = cpu_has_feature(X86_FEATURE_PAE) ? 36 : 32;
cpu.virt_addr_bits = 32;
}
}

void cpu_init(void) {
detect_features();

if (cpu_has_feature(X86_FEATURE_PGE)) {
uint32_t cr4 = read_cr4();
cr4 |= 0x80; // PGE
write_cr4(cr4);
}

if (cpu_has_feature(X86_FEATURE_PAT)) {
uint64_t pat = rdmsr(0x277);
pat &= ~((uint64_t)0x7 << 32); // Clear PAT4
pat |= (uint64_t)1 << 32; // Set write-combining
wrmsr(0x277, pat);
}
}

struct cpu* cpu_get(void) { return &cpu; }

bool cpu_has_feature(int feature) {
return cpu.features[feature >> 5] & (1 << (feature & 31));
}
Loading

0 comments on commit c4ff122

Please sign in to comment.