1 /* 2 * Copyright 2005-2007, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "generic_x86.h" 11 #include "intel.h" 12 #include "amd.h" 13 #include "via.h" 14 15 #include <KernelExport.h> 16 #include <arch_system_info.h> 17 #include <arch/x86/arch_cpu.h> 18 19 20 //#define TRACE_MTRR 21 #ifdef TRACE_MTRR 22 # define TRACE(x) dprintf x 23 #else 24 # define TRACE(x) ; 25 #endif 26 27 28 #define IA32_MTRR_ENABLE (1UL << 11) 29 #define IA32_MTRR_ENABLE_FIXED (1UL << 10) 30 #define IA32_MTRR_VALID_RANGE (1UL << 11) 31 32 33 struct mtrr_capabilities { 34 mtrr_capabilities(uint64 value) { *(uint64 *)this = value; } 35 36 uint64 variable_ranges : 8; 37 uint64 supports_fixed : 1; 38 uint64 _reserved0 : 1; 39 uint64 supports_write_combined : 1; 40 uint64 _reserved1 : 53; 41 }; 42 43 44 uint64 gPhysicalMask = 0; 45 46 47 uint32 48 generic_count_mtrrs(void) 49 { 50 if (!x86_check_feature(IA32_FEATURE_MTRR, FEATURE_COMMON) 51 || !x86_check_feature(IA32_FEATURE_MSR, FEATURE_COMMON)) 52 return 0; 53 54 mtrr_capabilities capabilities(x86_read_msr(IA32_MSR_MTRR_CAPABILITIES)); 55 TRACE(("CPU has %u variable range MTRs.\n", (uint8)capabilities.variable_ranges)); 56 return capabilities.variable_ranges; 57 } 58 59 60 void 61 generic_init_mtrrs(uint32 count) 62 { 63 if (count == 0) 64 return; 65 66 // disable and clear all MTRRs 67 // (we leave the fixed MTRRs as is) 68 // TODO: check if the fixed MTRRs are set on all CPUs identically? 69 TRACE(("generic_init_mtrrs(count = %ld)\n", count)); 70 71 x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE, 72 x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & ~IA32_MTRR_ENABLE); 73 74 for (uint32 i = count; i-- > 0;) { 75 if (x86_read_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + i * 2) & IA32_MTRR_VALID_RANGE) 76 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + i * 2, 0); 77 } 78 79 // but turn on variable MTRR functionality 80 81 x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE, 82 x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) | IA32_MTRR_ENABLE); 83 } 84 85 86 void 87 generic_set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type) 88 { 89 index *= 2; 90 // there are two registers per slot 91 92 uint64 mask = length - 1; 93 mask = ~mask & gPhysicalMask; 94 95 TRACE(("MTRR %ld: new mask %Lx)\n", index, mask)); 96 TRACE((" mask test base: %Lx)\n", mask & base)); 97 TRACE((" mask test middle: %Lx)\n", mask & (base + length / 2))); 98 TRACE((" mask test end: %Lx)\n", mask & (base + length))); 99 100 // First, disable MTRR 101 102 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index, 0); 103 104 if (base != 0 || mask != 0 || type != 0) { 105 // then fill in the new values, and enable it again 106 107 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index, 108 (base & ~(B_PAGE_SIZE - 1)) | type); 109 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index, 110 mask | IA32_MTRR_VALID_RANGE); 111 } else { 112 // reset base as well 113 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index, 0); 114 } 115 } 116 117 118 status_t 119 generic_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, uint8 *_type) 120 { 121 uint64 mask = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index * 2); 122 if ((mask & IA32_MTRR_VALID_RANGE) == 0) 123 return B_ERROR; 124 125 uint64 base = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index * 2); 126 127 *_base = base & ~(B_PAGE_SIZE - 1); 128 *_length = (~mask & gPhysicalMask) + 1; 129 *_type = base & 0xff; 130 131 return B_OK; 132 } 133 134 135 status_t 136 generic_mtrr_compute_physical_mask(void) 137 { 138 uint32 bits = 36; 139 140 cpuid_info cpuInfo; 141 if (get_current_cpuid(&cpuInfo, 0x80000000) == B_OK 142 && (cpuInfo.eax_0.max_eax & 0xff) >= 8) { 143 get_current_cpuid(&cpuInfo, 0x80000008); 144 bits = cpuInfo.regs.eax & 0xff; 145 146 // Obviously, the bits are not always reported correctly 147 if (bits < 36) 148 bits = 36; 149 } 150 151 gPhysicalMask = ((1ULL << bits) - 1) & ~(B_PAGE_SIZE - 1); 152 153 TRACE(("CPU has %ld physical address bits, physical mask is %016Lx\n", 154 bits, gPhysicalMask)); 155 156 return B_OK; 157 } 158 159 160 void 161 generic_dump_mtrrs(uint32 count) 162 { 163 if (count == 0) 164 return; 165 166 if (x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) & IA32_MTRR_ENABLE) { 167 TRACE(("MTRR enabled\n")); 168 } else { 169 TRACE(("MTRR disabled\n")); 170 } 171 172 for (uint32 i = 0; i < count; i++) { 173 uint64 base; 174 uint64 length; 175 uint8 type; 176 if (generic_get_mtrr(i, &base, &length, &type) == B_OK) { 177 TRACE((" %ld: 0x%Lx, 0x%Lx, %u\n", i, base, length, type)); 178 } else { 179 TRACE((" %ld: empty\n", i)); 180 } 181 } 182 } 183 184 185 module_info *modules[] = { 186 (module_info *)&gIntelModule, 187 (module_info *)&gAMDModule, 188 (module_info *)&gVIAModule, 189 NULL 190 }; 191