From: Tulio A M Mendes Date: Thu, 12 Feb 2026 04:09:08 +0000 (-0300) Subject: feat: MTRR write-combining support — mtrr_init/mtrr_set_range for variable-range... X-Git-Url: https://projects.tadryanom.me/docs/static/gitweb.css?a=commitdiff_plain;h=70b713540c9bd0ac7dab73817d783a32e7c37c0d;p=AdrOS.git feat: MTRR write-combining support — mtrr_init/mtrr_set_range for variable-range MTRR programming --- diff --git a/include/mtrr.h b/include/mtrr.h new file mode 100644 index 0000000..f8798f5 --- /dev/null +++ b/include/mtrr.h @@ -0,0 +1,15 @@ +#ifndef MTRR_H +#define MTRR_H + +#include + +#define MTRR_TYPE_UC 0 /* Uncacheable */ +#define MTRR_TYPE_WC 1 /* Write-Combining */ +#define MTRR_TYPE_WT 4 /* Write-Through */ +#define MTRR_TYPE_WP 5 /* Write-Protect */ +#define MTRR_TYPE_WB 6 /* Write-Back */ + +void mtrr_init(void); +int mtrr_set_range(uint64_t base, uint64_t size, uint8_t type); + +#endif diff --git a/src/arch/x86/mtrr.c b/src/arch/x86/mtrr.c new file mode 100644 index 0000000..0939151 --- /dev/null +++ b/src/arch/x86/mtrr.c @@ -0,0 +1,87 @@ +#include "mtrr.h" +#include "uart_console.h" + +#define IA32_MTRRCAP 0xFE +#define IA32_MTRR_DEF_TYPE 0x2FF +#define IA32_MTRR_PHYS_BASE(n) (0x200 + 2*(n)) +#define IA32_MTRR_PHYS_MASK(n) (0x201 + 2*(n)) + +static inline uint64_t rdmsr(uint32_t msr) { + uint32_t lo, 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 val) { + __asm__ volatile("wrmsr" : : "c"(msr), "a"((uint32_t)val), "d"((uint32_t)(val >> 32))); +} + +static uint8_t mtrr_count = 0; +static uint8_t mtrr_enabled = 0; + +void mtrr_init(void) { + uint32_t eax, edx; + __asm__ volatile("cpuid" : "=a"(eax) : "a"(1) : "ebx", "ecx", "edx"); + /* Check MTRR support: CPUID.1:EDX bit 12 */ + __asm__ volatile("cpuid" : "=a"(eax), "=d"(edx) : "a"(1) : "ebx", "ecx"); + if (!(edx & (1U << 12))) { + uart_print("[MTRR] Not supported by CPU\n"); + return; + } + + uint64_t cap = rdmsr(IA32_MTRRCAP); + mtrr_count = (uint8_t)(cap & 0xFF); + if (mtrr_count == 0) { + uart_print("[MTRR] No variable-range MTRRs available\n"); + return; + } + + mtrr_enabled = 1; + uart_print("[MTRR] Initialized, "); + /* Simple decimal print for count */ + char buf[4]; + buf[0] = (char)('0' + mtrr_count / 10); + buf[1] = (char)('0' + mtrr_count % 10); + buf[2] = '\0'; + uart_print(buf); + uart_print(" variable-range registers\n"); +} + +int mtrr_set_range(uint64_t base, uint64_t size, uint8_t type) { + if (!mtrr_enabled) return -1; + if (size == 0) return -1; + /* Size must be a power of 2 and base must be aligned to size */ + if (size & (size - 1)) return -1; + if (base & (size - 1)) return -1; + + /* Find a free variable-range MTRR register */ + int slot = -1; + for (int i = 0; i < mtrr_count; i++) { + uint64_t mask = rdmsr(IA32_MTRR_PHYS_MASK(i)); + if (!(mask & (1ULL << 11))) { /* Valid bit not set = free */ + slot = i; + break; + } + } + if (slot < 0) return -1; /* No free MTRR slots */ + + /* 36-bit physical address mask (common for 32-bit x86) */ + uint64_t addr_mask = 0x0000000FFFFFFFFFULL; + uint64_t phys_mask = (~(size - 1)) & addr_mask; + + /* Disable interrupts during MTRR programming */ + __asm__ volatile("cli"); + + /* Flush caches */ + __asm__ volatile("wbinvd"); + + wrmsr(IA32_MTRR_PHYS_BASE(slot), (base & addr_mask) | type); + wrmsr(IA32_MTRR_PHYS_MASK(slot), phys_mask | (1ULL << 11)); /* Set valid bit */ + + /* Flush caches again */ + __asm__ volatile("wbinvd"); + + __asm__ volatile("sti"); + + return 0; +}