Viewing: cpu_features.c
📄 cpu_features.c (Read Only) ⬅ To go back
#include "hal/cpu_features.h"
#include "arch/x86/cpuid.h"
#include "console.h"

#include <stddef.h>

#define CR4_SMEP (1U << 20)
#define CR4_SMAP (1U << 21)

static inline uint32_t read_cr4(void) {
    uint32_t val;
    __asm__ volatile("mov %%cr4, %0" : "=r"(val));
    return val;
}

static inline void write_cr4(uint32_t val) {
    __asm__ volatile("mov %0, %%cr4" :: "r"(val) : "memory");
}

int g_smap_enabled = 0;

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;

    /* Enable SMEP if supported: prevents kernel from executing user-mapped pages.
     * This blocks a common exploit technique where an attacker maps shellcode in
     * userspace and tricks the kernel into jumping to it. */
    if (g_x86_features.smep) {
        uint32_t cr4 = read_cr4();
        cr4 |= CR4_SMEP;
        write_cr4(cr4);
        kprintf("[CPU] SMEP enabled.\n");
    }

    /* Enable SMAP if supported: prevents kernel from accidentally reading/writing
     * user-mapped pages.  copy_from_user/copy_to_user bracket accesses with
     * STAC/CLAC so legitimate user copies still work. */
    if (g_x86_features.smap) {
        uint32_t cr4 = read_cr4();
        cr4 |= CR4_SMAP;
        write_cr4(cr4);
        g_smap_enabled = 1;
        kprintf("[CPU] SMAP enabled.\n");
    }
}

const struct cpu_features* hal_cpu_get_features(void) {
    return &g_features;
}

void hal_cpu_print_features(void) {
    x86_cpuid_print(&g_x86_features);
}