From 2058e6c1d4c07696e8bb8cb59bbf96a27b5e1688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 16 Dec 2005 17:16:22 +0000 Subject: [PATCH] Refactored MTRR code a bit: there is now a generic base that is used by all CPU specific implementations as much as possible. AMD and Intel are now separated again, even though they are currently equivalent besides the CPU vendor detection. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15567 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/cpu/x86/Jamfile | 2 +- src/add-ons/kernel/cpu/x86/amd.cpp | 41 ++---- src/add-ons/kernel/cpu/x86/generic_x86.cpp | 158 +++++++++++++++++++- src/add-ons/kernel/cpu/x86/generic_x86.h | 34 +++++ src/add-ons/kernel/cpu/x86/intel.cpp | 164 ++------------------- src/add-ons/kernel/cpu/x86/via.cpp | 119 +-------------- 6 files changed, 223 insertions(+), 295 deletions(-) create mode 100644 src/add-ons/kernel/cpu/x86/generic_x86.h diff --git a/src/add-ons/kernel/cpu/x86/Jamfile b/src/add-ons/kernel/cpu/x86/Jamfile index 437acb6f75..52f6428182 100644 --- a/src/add-ons/kernel/cpu/x86/Jamfile +++ b/src/add-ons/kernel/cpu/x86/Jamfile @@ -4,7 +4,7 @@ UsePrivateHeaders kernel ; KernelAddon generic_x86 : kernel cpu : generic_x86.cpp + amd.cpp intel.cpp -# amd.cpp via.cpp ; diff --git a/src/add-ons/kernel/cpu/x86/amd.cpp b/src/add-ons/kernel/cpu/x86/amd.cpp index 2cf9ea95c9..3481afa306 100644 --- a/src/add-ons/kernel/cpu/x86/amd.cpp +++ b/src/add-ons/kernel/cpu/x86/amd.cpp @@ -8,26 +8,15 @@ #include "amd.h" +#include "generic_x86.h" + +#include -static uint32 -amd_count_mtrrs(void) +static void +amd_init_mtrrs(void) { - return 0; -} - - -static status_t -amd_set_mtrr(uint32 index, addr_t base, addr_t length, uint32 type) -{ - return B_OK; -} - - -static status_t -amd_unset_mtrr(uint32 index) -{ - return B_OK; + generic_init_mtrrs(generic_count_mtrrs()); } @@ -41,13 +30,9 @@ amd_init(void) if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_AMD_x86) return B_ERROR; - return B_OK; -} + generic_mtrr_compute_physical_mask(); + generic_dump_mtrrs(generic_count_mtrrs()); - -static status_t -amd_uninit(void) -{ return B_OK; } @@ -59,7 +44,7 @@ amd_stdops(int32 op, ...) case B_MODULE_INIT: return amd_init(); case B_MODULE_UNINIT: - return amd_uninit(); + return B_OK; } return B_ERROR; @@ -73,7 +58,9 @@ x86_cpu_module_info gAMDModule = { amd_stdops, }, - amd_count_mtrrs, - amd_set_mtrr, - amd_unset_mtrr, + generic_count_mtrrs, + amd_init_mtrrs, + + generic_set_mtrr, + generic_get_mtrr, }; diff --git a/src/add-ons/kernel/cpu/x86/generic_x86.cpp b/src/add-ons/kernel/cpu/x86/generic_x86.cpp index 8e62a3a391..1df3426d89 100644 --- a/src/add-ons/kernel/cpu/x86/generic_x86.cpp +++ b/src/add-ons/kernel/cpu/x86/generic_x86.cpp @@ -7,14 +7,170 @@ */ +#include "generic_x86.h" #include "intel.h" #include "amd.h" #include "via.h" +//#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) + + +struct mtrr_capabilities { + mtrr_capabilities(uint64 value) { *(uint64 *)this = value; } + + uint64 variable_ranges : 8; + uint64 supports_fixed : 1; + uint64 _reserved0 : 1; + uint64 supports_write_combined : 1; + uint64 _reserved1 : 53; +}; + + +uint64 gPhysicalMask = 0; + + +uint32 +generic_count_mtrrs(void) +{ + cpuid_info cpuInfo; + if (get_cpuid(&cpuInfo, 1, 0) != B_OK + || (cpuInfo.eax_1.features & IA32_FEATURE_MTRR) == 0) + return 0; + + mtrr_capabilities capabilities(x86_read_msr(IA32_MSR_MTRR_CAPABILITIES)); + TRACE(("cpu has %ld variable range MTRs.\n", capabilities.variable_ranges)); + return capabilities.variable_ranges; +} + + +void +generic_init_mtrrs(uint32 count) +{ + // 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 = count; 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); +} + + +void +generic_set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type) +{ + index *= 2; + // there are two registers per slot + + uint64 mask = length - 1; + mask = ~mask & gPhysicalMask; + + 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); + } +} + + +status_t +generic_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, uint8 *_type) +{ + 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 & gPhysicalMask) + 1; + *_type = base & 0xff; + + return B_OK; +} + + +status_t +generic_mtrr_compute_physical_mask(void) +{ + uint32 bits = 36; + + cpuid_info cpuInfo; + if (get_cpuid(&cpuInfo, 0x80000000, 0) == B_OK + && cpuInfo.eax_0.max_eax & 0xff >= 8) { + get_cpuid(&cpuInfo, 0x80000008, 0); + bits = cpuInfo.regs.eax & 0xff; + } + + gPhysicalMask = ((1ULL << bits) - 1) & ~(B_PAGE_SIZE - 1); + + TRACE(("CPU has %ld physical address bits, physical mask is %016Lx\n", + bits, gPhysicalMask)); + + return B_OK; +} + + +void +generic_dump_mtrrs(uint32 count) +{ + 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 < count; i++) { + uint64 base; + uint64 length; + uint8 type; + if (generic_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)); + } + } +} + + module_info *modules[] = { (module_info *)&gIntelModule, -// (module_info *)&gAMDModule, + (module_info *)&gAMDModule, (module_info *)&gVIAModule, NULL }; diff --git a/src/add-ons/kernel/cpu/x86/generic_x86.h b/src/add-ons/kernel/cpu/x86/generic_x86.h new file mode 100644 index 0000000000..7793e67ea4 --- /dev/null +++ b/src/add-ons/kernel/cpu/x86/generic_x86.h @@ -0,0 +1,34 @@ +/* + * Copyright 2005, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef CPU_GENERIC_x86_H +#define CPU_GENERIC_x86_H + + +#include + + +extern uint64 gPhysicalMask; + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32 generic_count_mtrrs(void); +extern void generic_init_mtrrs(uint32 count); +extern void generic_set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type); +extern status_t generic_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, + uint8 *_type); +extern status_t generic_mtrr_compute_physical_mask(void); + +extern void generic_dump_mtrrs(uint32 count); + +#ifdef __cplusplus +} +#endif + +#endif // CPU_GENERIC_x86_H diff --git a/src/add-ons/kernel/cpu/x86/intel.cpp b/src/add-ons/kernel/cpu/x86/intel.cpp index 61387d533c..8281ed2045 100644 --- a/src/add-ons/kernel/cpu/x86/intel.cpp +++ b/src/add-ons/kernel/cpu/x86/intel.cpp @@ -8,121 +8,15 @@ #include "intel.h" +#include "generic_x86.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) - - -struct mtrr_capabilities { - mtrr_capabilities(uint64 value) { *(uint64 *)this = value; } - - uint64 variable_ranges : 8; - uint64 supports_fixed : 1; - uint64 _reserved0 : 1; - uint64 supports_write_combined : 1; - uint64 _reserved1 : 53; -}; - - -static uint64 sPhysicalMask = 0; - - -static uint32 -intel_count_mtrrs(void) -{ - cpuid_info cpuInfo; - if (get_cpuid(&cpuInfo, 1, 0) != B_OK - || (cpuInfo.eax_1.features & IA32_FEATURE_MTRR) == 0) - return 0; - - mtrr_capabilities capabilities(x86_read_msr(IA32_MSR_MTRR_CAPABILITIES)); - TRACE(("cpu has %ld variable range MTRs.\n", capabilities.variable_ranges)); - return capabilities.variable_ranges; -} static void intel_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 = intel_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 -intel_set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type) -{ - index *= 2; - // there are two registers per slot - - uint64 mask = length - 1; - mask = ~mask & sPhysicalMask; - - 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 -intel_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, uint8 *_type) -{ - 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 & sPhysicalMask) + 1; - *_type = base & 0xff; - - return B_OK; + generic_init_mtrrs(generic_count_mtrrs()); } @@ -133,52 +27,12 @@ intel_init(void) if (get_system_info(&info) != B_OK) return B_ERROR; - if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_INTEL_x86 - && (info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_AMD_x86) + if ((info.cpu_type & B_CPU_x86_VENDOR_MASK) != B_CPU_INTEL_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")); - } + generic_mtrr_compute_physical_mask(); + generic_dump_mtrrs(generic_count_mtrrs()); - for (uint32 i = 0; i < intel_count_mtrrs(); i++) { - uint64 base; - uint64 length; - uint8 type; - if (intel_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 - - // get number of physical address bits - - uint32 bits = 36; - - cpuid_info cpuInfo; - if (get_cpuid(&cpuInfo, 0x80000000, 0) == B_OK - && cpuInfo.eax_0.max_eax & 0xff >= 8) { - get_cpuid(&cpuInfo, 0x80000008, 0); - bits = cpuInfo.regs.eax & 0xff; - } - - sPhysicalMask = ((1ULL << bits) - 1) & ~(B_PAGE_SIZE - 1); - - TRACE(("CPU has %ld physical address bits, physical mask is %016Lx\n", - bits, sPhysicalMask)); - - return B_OK; -} - - -static status_t -intel_uninit(void) -{ return B_OK; } @@ -190,7 +44,7 @@ intel_stdops(int32 op, ...) case B_MODULE_INIT: return intel_init(); case B_MODULE_UNINIT: - return intel_uninit(); + return B_OK; } return B_ERROR; @@ -204,9 +58,9 @@ x86_cpu_module_info gIntelModule = { intel_stdops, }, - intel_count_mtrrs, + generic_count_mtrrs, intel_init_mtrrs, - intel_set_mtrr, - intel_get_mtrr, + generic_set_mtrr, + generic_get_mtrr, }; diff --git a/src/add-ons/kernel/cpu/x86/via.cpp b/src/add-ons/kernel/cpu/x86/via.cpp index b20d10bb53..a4f5b6adc5 100644 --- a/src/add-ons/kernel/cpu/x86/via.cpp +++ b/src/add-ons/kernel/cpu/x86/via.cpp @@ -8,26 +8,9 @@ #include "via.h" +#include "generic_x86.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 @@ -46,71 +29,7 @@ via_count_mtrrs(void) 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_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, uint8 *_type) -{ - 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; - - return B_OK; + generic_init_mtrrs(via_count_mtrrs()); } @@ -124,32 +43,10 @@ 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")); - } + // current VIA CPUs have always 36 bit (or less?) + gPhysicalMask = ((1ULL << 36) - 1) & ~(B_PAGE_SIZE - 1); - 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; -} - - -static status_t -via_uninit(void) -{ + generic_dump_mtrrs(generic_count_mtrrs()); return B_OK; } @@ -161,7 +58,7 @@ via_stdops(int32 op, ...) case B_MODULE_INIT: return via_init(); case B_MODULE_UNINIT: - return via_uninit(); + return B_OK; } return B_ERROR; @@ -178,6 +75,6 @@ x86_cpu_module_info gVIAModule = { via_count_mtrrs, via_init_mtrrs, - via_set_mtrr, - via_get_mtrr, + generic_set_mtrr, + generic_get_mtrr, };