diff --git a/src/add-ons/kernel/cpu/x86/Jamfile b/src/add-ons/kernel/cpu/x86/Jamfile index 1aad1d564f..437acb6f75 100644 --- a/src/add-ons/kernel/cpu/x86/Jamfile +++ b/src/add-ons/kernel/cpu/x86/Jamfile @@ -6,5 +6,5 @@ KernelAddon generic_x86 : kernel cpu : generic_x86.cpp intel.cpp # amd.cpp -# via.cpp + via.cpp ; diff --git a/src/add-ons/kernel/cpu/x86/generic_x86.cpp b/src/add-ons/kernel/cpu/x86/generic_x86.cpp index d782d6a8ba..8e62a3a391 100644 --- a/src/add-ons/kernel/cpu/x86/generic_x86.cpp +++ b/src/add-ons/kernel/cpu/x86/generic_x86.cpp @@ -15,6 +15,6 @@ module_info *modules[] = { (module_info *)&gIntelModule, // (module_info *)&gAMDModule, -// (module_info *)&gVIAModule, + (module_info *)&gVIAModule, NULL }; diff --git a/src/add-ons/kernel/cpu/x86/intel.cpp b/src/add-ons/kernel/cpu/x86/intel.cpp index 9c6c095275..61387d533c 100644 --- a/src/add-ons/kernel/cpu/x86/intel.cpp +++ b/src/add-ons/kernel/cpu/x86/intel.cpp @@ -22,12 +22,10 @@ #endif -#define IA32_MTRR_FEATURE (1UL << 12) #define IA32_MTRR_ENABLE (1UL << 11) #define IA32_MTRR_ENABLE_FIXED (1UL << 10) #define IA32_MTRR_VALID_RANGE (1UL << 11) -#define MTRR_MASK (0xffffffff & (B_PAGE_SIZE - 1)) struct mtrr_capabilities { mtrr_capabilities(uint64 value) { *(uint64 *)this = value; } @@ -48,7 +46,7 @@ intel_count_mtrrs(void) { cpuid_info cpuInfo; if (get_cpuid(&cpuInfo, 1, 0) != B_OK - || (cpuInfo.eax_1.features & IA32_MTRR_FEATURE) == 0) + || (cpuInfo.eax_1.features & IA32_FEATURE_MTRR) == 0) return 0; mtrr_capabilities capabilities(x86_read_msr(IA32_MSR_MTRR_CAPABILITIES)); diff --git a/src/add-ons/kernel/cpu/x86/via.cpp b/src/add-ons/kernel/cpu/x86/via.cpp index ca81448a4d..b20d10bb53 100644 --- a/src/add-ons/kernel/cpu/x86/via.cpp +++ b/src/add-ons/kernel/cpu/x86/via.cpp @@ -9,24 +9,107 @@ #include "via.h" +#include +#include +#include + + +#define TRACE_MTRR +#ifdef TRACE_MTRR +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + +#define IA32_MTRR_ENABLE (1UL << 11) +#define IA32_MTRR_ENABLE_FIXED (1UL << 10) +#define IA32_MTRR_VALID_RANGE (1UL << 11) + + +static uint64 kPhysicalMask = ((1ULL << 36) - 1) & ~(B_PAGE_SIZE - 1);; + static uint32 via_count_mtrrs(void) { - return 0; + cpuid_info cpuInfo; + if (get_cpuid(&cpuInfo, 1, 0) != B_OK + || (cpuInfo.eax_1.features & IA32_FEATURE_MTRR) == 0) + return 0; + + // IA32_MSR_MTRR_CAPABILITIES doesn't exist on VIA CPUs + return 8; +} + + +static void +via_init_mtrrs(void) +{ + // disable and clear all MTRRs + // (we leave the fixed MTRRs as is) + // TODO: check if the fixed MTRRs are set on all CPUs identically? + + x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE, + x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & ~IA32_MTRR_ENABLE); + + for (uint32 i = via_count_mtrrs(); i-- > 0;) { + if (x86_read_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + i * 2) & IA32_MTRR_VALID_RANGE) + x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + i * 2, 0); + } + + // but turn on variable MTRR functionality + + x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE, + x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) | IA32_MTRR_ENABLE); +} + + +static void +via_set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type) +{ + index *= 2; + // there are two registers per slot + + uint64 mask = length - 1; + mask = ~mask & kPhysicalMask; + + TRACE(("MTRR %ld: new mask %Lx)\n", index, mask)); + TRACE((" mask test base: %Lx)\n", mask & base)); + TRACE((" mask test middle: %Lx)\n", mask & (base + length / 2))); + TRACE((" mask test end: %Lx)\n", mask & (base + length))); + + // First, disable MTRR + + x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index, 0); + + if (base != 0 || mask != 0 || type != 0) { + // then fill in the new values, and enable it again + + x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index, + (base & ~(B_PAGE_SIZE - 1)) | type); + x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index, + mask | IA32_MTRR_VALID_RANGE); + } else { + // reset base as well + x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index, 0); + } } static status_t -via_set_mtrr(uint32 index, addr_t base, addr_t length, uint32 type) +via_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, uint8 *_type) { - return B_OK; -} + uint64 mask = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index * 2); + if ((mask & IA32_MTRR_VALID_RANGE) == 0) + return B_ERROR; + uint64 base = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index * 2); + + *_base = base & ~(B_PAGE_SIZE - 1); + *_length = (~mask & kPhysicalMask) + 1; + *_type = base & 0xff; -static status_t -via_unset_mtrr(uint32 index) -{ return B_OK; } @@ -41,6 +124,25 @@ via_init(void) if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_VIA_IDT_x86) return B_ERROR; + if (x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & IA32_MTRR_ENABLE) { + TRACE(("MTRR enabled\n")); + } else { + TRACE(("MTRR disabled\n")); + } + + for (uint32 i = 0; i < via_count_mtrrs(); i++) { + uint64 base; + uint64 length; + uint8 type; + if (via_get_mtrr(i, &base, &length, &type) == B_OK) { + TRACE((" %ld: 0x%Lx, 0x%Lx, %u\n", i, base, length, type)); + } else { + TRACE((" %ld: empty\n", i)); + } + } + + // TODO: dump fixed ranges as well + return B_OK; } @@ -74,6 +176,8 @@ x86_cpu_module_info gVIAModule = { }, via_count_mtrrs, + via_init_mtrrs, + via_set_mtrr, - via_unset_mtrr, + via_get_mtrr, };