--- /dev/null
+#ifndef ARCH_X86_CPUID_H
+#define ARCH_X86_CPUID_H
+
+#include <stdint.h>
+
+struct x86_cpu_features {
+ /* CPUID leaf 0 */
+ uint32_t max_leaf;
+ char vendor[13]; /* "GenuineIntel" / "AuthenticAMD" */
+
+ /* CPUID leaf 1 — ECX */
+ uint8_t sse3 : 1;
+ uint8_t ssse3 : 1;
+ uint8_t sse41 : 1;
+ uint8_t sse42 : 1;
+ uint8_t x2apic : 1;
+ uint8_t avx : 1;
+ uint8_t hypervisor : 1;
+
+ /* CPUID leaf 1 — EDX */
+ uint8_t fpu : 1;
+ uint8_t tsc : 1;
+ uint8_t msr : 1;
+ uint8_t pae : 1;
+ uint8_t cx8 : 1; /* CMPXCHG8B */
+ uint8_t apic : 1;
+ uint8_t sep : 1; /* SYSENTER/SYSEXIT */
+ uint8_t mtrr : 1;
+ uint8_t pge : 1; /* Page Global Enable */
+ uint8_t cmov : 1;
+ uint8_t pat : 1;
+ uint8_t pse36 : 1;
+ uint8_t mmx : 1;
+ uint8_t fxsr : 1; /* FXSAVE/FXRSTOR */
+ uint8_t sse : 1;
+ uint8_t sse2 : 1;
+ uint8_t htt : 1; /* Hyper-Threading */
+
+ /* CPUID leaf 0x80000001 — EDX */
+ uint8_t nx : 1; /* No-Execute (NX / XD) */
+ uint8_t lm : 1; /* Long Mode (64-bit) */
+ uint8_t syscall : 1; /* SYSCALL/SYSRET */
+
+ /* Extended info */
+ uint32_t max_ext_leaf;
+ char brand[49]; /* CPU brand string (leaves 0x80000002-4) */
+
+ /* Topology (from leaf 1 EBX) */
+ uint8_t initial_apic_id;
+ uint8_t logical_cpus; /* max logical CPUs per package */
+};
+
+/* Detect CPU features. Call once during early boot. */
+void x86_cpuid_detect(struct x86_cpu_features* out);
+
+/* Print detected features to UART. */
+void x86_cpuid_print(const struct x86_cpu_features* f);
+
+#endif
--- /dev/null
+#include "arch/x86/cpuid.h"
+#include "uart_console.h"
+#include "utils.h"
+
+#include <stddef.h>
+
+static inline void cpuid(uint32_t leaf, uint32_t* eax, uint32_t* ebx,
+ uint32_t* ecx, uint32_t* edx) {
+ __asm__ volatile("cpuid"
+ : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
+ : "a"(leaf), "c"(0));
+}
+
+void x86_cpuid_detect(struct x86_cpu_features* out) {
+ uint32_t eax, ebx, ecx, edx;
+
+ /* Zero everything */
+ for (size_t i = 0; i < sizeof(*out); i++)
+ ((uint8_t*)out)[i] = 0;
+
+ /* Leaf 0: vendor string + max standard leaf */
+ cpuid(0, &eax, &ebx, &ecx, &edx);
+ out->max_leaf = eax;
+
+ /* Vendor: EBX-EDX-ECX */
+ *(uint32_t*)&out->vendor[0] = ebx;
+ *(uint32_t*)&out->vendor[4] = edx;
+ *(uint32_t*)&out->vendor[8] = ecx;
+ out->vendor[12] = '\0';
+
+ if (out->max_leaf < 1) return;
+
+ /* Leaf 1: feature flags */
+ cpuid(1, &eax, &ebx, &ecx, &edx);
+
+ /* ECX features */
+ out->sse3 = (ecx >> 0) & 1;
+ out->ssse3 = (ecx >> 9) & 1;
+ out->sse41 = (ecx >> 19) & 1;
+ out->sse42 = (ecx >> 20) & 1;
+ out->x2apic = (ecx >> 21) & 1;
+ out->avx = (ecx >> 28) & 1;
+ out->hypervisor = (ecx >> 31) & 1;
+
+ /* EDX features */
+ out->fpu = (edx >> 0) & 1;
+ out->tsc = (edx >> 4) & 1;
+ out->msr = (edx >> 5) & 1;
+ out->pae = (edx >> 6) & 1;
+ out->cx8 = (edx >> 8) & 1;
+ out->apic = (edx >> 9) & 1;
+ out->sep = (edx >> 11) & 1;
+ out->mtrr = (edx >> 12) & 1;
+ out->pge = (edx >> 13) & 1;
+ out->cmov = (edx >> 15) & 1;
+ out->pat = (edx >> 16) & 1;
+ out->pse36 = (edx >> 17) & 1;
+ out->mmx = (edx >> 23) & 1;
+ out->fxsr = (edx >> 24) & 1;
+ out->sse = (edx >> 25) & 1;
+ out->sse2 = (edx >> 26) & 1;
+ out->htt = (edx >> 28) & 1;
+
+ /* Topology from EBX */
+ out->initial_apic_id = (uint8_t)(ebx >> 24);
+ out->logical_cpus = (uint8_t)(ebx >> 16);
+
+ /* Extended leaves */
+ cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
+ out->max_ext_leaf = eax;
+
+ if (out->max_ext_leaf >= 0x80000001) {
+ cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+ out->nx = (edx >> 20) & 1;
+ out->lm = (edx >> 29) & 1;
+ out->syscall = (edx >> 11) & 1;
+ }
+
+ /* Brand string (leaves 0x80000002 - 0x80000004) */
+ if (out->max_ext_leaf >= 0x80000004) {
+ uint32_t* b = (uint32_t*)out->brand;
+ for (uint32_t leaf = 0x80000002; leaf <= 0x80000004; leaf++) {
+ cpuid(leaf, &eax, &ebx, &ecx, &edx);
+ *b++ = eax;
+ *b++ = ebx;
+ *b++ = ecx;
+ *b++ = edx;
+ }
+ out->brand[48] = '\0';
+ }
+}
+
+void x86_cpuid_print(const struct x86_cpu_features* f) {
+ uart_print("[CPUID] Vendor: ");
+ uart_print(f->vendor);
+ uart_print("\n");
+
+ if (f->brand[0]) {
+ uart_print("[CPUID] Brand: ");
+ uart_print(f->brand);
+ uart_print("\n");
+ }
+
+ uart_print("[CPUID] Features:");
+ if (f->fpu) uart_print(" FPU");
+ if (f->tsc) uart_print(" TSC");
+ if (f->msr) uart_print(" MSR");
+ if (f->pae) uart_print(" PAE");
+ if (f->apic) uart_print(" APIC");
+ if (f->sep) uart_print(" SEP");
+ if (f->pge) uart_print(" PGE");
+ if (f->mmx) uart_print(" MMX");
+ if (f->fxsr) uart_print(" FXSR");
+ if (f->sse) uart_print(" SSE");
+ if (f->sse2) uart_print(" SSE2");
+ if (f->sse3) uart_print(" SSE3");
+ if (f->ssse3) uart_print(" SSSE3");
+ if (f->sse41) uart_print(" SSE4.1");
+ if (f->sse42) uart_print(" SSE4.2");
+ if (f->avx) uart_print(" AVX");
+ if (f->htt) uart_print(" HTT");
+ if (f->nx) uart_print(" NX");
+ if (f->lm) uart_print(" LM");
+ if (f->x2apic) uart_print(" x2APIC");
+ if (f->hypervisor) uart_print(" HYPERVISOR");
+ if (f->syscall) uart_print(" SYSCALL");
+ uart_print("\n");
+
+ uart_print("[CPUID] APIC ID: ");
+ char tmp[4];
+ itoa(f->initial_apic_id, tmp, 10);
+ uart_print(tmp);
+ uart_print(", Logical CPUs: ");
+ itoa(f->logical_cpus, tmp, 10);
+ uart_print(tmp);
+ uart_print("\n");
+}
--- /dev/null
+#include "hal/cpu_features.h"
+#include "arch/x86/cpuid.h"
+
+#include <stddef.h>
+
+static struct cpu_features g_features;
+static struct x86_cpu_features g_x86_features;
+
+void hal_cpu_detect_features(void) {
+ x86_cpuid_detect(&g_x86_features);
+
+ /* Copy to generic struct */
+ for (size_t i = 0; i < 12; i++)
+ g_features.vendor[i] = g_x86_features.vendor[i];
+ g_features.vendor[12] = '\0';
+
+ for (size_t i = 0; i < 48; i++)
+ g_features.brand[i] = g_x86_features.brand[i];
+ g_features.brand[48] = '\0';
+
+ g_features.has_apic = g_x86_features.apic;
+ g_features.has_x2apic = g_x86_features.x2apic;
+ g_features.has_pae = g_x86_features.pae;
+ g_features.has_nx = g_x86_features.nx;
+ g_features.has_sse = g_x86_features.sse;
+ g_features.has_sse2 = g_x86_features.sse2;
+ g_features.has_fxsr = g_x86_features.fxsr;
+ g_features.has_sysenter = g_x86_features.sep;
+ g_features.has_syscall = g_x86_features.syscall;
+ g_features.has_htt = g_x86_features.htt;
+ g_features.has_tsc = g_x86_features.tsc;
+ g_features.has_msr = g_x86_features.msr;
+ g_features.is_hypervisor = g_x86_features.hypervisor;
+
+ g_features.logical_cpus = g_x86_features.logical_cpus;
+ g_features.initial_cpu_id = g_x86_features.initial_apic_id;
+}
+
+const struct cpu_features* hal_cpu_get_features(void) {
+ return &g_features;
+}
+
+void hal_cpu_print_features(void) {
+ x86_cpuid_print(&g_x86_features);
+}