1 /* 2 * Copyright 2005-2009, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Ingo Weinhold, ingo_weinhold@gmx.de 8 */ 9 10 11 #include "generic_x86.h" 12 #include "intel.h" 13 #include "amd.h" 14 #include "via.h" 15 16 #include <KernelExport.h> 17 #include <arch_system_info.h> 18 #include <arch/x86/arch_cpu.h> 19 #include <smp.h> 20 21 22 //#define TRACE_MTRR 23 #ifdef TRACE_MTRR 24 # define TRACE(x...) dprintf("mtrr: " x) 25 #else 26 # define TRACE(x...) /* nothing */ 27 #endif 28 29 30 #define IA32_MTRR_ENABLE (1UL << 11) 31 #define IA32_MTRR_ENABLE_FIXED (1UL << 10) 32 #define IA32_MTRR_VALID_RANGE (1UL << 11) 33 34 35 struct mtrr_capabilities { 36 mtrr_capabilities(uint64 value) { *(uint64 *)this = value; } 37 38 uint64 variable_ranges : 8; 39 uint64 supports_fixed : 1; 40 uint64 _reserved0 : 1; 41 uint64 supports_write_combined : 1; 42 uint64 _reserved1 : 53; 43 }; 44 45 46 uint64 gPhysicalMask = 0; 47 48 49 #ifdef TRACE_MTRR 50 static const char * 51 mtrr_type_to_string(uint8 type) 52 { 53 switch (type) { 54 case 0: 55 return "uncacheable"; 56 case 1: 57 return "write combining"; 58 case 4: 59 return "write-through"; 60 case 5: 61 return "write-protected"; 62 case 6: 63 return "write-back"; 64 default: 65 return "reserved"; 66 } 67 } 68 #endif // TRACE_MTRR 69 70 71 static void 72 set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type) 73 { 74 uint64 mask = length - 1; 75 mask = ~mask & gPhysicalMask; 76 77 TRACE("MTRR %lu: new mask %Lx\n", index, mask); 78 TRACE(" mask test base: %Lx\n", mask & base); 79 TRACE(" mask test middle: %Lx\n", mask & (base + length / 2)); 80 TRACE(" mask test end: %Lx\n", mask & (base + length)); 81 82 index *= 2; 83 // there are two registers per slot 84 85 // First, disable MTRR 86 87 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index, 0); 88 89 if (base != 0 || mask != 0 || type != 0) { 90 // then fill in the new values, and enable it again 91 92 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index, 93 (base & ~(B_PAGE_SIZE - 1)) | type); 94 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index, 95 mask | IA32_MTRR_VALID_RANGE); 96 } else { 97 // reset base as well 98 x86_write_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index, 0); 99 } 100 } 101 102 103 // #pragma mark - 104 105 106 uint32 107 generic_count_mtrrs(void) 108 { 109 if (!x86_check_feature(IA32_FEATURE_MTRR, FEATURE_COMMON) 110 || !x86_check_feature(IA32_FEATURE_MSR, FEATURE_COMMON)) 111 return 0; 112 113 mtrr_capabilities capabilities(x86_read_msr(IA32_MSR_MTRR_CAPABILITIES)); 114 TRACE("CPU %ld has %u variable range MTRRs.\n", smp_get_current_cpu(), 115 (uint8)capabilities.variable_ranges); 116 return capabilities.variable_ranges; 117 } 118 119 120 void 121 generic_init_mtrrs(uint32 count) 122 { 123 if (count == 0) 124 return; 125 126 // If MTRRs are enabled, we leave everything as is (save for, possibly, the 127 // default, which we set below), so that we can benefit from the BIOS's 128 // setup until we've installed our own. If MTRRs are disabled, we clear 129 // all registers and enable MTRRs. 130 // (we leave the fixed MTRRs as is) 131 // TODO: check if the fixed MTRRs are set on all CPUs identically? 132 TRACE("generic_init_mtrrs(count = %ld)\n", count); 133 134 uint64 defaultType = x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE); 135 if ((defaultType & IA32_MTRR_ENABLE) == 0) { 136 for (uint32 i = 0; i < count; i++) 137 set_mtrr(i, 0, 0, 0); 138 } 139 140 // Turn on variable MTRR functionality. 141 // We need to ensure that the default type is uncacheable, otherwise 142 // clearing the mtrrs could result in ranges that aren't supposed to be 143 // cacheable to become cacheable due to the default type. 144 x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE, 145 (defaultType & ~0xff) | IA32_MTRR_ENABLE); 146 } 147 148 149 void 150 generic_set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type) 151 { 152 set_mtrr(index, base, length, type); 153 TRACE("[cpu %ld] mtrrs now:\n", smp_get_current_cpu()); 154 generic_dump_mtrrs(generic_count_mtrrs()); 155 } 156 157 158 status_t 159 generic_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, uint8 *_type) 160 { 161 uint64 mask = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_MASK_0 + index * 2); 162 if ((mask & IA32_MTRR_VALID_RANGE) == 0) 163 return B_ERROR; 164 165 uint64 base = x86_read_msr(IA32_MSR_MTRR_PHYSICAL_BASE_0 + index * 2); 166 167 *_base = base & ~(B_PAGE_SIZE - 1); 168 *_length = (~mask & gPhysicalMask) + B_PAGE_SIZE; 169 *_type = base & 0xff; 170 171 return B_OK; 172 } 173 174 175 void 176 generic_set_mtrrs(uint8 newDefaultType, const x86_mtrr_info* infos, 177 uint32 count, uint32 maxCount) 178 { 179 // check count 180 if (maxCount == 0) 181 return; 182 183 if (count > maxCount) 184 count = maxCount; 185 186 // disable MTTRs 187 uint64 defaultType = x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE) 188 & ~IA32_MTRR_ENABLE; 189 x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE, defaultType); 190 191 // set the given MTRRs 192 for (uint32 i = 0; i < count; i++) 193 set_mtrr(i, infos[i].base, infos[i].size, infos[i].type); 194 195 // clear the other MTRRs 196 for (uint32 i = count; i < maxCount; i++) 197 set_mtrr(i, 0, 0, 0); 198 199 // re-enable MTTRs and set the new default type 200 defaultType = (defaultType & ~(uint64)0xff) | newDefaultType; 201 x86_write_msr(IA32_MSR_MTRR_DEFAULT_TYPE, defaultType | IA32_MTRR_ENABLE); 202 } 203 204 205 status_t 206 generic_mtrr_compute_physical_mask(void) 207 { 208 uint32 bits = 36; 209 210 cpuid_info cpuInfo; 211 if (get_current_cpuid(&cpuInfo, 0x80000000, 0) == B_OK 212 && (cpuInfo.eax_0.max_eax & 0xff) >= 8) { 213 get_current_cpuid(&cpuInfo, 0x80000008, 0); 214 bits = cpuInfo.regs.eax & 0xff; 215 216 // Obviously, the bits are not always reported correctly 217 if (bits < 36) 218 bits = 36; 219 } 220 221 gPhysicalMask = ((1ULL << bits) - 1) & ~(B_PAGE_SIZE - 1); 222 223 TRACE("CPU %ld has %ld physical address bits, physical mask is %016Lx\n", 224 smp_get_current_cpu(), bits, gPhysicalMask); 225 226 return B_OK; 227 } 228 229 230 void 231 generic_dump_mtrrs(uint32 count) 232 { 233 #ifdef TRACE_MTRR 234 if (count == 0) 235 return; 236 237 int cpu = smp_get_current_cpu(); 238 uint64 defaultType = x86_read_msr(IA32_MSR_MTRR_DEFAULT_TYPE); 239 TRACE("[cpu %d] MTRRs are %sabled\n", cpu, 240 (defaultType & IA32_MTRR_ENABLE) != 0 ? "en" : "dis"); 241 TRACE("[cpu %d] default type is %u %s\n", cpu, 242 (uint8)defaultType, mtrr_type_to_string(defaultType)); 243 TRACE("[cpu %d] fixed range MTRRs are %sabled\n", cpu, 244 (defaultType & IA32_MTRR_ENABLE_FIXED) != 0 ? "en" : "dis"); 245 246 for (uint32 i = 0; i < count; i++) { 247 uint64 base; 248 uint64 length; 249 uint8 type; 250 if (generic_get_mtrr(i, &base, &length, &type) == B_OK) { 251 TRACE("[cpu %d] %lu: base: 0x%Lx; length: 0x%Lx; type: %u %s\n", 252 cpu, i, base, length, type, mtrr_type_to_string(type)); 253 } else 254 TRACE("[cpu %d] %lu: empty\n", cpu, i); 255 } 256 #endif // TRACE_MTRR 257 } 258 259 260 module_info *modules[] = { 261 (module_info *)&gIntelModule, 262 (module_info *)&gAMDModule, 263 (module_info *)&gVIAModule, 264 NULL 265 }; 266