1393fceb5SAxel Dörfler /* 2bb163c02SIngo Weinhold * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3b20d05b4SJérôme Duval * Copyright 2008, Jérôme Duval. 4bb163c02SIngo Weinhold * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. 5393fceb5SAxel Dörfler * Distributed under the terms of the MIT License. 6393fceb5SAxel Dörfler * 7393fceb5SAxel Dörfler * Copyright 2001, Travis Geiselbrecht. All rights reserved. 8393fceb5SAxel Dörfler * Distributed under the terms of the NewOS License. 9393fceb5SAxel Dörfler */ 10393fceb5SAxel Dörfler 11393fceb5SAxel Dörfler 1274785e79SIngo Weinhold #include <stdlib.h> 1374785e79SIngo Weinhold #include <string.h> 1474785e79SIngo Weinhold 15393fceb5SAxel Dörfler #include <KernelExport.h> 1674785e79SIngo Weinhold 17393fceb5SAxel Dörfler #include <smp.h> 18393fceb5SAxel Dörfler #include <util/AutoLock.h> 19393fceb5SAxel Dörfler #include <vm.h> 2074785e79SIngo Weinhold #include <vm_address_space.h> 21393fceb5SAxel Dörfler #include <vm_page.h> 22393fceb5SAxel Dörfler #include <vm_priv.h> 23393fceb5SAxel Dörfler 24393fceb5SAxel Dörfler #include <arch/vm.h> 25393fceb5SAxel Dörfler #include <arch/int.h> 26393fceb5SAxel Dörfler #include <arch/cpu.h> 27393fceb5SAxel Dörfler 28393fceb5SAxel Dörfler #include <arch/x86/bios.h> 29393fceb5SAxel Dörfler 3047c40a10SIngo Weinhold #include "x86_paging.h" 3147c40a10SIngo Weinhold 32393fceb5SAxel Dörfler 33393fceb5SAxel Dörfler //#define TRACE_ARCH_VM 34393fceb5SAxel Dörfler #ifdef TRACE_ARCH_VM 35393fceb5SAxel Dörfler # define TRACE(x) dprintf x 36393fceb5SAxel Dörfler #else 37393fceb5SAxel Dörfler # define TRACE(x) ; 38393fceb5SAxel Dörfler #endif 39393fceb5SAxel Dörfler 404f893e39SJérôme Duval #define TRACE_MTRR_ARCH_VM 414f893e39SJérôme Duval #ifdef TRACE_MTRR_ARCH_VM 424f893e39SJérôme Duval # define TRACE_MTRR(x...) dprintf(x) 434f893e39SJérôme Duval #else 444f893e39SJérôme Duval # define TRACE_MTRR(x...) 454f893e39SJérôme Duval #endif 464f893e39SJérôme Duval 47393fceb5SAxel Dörfler 48bb163c02SIngo Weinhold static const uint32 kMaxMemoryTypeRanges = 32; 49bb163c02SIngo Weinhold static const uint32 kMaxMemoryTypeRegisters = 32; 50bb163c02SIngo Weinhold static const uint64 kMinMemoryTypeRangeSize = 1 << 12; 51bb163c02SIngo Weinhold 52bb163c02SIngo Weinhold 53bb163c02SIngo Weinhold struct memory_type_range_analysis_info { 54bb163c02SIngo Weinhold uint64 size; 55bb163c02SIngo Weinhold uint32 rangesNeeded; 56bb163c02SIngo Weinhold uint32 subtractiveRangesNeeded; 57bb163c02SIngo Weinhold uint64 bestSubtractiveRange; 58bb163c02SIngo Weinhold }; 59bb163c02SIngo Weinhold 60bb163c02SIngo Weinhold struct memory_type_range_analysis { 61bb163c02SIngo Weinhold uint64 base; 62bb163c02SIngo Weinhold uint64 size; 63bb163c02SIngo Weinhold uint32 type; 64bb163c02SIngo Weinhold uint32 rangesNeeded; 65bb163c02SIngo Weinhold uint64 endRange; 66bb163c02SIngo Weinhold memory_type_range_analysis_info left; 67bb163c02SIngo Weinhold memory_type_range_analysis_info right; 68bb163c02SIngo Weinhold }; 69bb163c02SIngo Weinhold 70bb163c02SIngo Weinhold struct memory_type_range { 71bb163c02SIngo Weinhold uint64 base; 72bb163c02SIngo Weinhold uint64 size; 73bb163c02SIngo Weinhold uint32 type; 74bb163c02SIngo Weinhold area_id area; 75bb163c02SIngo Weinhold }; 76bb163c02SIngo Weinhold 77393fceb5SAxel Dörfler 78393fceb5SAxel Dörfler void *gDmaAddress; 79393fceb5SAxel Dörfler 80bb163c02SIngo Weinhold static memory_type_range sMemoryTypeRanges[kMaxMemoryTypeRanges]; 81bb163c02SIngo Weinhold static uint32 sMemoryTypeRangeCount; 82bb163c02SIngo Weinhold 83bb163c02SIngo Weinhold static memory_type_range_analysis sMemoryTypeRangeAnalysis[ 84bb163c02SIngo Weinhold kMaxMemoryTypeRanges]; 85bb163c02SIngo Weinhold 86bb163c02SIngo Weinhold static x86_mtrr_info sMemoryTypeRegisters[kMaxMemoryTypeRegisters]; 87393fceb5SAxel Dörfler static uint32 sMemoryTypeRegisterCount; 88bb163c02SIngo Weinhold static uint32 sMemoryTypeRegistersUsed; 89bb163c02SIngo Weinhold 90bb163c02SIngo Weinhold static mutex sMemoryTypeLock = MUTEX_INITIALIZER("memory type ranges"); 91393fceb5SAxel Dörfler 92393fceb5SAxel Dörfler 93bb163c02SIngo Weinhold static void 94bb163c02SIngo Weinhold set_mtrrs() 95393fceb5SAxel Dörfler { 96bb163c02SIngo Weinhold x86_set_mtrrs(sMemoryTypeRegisters, sMemoryTypeRegistersUsed); 97393fceb5SAxel Dörfler 98bb163c02SIngo Weinhold #ifdef TRACE_MTRR_ARCH_VM 99bb163c02SIngo Weinhold TRACE_MTRR("set MTRRs to:\n"); 100bb163c02SIngo Weinhold for (uint32 i = 0; i < sMemoryTypeRegistersUsed; i++) { 101bb163c02SIngo Weinhold const x86_mtrr_info& info = sMemoryTypeRegisters[i]; 102bb163c02SIngo Weinhold TRACE_MTRR(" mtrr: %2lu: base: %#9llx, size: %#9llx, type: %u\n", 103bb163c02SIngo Weinhold i, info.base, info.size, info.type); 104393fceb5SAxel Dörfler } 105bb163c02SIngo Weinhold #endif 106393fceb5SAxel Dörfler } 107393fceb5SAxel Dörfler 108393fceb5SAxel Dörfler 109393fceb5SAxel Dörfler static void 110bb163c02SIngo Weinhold add_used_mtrr(uint64 base, uint64 size, uint32 type) 111393fceb5SAxel Dörfler { 112bb163c02SIngo Weinhold ASSERT(sMemoryTypeRegistersUsed < sMemoryTypeRegisterCount); 113393fceb5SAxel Dörfler 114bb163c02SIngo Weinhold x86_mtrr_info& info = sMemoryTypeRegisters[sMemoryTypeRegistersUsed++]; 115bb163c02SIngo Weinhold info.base = base; 116bb163c02SIngo Weinhold info.size = size; 117bb163c02SIngo Weinhold info.type = type; 118393fceb5SAxel Dörfler } 119393fceb5SAxel Dörfler 120393fceb5SAxel Dörfler 1214f893e39SJérôme Duval static void 122bb163c02SIngo Weinhold analyze_range(memory_type_range_analysis& analysis, uint64 previousEnd, 123bb163c02SIngo Weinhold uint64 nextBase) 1244f893e39SJérôme Duval { 125bb163c02SIngo Weinhold uint64 base = analysis.base; 126bb163c02SIngo Weinhold uint64 size = analysis.size; 1274f893e39SJérôme Duval 128bb163c02SIngo Weinhold memory_type_range_analysis_info& left = analysis.left; 129bb163c02SIngo Weinhold memory_type_range_analysis_info& right = analysis.right; 130bb163c02SIngo Weinhold 131bb163c02SIngo Weinhold uint32 leftSubtractiveRangesNeeded = 2; 132bb163c02SIngo Weinhold int32 leftBestSubtractiveRangeDifference = 0; 133bb163c02SIngo Weinhold uint32 leftBestSubtractivePositiveRangesNeeded = 0; 134bb163c02SIngo Weinhold uint32 leftBestSubtractiveRangesNeeded = 0; 135bb163c02SIngo Weinhold 136bb163c02SIngo Weinhold uint32 rightSubtractiveRangesNeeded = 2; 137bb163c02SIngo Weinhold int32 rightBestSubtractiveRangeDifference = 0; 138bb163c02SIngo Weinhold uint32 rightBestSubtractivePositiveRangesNeeded = 0; 139bb163c02SIngo Weinhold uint32 rightBestSubtractiveRangesNeeded = 0; 140bb163c02SIngo Weinhold 141bb163c02SIngo Weinhold uint64 range = kMinMemoryTypeRangeSize; 142bb163c02SIngo Weinhold 143bb163c02SIngo Weinhold while (size > 0) { 144bb163c02SIngo Weinhold if ((base & range) != 0) { 145bb163c02SIngo Weinhold left.rangesNeeded++; 146bb163c02SIngo Weinhold 147bb163c02SIngo Weinhold bool replaceBestSubtractive = false; 148bb163c02SIngo Weinhold int32 rangeDifference = (int32)left.rangesNeeded 149bb163c02SIngo Weinhold - (int32)leftSubtractiveRangesNeeded; 150bb163c02SIngo Weinhold if (left.bestSubtractiveRange == 0 151bb163c02SIngo Weinhold || leftBestSubtractiveRangeDifference < rangeDifference) { 152bb163c02SIngo Weinhold // check for intersection with previous range 153bb163c02SIngo Weinhold replaceBestSubtractive 154bb163c02SIngo Weinhold = previousEnd == 0 || base - range >= previousEnd; 1554f893e39SJérôme Duval } 1564f893e39SJérôme Duval 157bb163c02SIngo Weinhold if (replaceBestSubtractive) { 158bb163c02SIngo Weinhold leftBestSubtractiveRangeDifference = rangeDifference; 159bb163c02SIngo Weinhold leftBestSubtractiveRangesNeeded 160bb163c02SIngo Weinhold = leftSubtractiveRangesNeeded; 161bb163c02SIngo Weinhold left.bestSubtractiveRange = range; 162bb163c02SIngo Weinhold leftBestSubtractivePositiveRangesNeeded = 0; 163bb163c02SIngo Weinhold } else 164bb163c02SIngo Weinhold leftBestSubtractivePositiveRangesNeeded++; 165bb163c02SIngo Weinhold 166bb163c02SIngo Weinhold left.size += range; 167bb163c02SIngo Weinhold base += range; 168bb163c02SIngo Weinhold size -= range; 169bb163c02SIngo Weinhold } else if (left.bestSubtractiveRange > 0) 170bb163c02SIngo Weinhold leftSubtractiveRangesNeeded++; 171bb163c02SIngo Weinhold 172bb163c02SIngo Weinhold if ((size & range) != 0) { 173bb163c02SIngo Weinhold right.rangesNeeded++; 174bb163c02SIngo Weinhold 175bb163c02SIngo Weinhold bool replaceBestSubtractive = false; 176bb163c02SIngo Weinhold int32 rangeDifference = (int32)right.rangesNeeded 177bb163c02SIngo Weinhold - (int32)rightSubtractiveRangesNeeded; 178bb163c02SIngo Weinhold if (right.bestSubtractiveRange == 0 179bb163c02SIngo Weinhold || rightBestSubtractiveRangeDifference < rangeDifference) { 180bb163c02SIngo Weinhold // check for intersection with previous range 181bb163c02SIngo Weinhold replaceBestSubtractive 182bb163c02SIngo Weinhold = nextBase == 0 || base + size + range <= nextBase; 183bb163c02SIngo Weinhold } 184bb163c02SIngo Weinhold 185bb163c02SIngo Weinhold if (replaceBestSubtractive) { 186bb163c02SIngo Weinhold rightBestSubtractiveRangeDifference = rangeDifference; 187bb163c02SIngo Weinhold rightBestSubtractiveRangesNeeded 188bb163c02SIngo Weinhold = rightSubtractiveRangesNeeded; 189bb163c02SIngo Weinhold right.bestSubtractiveRange = range; 190bb163c02SIngo Weinhold rightBestSubtractivePositiveRangesNeeded = 0; 191bb163c02SIngo Weinhold } else 192bb163c02SIngo Weinhold rightBestSubtractivePositiveRangesNeeded++; 193bb163c02SIngo Weinhold 194bb163c02SIngo Weinhold right.size += range; 195bb163c02SIngo Weinhold size -= range; 196bb163c02SIngo Weinhold } else if (right.bestSubtractiveRange > 0) 197bb163c02SIngo Weinhold rightSubtractiveRangesNeeded++; 198bb163c02SIngo Weinhold 199bb163c02SIngo Weinhold range <<= 1; 200bb163c02SIngo Weinhold } 201bb163c02SIngo Weinhold 202bb163c02SIngo Weinhold analysis.endRange = range; 203bb163c02SIngo Weinhold 204bb163c02SIngo Weinhold // If a subtractive setup doesn't have any advantages, don't use it. 205bb163c02SIngo Weinhold // Also compute analysis.rangesNeeded. 206bb163c02SIngo Weinhold if (leftBestSubtractiveRangesNeeded 207bb163c02SIngo Weinhold + leftBestSubtractivePositiveRangesNeeded >= left.rangesNeeded) { 208bb163c02SIngo Weinhold left.bestSubtractiveRange = 0; 209bb163c02SIngo Weinhold left.subtractiveRangesNeeded = 0; 210bb163c02SIngo Weinhold analysis.rangesNeeded = left.rangesNeeded; 211bb163c02SIngo Weinhold } else { 212bb163c02SIngo Weinhold left.subtractiveRangesNeeded = leftBestSubtractiveRangesNeeded 213bb163c02SIngo Weinhold + leftBestSubtractivePositiveRangesNeeded; 214bb163c02SIngo Weinhold analysis.rangesNeeded = left.subtractiveRangesNeeded; 215bb163c02SIngo Weinhold } 216bb163c02SIngo Weinhold 217bb163c02SIngo Weinhold if (rightBestSubtractiveRangesNeeded 218bb163c02SIngo Weinhold + rightBestSubtractivePositiveRangesNeeded >= right.rangesNeeded) { 219bb163c02SIngo Weinhold right.bestSubtractiveRange = 0; 220bb163c02SIngo Weinhold right.subtractiveRangesNeeded = 0; 221bb163c02SIngo Weinhold analysis.rangesNeeded += right.rangesNeeded; 222bb163c02SIngo Weinhold } else { 223bb163c02SIngo Weinhold right.subtractiveRangesNeeded = rightBestSubtractiveRangesNeeded 224bb163c02SIngo Weinhold + rightBestSubtractivePositiveRangesNeeded; 225bb163c02SIngo Weinhold analysis.rangesNeeded += right.subtractiveRangesNeeded; 226bb163c02SIngo Weinhold } 227bb163c02SIngo Weinhold } 228bb163c02SIngo Weinhold 229bb163c02SIngo Weinhold static void 230bb163c02SIngo Weinhold compute_mtrrs(const memory_type_range_analysis& analysis) 231bb163c02SIngo Weinhold { 232bb163c02SIngo Weinhold const memory_type_range_analysis_info& left = analysis.left; 233bb163c02SIngo Weinhold const memory_type_range_analysis_info& right = analysis.right; 234bb163c02SIngo Weinhold 235bb163c02SIngo Weinhold // generate a setup for the left side 236bb163c02SIngo Weinhold if (left.rangesNeeded > 0) { 237bb163c02SIngo Weinhold uint64 base = analysis.base; 238bb163c02SIngo Weinhold uint64 size = left.size; 239bb163c02SIngo Weinhold uint64 range = analysis.endRange; 240bb163c02SIngo Weinhold uint64 rangeEnd = base + size; 241bb163c02SIngo Weinhold bool subtractive = false; 242bb163c02SIngo Weinhold while (size > 0) { 243bb163c02SIngo Weinhold if (range == left.bestSubtractiveRange) { 244bb163c02SIngo Weinhold base = rangeEnd - 2 * range; 245bb163c02SIngo Weinhold add_used_mtrr(base, range, analysis.type); 246bb163c02SIngo Weinhold subtractive = true; 247bb163c02SIngo Weinhold break; 248bb163c02SIngo Weinhold } 249bb163c02SIngo Weinhold 250bb163c02SIngo Weinhold if ((size & range) != 0) { 251bb163c02SIngo Weinhold rangeEnd -= range; 252bb163c02SIngo Weinhold add_used_mtrr(rangeEnd, range, analysis.type); 253bb163c02SIngo Weinhold size -= range; 254bb163c02SIngo Weinhold } 255bb163c02SIngo Weinhold 256bb163c02SIngo Weinhold range >>= 1; 257bb163c02SIngo Weinhold } 258bb163c02SIngo Weinhold 259bb163c02SIngo Weinhold if (subtractive) { 260bb163c02SIngo Weinhold uint64 shortestRange = range; 261bb163c02SIngo Weinhold while (size > 0) { 262bb163c02SIngo Weinhold if ((size & range) != 0) { 263bb163c02SIngo Weinhold shortestRange = range; 264bb163c02SIngo Weinhold size -= range; 265bb163c02SIngo Weinhold } else { 266bb163c02SIngo Weinhold add_used_mtrr(base, range, IA32_MTR_UNCACHED); 267bb163c02SIngo Weinhold base += range; 268bb163c02SIngo Weinhold } 269bb163c02SIngo Weinhold 270bb163c02SIngo Weinhold range >>= 1; 271bb163c02SIngo Weinhold } 272bb163c02SIngo Weinhold 273bb163c02SIngo Weinhold add_used_mtrr(base, shortestRange, IA32_MTR_UNCACHED); 274bb163c02SIngo Weinhold } 275bb163c02SIngo Weinhold } 276bb163c02SIngo Weinhold 277bb163c02SIngo Weinhold // generate a setup for the right side 278bb163c02SIngo Weinhold if (right.rangesNeeded > 0) { 279bb163c02SIngo Weinhold uint64 base = analysis.base + left.size; 280bb163c02SIngo Weinhold uint64 size = right.size; 281bb163c02SIngo Weinhold uint64 range = analysis.endRange; 282bb163c02SIngo Weinhold bool subtractive = false; 283bb163c02SIngo Weinhold while (size > 0) { 284bb163c02SIngo Weinhold if (range == right.bestSubtractiveRange) { 285bb163c02SIngo Weinhold add_used_mtrr(base, range * 2, analysis.type); 286bb163c02SIngo Weinhold subtractive = true; 287bb163c02SIngo Weinhold break; 288bb163c02SIngo Weinhold } 289bb163c02SIngo Weinhold 290bb163c02SIngo Weinhold if ((size & range) != 0) { 291bb163c02SIngo Weinhold add_used_mtrr(base, range, analysis.type); 292bb163c02SIngo Weinhold base += range; 293bb163c02SIngo Weinhold size -= range; 294bb163c02SIngo Weinhold } 295bb163c02SIngo Weinhold 296bb163c02SIngo Weinhold range >>= 1; 297bb163c02SIngo Weinhold } 298bb163c02SIngo Weinhold 299bb163c02SIngo Weinhold if (subtractive) { 300bb163c02SIngo Weinhold uint64 rangeEnd = base + range * 2; 301bb163c02SIngo Weinhold uint64 shortestRange = range; 302bb163c02SIngo Weinhold while (size > 0) { 303bb163c02SIngo Weinhold if ((size & range) != 0) { 304bb163c02SIngo Weinhold shortestRange = range; 305bb163c02SIngo Weinhold size -= range; 306bb163c02SIngo Weinhold } else { 307bb163c02SIngo Weinhold rangeEnd -= range; 308bb163c02SIngo Weinhold add_used_mtrr(rangeEnd, range, IA32_MTR_UNCACHED); 309bb163c02SIngo Weinhold } 310bb163c02SIngo Weinhold 311bb163c02SIngo Weinhold range >>= 1; 312bb163c02SIngo Weinhold } 313bb163c02SIngo Weinhold 314bb163c02SIngo Weinhold rangeEnd -= shortestRange; 315bb163c02SIngo Weinhold add_used_mtrr(rangeEnd, shortestRange, IA32_MTR_UNCACHED); 316bb163c02SIngo Weinhold } 317bb163c02SIngo Weinhold } 3184f893e39SJérôme Duval } 3194f893e39SJérôme Duval 3204f893e39SJérôme Duval 321393fceb5SAxel Dörfler static status_t 322bb163c02SIngo Weinhold update_mttrs() 323393fceb5SAxel Dörfler { 324bb163c02SIngo Weinhold // Transfer the range array to the analysis array, dropping all uncachable 325bb163c02SIngo Weinhold // ranges (that's the default anyway) and joining adjacent ranges with the 326bb163c02SIngo Weinhold // same type. 327bb163c02SIngo Weinhold memory_type_range_analysis* ranges = sMemoryTypeRangeAnalysis; 328bb163c02SIngo Weinhold uint32 rangeCount = 0; 329bb163c02SIngo Weinhold { 330bb163c02SIngo Weinhold uint32 previousRangeType = IA32_MTR_UNCACHED; 331bb163c02SIngo Weinhold uint64 previousRangeEnd = 0; 332bb163c02SIngo Weinhold for (uint32 i = 0; i < sMemoryTypeRangeCount; i++) { 333bb163c02SIngo Weinhold if (sMemoryTypeRanges[i].type != IA32_MTR_UNCACHED) { 334bb163c02SIngo Weinhold uint64 rangeEnd = sMemoryTypeRanges[i].base 335bb163c02SIngo Weinhold + sMemoryTypeRanges[i].size; 336bb163c02SIngo Weinhold if (previousRangeType == sMemoryTypeRanges[i].type 337bb163c02SIngo Weinhold && previousRangeEnd >= sMemoryTypeRanges[i].base) { 338bb163c02SIngo Weinhold // the range overlaps/continues the previous range -- just 339bb163c02SIngo Weinhold // enlarge that one 340bb163c02SIngo Weinhold if (rangeEnd > previousRangeEnd) 341bb163c02SIngo Weinhold previousRangeEnd = rangeEnd; 342bb163c02SIngo Weinhold ranges[rangeCount - 1].size = previousRangeEnd 343bb163c02SIngo Weinhold - ranges[rangeCount - 1].base; 344bb163c02SIngo Weinhold } else { 345bb163c02SIngo Weinhold // add the new range 346bb163c02SIngo Weinhold memset(&ranges[rangeCount], 0, sizeof(ranges[rangeCount])); 347bb163c02SIngo Weinhold ranges[rangeCount].base = sMemoryTypeRanges[i].base; 348bb163c02SIngo Weinhold ranges[rangeCount].size = sMemoryTypeRanges[i].size; 349bb163c02SIngo Weinhold ranges[rangeCount].type = sMemoryTypeRanges[i].type; 350bb163c02SIngo Weinhold previousRangeEnd = rangeEnd; 351bb163c02SIngo Weinhold previousRangeType = sMemoryTypeRanges[i].type; 352bb163c02SIngo Weinhold rangeCount++; 353bb163c02SIngo Weinhold } 354bb163c02SIngo Weinhold } 355bb163c02SIngo Weinhold } 356bb163c02SIngo Weinhold } 357393fceb5SAxel Dörfler 358bb163c02SIngo Weinhold // analyze the ranges 359bb163c02SIngo Weinhold uint32 registersNeeded = 0; 360bb163c02SIngo Weinhold uint64 previousEnd = 0; 361bb163c02SIngo Weinhold for (uint32 i = 0; i < rangeCount; i++) { 362bb163c02SIngo Weinhold memory_type_range_analysis& range = ranges[i]; 363bb163c02SIngo Weinhold uint64 nextBase = i + 1 < rangeCount ? ranges[i + 1].base : 0; 364bb163c02SIngo Weinhold analyze_range(range, previousEnd, nextBase); 365bb163c02SIngo Weinhold registersNeeded += range.rangesNeeded; 366bb163c02SIngo Weinhold previousEnd = range.base + range.size; 367bb163c02SIngo Weinhold } 368bb163c02SIngo Weinhold 369bb163c02SIngo Weinhold // fail when we need more registers than we have 370bb163c02SIngo Weinhold if (registersNeeded > sMemoryTypeRegisterCount) 371bb163c02SIngo Weinhold return B_BUSY; 372bb163c02SIngo Weinhold 373bb163c02SIngo Weinhold sMemoryTypeRegistersUsed = 0; 374bb163c02SIngo Weinhold 375bb163c02SIngo Weinhold for (uint32 i = 0; i < rangeCount; i++) { 376bb163c02SIngo Weinhold memory_type_range_analysis& range = ranges[i]; 377bb163c02SIngo Weinhold compute_mtrrs(range); 378bb163c02SIngo Weinhold } 379bb163c02SIngo Weinhold 380bb163c02SIngo Weinhold set_mtrrs(); 381bb163c02SIngo Weinhold 382bb163c02SIngo Weinhold return B_OK; 383bb163c02SIngo Weinhold } 384bb163c02SIngo Weinhold 385bb163c02SIngo Weinhold 386bb163c02SIngo Weinhold static void 387bb163c02SIngo Weinhold remove_memory_type_range_locked(uint32 index) 388bb163c02SIngo Weinhold { 389bb163c02SIngo Weinhold sMemoryTypeRangeCount--; 390bb163c02SIngo Weinhold if (index < sMemoryTypeRangeCount) { 391bb163c02SIngo Weinhold memmove(sMemoryTypeRanges + index, sMemoryTypeRanges + index + 1, 392bb163c02SIngo Weinhold (sMemoryTypeRangeCount - index) * sizeof(memory_type_range)); 393bb163c02SIngo Weinhold } 394bb163c02SIngo Weinhold } 395bb163c02SIngo Weinhold 396bb163c02SIngo Weinhold 397bb163c02SIngo Weinhold static status_t 398bb163c02SIngo Weinhold add_memory_type_range(area_id areaID, uint64 base, uint64 size, uint32 type) 399bb163c02SIngo Weinhold { 400bb163c02SIngo Weinhold // translate the type 401393fceb5SAxel Dörfler if (type == 0) 402393fceb5SAxel Dörfler return B_OK; 403393fceb5SAxel Dörfler 404393fceb5SAxel Dörfler switch (type) { 405393fceb5SAxel Dörfler case B_MTR_UC: 4064f893e39SJérôme Duval type = IA32_MTR_UNCACHED; 407393fceb5SAxel Dörfler break; 408393fceb5SAxel Dörfler case B_MTR_WC: 4094f893e39SJérôme Duval type = IA32_MTR_WRITE_COMBINING; 410393fceb5SAxel Dörfler break; 411393fceb5SAxel Dörfler case B_MTR_WT: 4124f893e39SJérôme Duval type = IA32_MTR_WRITE_THROUGH; 413393fceb5SAxel Dörfler break; 414393fceb5SAxel Dörfler case B_MTR_WP: 4154f893e39SJérôme Duval type = IA32_MTR_WRITE_PROTECTED; 416393fceb5SAxel Dörfler break; 417393fceb5SAxel Dörfler case B_MTR_WB: 4184f893e39SJérôme Duval type = IA32_MTR_WRITE_BACK; 419393fceb5SAxel Dörfler break; 420393fceb5SAxel Dörfler default: 421393fceb5SAxel Dörfler return B_BAD_VALUE; 422393fceb5SAxel Dörfler } 423393fceb5SAxel Dörfler 424bb163c02SIngo Weinhold TRACE_MTRR("add_memory_type_range(%ld, %#llx, %#llx, %lu)\n", areaID, base, 425bb163c02SIngo Weinhold size, type); 426393fceb5SAxel Dörfler 427bb163c02SIngo Weinhold // base and size must at least be aligned to the minimum range size 428bb163c02SIngo Weinhold if (((base | size) & (kMinMemoryTypeRangeSize - 1)) != 0) { 429bb163c02SIngo Weinhold dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): Memory base or " 430bb163c02SIngo Weinhold "size not minimally aligned!\n", areaID, base, size, type); 431393fceb5SAxel Dörfler return B_BAD_VALUE; 432393fceb5SAxel Dörfler } 433393fceb5SAxel Dörfler 434bb163c02SIngo Weinhold MutexLocker locker(sMemoryTypeLock); 435bb163c02SIngo Weinhold 436bb163c02SIngo Weinhold if (sMemoryTypeRangeCount == kMaxMemoryTypeRanges) { 437bb163c02SIngo Weinhold dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): Out of " 438bb163c02SIngo Weinhold "memory ranges!\n", areaID, base, size, type); 439bb163c02SIngo Weinhold return B_BUSY; 440bb163c02SIngo Weinhold } 441bb163c02SIngo Weinhold 442bb163c02SIngo Weinhold // iterate through the existing ranges and check for clashes 443bb163c02SIngo Weinhold bool foundInsertionIndex = false; 444bb163c02SIngo Weinhold uint32 index = 0; 445bb163c02SIngo Weinhold for (uint32 i = 0; i < sMemoryTypeRangeCount; i++) { 446bb163c02SIngo Weinhold const memory_type_range& range = sMemoryTypeRanges[i]; 447bb163c02SIngo Weinhold if (range.base > base) { 448bb163c02SIngo Weinhold if (range.base - base < size && range.type != type) { 449bb163c02SIngo Weinhold dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): Memory " 450bb163c02SIngo Weinhold "range intersects with existing one (%#llx, %#llx, %lu).\n", 451bb163c02SIngo Weinhold areaID, base, size, type, range.base, range.size, 452bb163c02SIngo Weinhold range.type); 453393fceb5SAxel Dörfler return B_BAD_VALUE; 454bb163c02SIngo Weinhold } 455393fceb5SAxel Dörfler 456bb163c02SIngo Weinhold // found the insertion index 457bb163c02SIngo Weinhold if (!foundInsertionIndex) { 458bb163c02SIngo Weinhold index = i; 459bb163c02SIngo Weinhold foundInsertionIndex = true; 460bb163c02SIngo Weinhold } 461bb163c02SIngo Weinhold break; 462bb163c02SIngo Weinhold } else if (base - range.base < range.size && range.type != type) { 463bb163c02SIngo Weinhold dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): Memory " 464bb163c02SIngo Weinhold "range intersects with existing one (%#llx, %#llx, %lu).\n", 465bb163c02SIngo Weinhold areaID, base, size, type, range.base, range.size, range.type); 466bb163c02SIngo Weinhold return B_BAD_VALUE; 467bb163c02SIngo Weinhold } 468bb163c02SIngo Weinhold } 469393fceb5SAxel Dörfler 470bb163c02SIngo Weinhold if (!foundInsertionIndex) 471bb163c02SIngo Weinhold index = sMemoryTypeRangeCount; 472393fceb5SAxel Dörfler 473bb163c02SIngo Weinhold // make room for the new range 474bb163c02SIngo Weinhold if (index < sMemoryTypeRangeCount) { 475bb163c02SIngo Weinhold memmove(sMemoryTypeRanges + index + 1, sMemoryTypeRanges + index, 476bb163c02SIngo Weinhold (sMemoryTypeRangeCount - index) * sizeof(memory_type_range)); 477bb163c02SIngo Weinhold } 478bb163c02SIngo Weinhold sMemoryTypeRangeCount++; 479393fceb5SAxel Dörfler 480bb163c02SIngo Weinhold memory_type_range& rangeInfo = sMemoryTypeRanges[index]; 481bb163c02SIngo Weinhold rangeInfo.base = base; 482bb163c02SIngo Weinhold rangeInfo.size = size; 483bb163c02SIngo Weinhold rangeInfo.type = type; 484bb163c02SIngo Weinhold rangeInfo.area = areaID; 485bb163c02SIngo Weinhold 486bb163c02SIngo Weinhold uint64 range = kMinMemoryTypeRangeSize; 487bb163c02SIngo Weinhold status_t error; 488bb163c02SIngo Weinhold do { 489bb163c02SIngo Weinhold error = update_mttrs(); 490bb163c02SIngo Weinhold if (error == B_OK) { 491bb163c02SIngo Weinhold if (rangeInfo.size != size) { 492bb163c02SIngo Weinhold dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): " 493bb163c02SIngo Weinhold "update_mtrrs() succeeded only with simplified range: " 494bb163c02SIngo Weinhold "base: %#llx, size: %#llx\n", areaID, base, size, type, 495bb163c02SIngo Weinhold rangeInfo.base, rangeInfo.size); 496bb163c02SIngo Weinhold } 497393fceb5SAxel Dörfler return B_OK; 498393fceb5SAxel Dörfler } 499393fceb5SAxel Dörfler 500bb163c02SIngo Weinhold // update_mttrs() failed -- try to simplify (i.e. shrink) the range 501bb163c02SIngo Weinhold while (rangeInfo.size != 0) { 502bb163c02SIngo Weinhold if ((rangeInfo.base & range) != 0) { 503bb163c02SIngo Weinhold rangeInfo.base += range; 504bb163c02SIngo Weinhold rangeInfo.size -= range; 505bb163c02SIngo Weinhold // don't shift the range yet -- we might still have an 506bb163c02SIngo Weinhold // unaligned size 507bb163c02SIngo Weinhold break; 508bb163c02SIngo Weinhold } 509bb163c02SIngo Weinhold if ((rangeInfo.size & range) != 0) { 510bb163c02SIngo Weinhold rangeInfo.size -= range; 511bb163c02SIngo Weinhold range <<= 1; 512bb163c02SIngo Weinhold break; 513bb163c02SIngo Weinhold } 514393fceb5SAxel Dörfler 515bb163c02SIngo Weinhold range <<= 1; 516bb163c02SIngo Weinhold } 517bb163c02SIngo Weinhold } while (rangeInfo.size > 0); 518bb163c02SIngo Weinhold 519bb163c02SIngo Weinhold dprintf("add_memory_type_range(%ld, %#llx, %#llx, %lu): update_mtrrs() " 520bb163c02SIngo Weinhold "failed.\n", areaID, base, size, type); 521bb163c02SIngo Weinhold remove_memory_type_range_locked(index); 522bb163c02SIngo Weinhold return error; 523bb163c02SIngo Weinhold } 5244f893e39SJérôme Duval 5254f893e39SJérôme Duval 5264f893e39SJérôme Duval static void 527bb163c02SIngo Weinhold remove_memory_type_range(area_id areaID) 5284f893e39SJérôme Duval { 529bb163c02SIngo Weinhold MutexLocker locker(sMemoryTypeLock); 530bb163c02SIngo Weinhold 531bb163c02SIngo Weinhold for (uint32 i = 0; i < sMemoryTypeRangeCount; i++) { 532bb163c02SIngo Weinhold if (sMemoryTypeRanges[i].area == areaID) { 533bb163c02SIngo Weinhold TRACE_MTRR("remove_memory_type_range(%ld, %#llx, %#llxd)\n", 534bb163c02SIngo Weinhold areaID, sMemoryTypeRanges[i].base, sMemoryTypeRanges[i].size); 535bb163c02SIngo Weinhold remove_memory_type_range_locked(i); 536bb163c02SIngo Weinhold update_mttrs(); 537bb163c02SIngo Weinhold // TODO: It's actually possible that this call fails, since 538bb163c02SIngo Weinhold // compute_mtrrs() joins ranges and removing one might cause a 539bb163c02SIngo Weinhold // previously joined big simple range to be split into several 540bb163c02SIngo Weinhold // ranges (or just make it more complicated). 541f7c655c7SJérôme Duval return; 542f7c655c7SJérôme Duval } 5434f893e39SJérôme Duval } 5444f893e39SJérôme Duval } 5454f893e39SJérôme Duval 5464f893e39SJérôme Duval 547393fceb5SAxel Dörfler // #pragma mark - 548393fceb5SAxel Dörfler 549393fceb5SAxel Dörfler 550393fceb5SAxel Dörfler status_t 551393fceb5SAxel Dörfler arch_vm_init(kernel_args *args) 552393fceb5SAxel Dörfler { 553393fceb5SAxel Dörfler TRACE(("arch_vm_init: entry\n")); 554393fceb5SAxel Dörfler return 0; 555393fceb5SAxel Dörfler } 556393fceb5SAxel Dörfler 557393fceb5SAxel Dörfler 558393fceb5SAxel Dörfler /*! Marks DMA region as in-use, and maps it into the kernel space */ 559393fceb5SAxel Dörfler status_t 560393fceb5SAxel Dörfler arch_vm_init_post_area(kernel_args *args) 561393fceb5SAxel Dörfler { 562393fceb5SAxel Dörfler area_id id; 563393fceb5SAxel Dörfler 564393fceb5SAxel Dörfler TRACE(("arch_vm_init_post_area: entry\n")); 565393fceb5SAxel Dörfler 566393fceb5SAxel Dörfler // account for DMA area and mark the pages unusable 567393fceb5SAxel Dörfler vm_mark_page_range_inuse(0x0, 0xa0000 / B_PAGE_SIZE); 568393fceb5SAxel Dörfler 569393fceb5SAxel Dörfler // map 0 - 0xa0000 directly 570393fceb5SAxel Dörfler id = map_physical_memory("dma_region", (void *)0x0, 0xa0000, 571393fceb5SAxel Dörfler B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 572393fceb5SAxel Dörfler &gDmaAddress); 573393fceb5SAxel Dörfler if (id < 0) { 574393fceb5SAxel Dörfler panic("arch_vm_init_post_area: unable to map dma region\n"); 575393fceb5SAxel Dörfler return B_NO_MEMORY; 576393fceb5SAxel Dörfler } 577393fceb5SAxel Dörfler 578393fceb5SAxel Dörfler return bios_init(); 579393fceb5SAxel Dörfler } 580393fceb5SAxel Dörfler 581393fceb5SAxel Dörfler 582393fceb5SAxel Dörfler /*! Gets rid of all yet unmapped (and therefore now unused) page tables */ 583393fceb5SAxel Dörfler status_t 584393fceb5SAxel Dörfler arch_vm_init_end(kernel_args *args) 585393fceb5SAxel Dörfler { 586393fceb5SAxel Dörfler TRACE(("arch_vm_init_endvm: entry\n")); 587393fceb5SAxel Dörfler 588393fceb5SAxel Dörfler // throw away anything in the kernel_args.pgtable[] that's not yet mapped 589393fceb5SAxel Dörfler vm_free_unused_boot_loader_range(KERNEL_BASE, 590393fceb5SAxel Dörfler 0x400000 * args->arch_args.num_pgtables); 591393fceb5SAxel Dörfler 592393fceb5SAxel Dörfler return B_OK; 593393fceb5SAxel Dörfler } 594393fceb5SAxel Dörfler 595393fceb5SAxel Dörfler 596393fceb5SAxel Dörfler status_t 597393fceb5SAxel Dörfler arch_vm_init_post_modules(kernel_args *args) 598393fceb5SAxel Dörfler { 599393fceb5SAxel Dörfler // the x86 CPU modules are now accessible 600393fceb5SAxel Dörfler 601393fceb5SAxel Dörfler sMemoryTypeRegisterCount = x86_count_mtrrs(); 602393fceb5SAxel Dörfler if (sMemoryTypeRegisterCount == 0) 603393fceb5SAxel Dörfler return B_OK; 604393fceb5SAxel Dörfler 605393fceb5SAxel Dörfler // not very likely, but play safe here 606393fceb5SAxel Dörfler if (sMemoryTypeRegisterCount > kMaxMemoryTypeRegisters) 607393fceb5SAxel Dörfler sMemoryTypeRegisterCount = kMaxMemoryTypeRegisters; 608393fceb5SAxel Dörfler 609393fceb5SAxel Dörfler // set the physical memory ranges to write-back mode 610393fceb5SAxel Dörfler for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) { 611bb163c02SIngo Weinhold add_memory_type_range(-1, args->physical_memory_range[i].start, 612bb163c02SIngo Weinhold args->physical_memory_range[i].size, B_MTR_WB); 613393fceb5SAxel Dörfler } 614393fceb5SAxel Dörfler 615393fceb5SAxel Dörfler return B_OK; 616393fceb5SAxel Dörfler } 617393fceb5SAxel Dörfler 618393fceb5SAxel Dörfler 619393fceb5SAxel Dörfler void 620b0db552cSIngo Weinhold arch_vm_aspace_swap(struct VMAddressSpace *from, struct VMAddressSpace *to) 621393fceb5SAxel Dörfler { 6229a42ad7aSIngo Weinhold // This functions is only invoked when a userland thread is in the process 6239a42ad7aSIngo Weinhold // of dying. It switches to the kernel team and does whatever cleanup is 6249a42ad7aSIngo Weinhold // necessary (in case it is the team's main thread, it will delete the 6259a42ad7aSIngo Weinhold // team). 6269a42ad7aSIngo Weinhold // It is however not necessary to change the page directory. Userland team's 6279a42ad7aSIngo Weinhold // page directories include all kernel mappings as well. Furthermore our 6289a42ad7aSIngo Weinhold // arch specific translation map data objects are ref-counted, so they won't 6299a42ad7aSIngo Weinhold // go away as long as they are still used on any CPU. 630393fceb5SAxel Dörfler } 631393fceb5SAxel Dörfler 632393fceb5SAxel Dörfler 633393fceb5SAxel Dörfler bool 634393fceb5SAxel Dörfler arch_vm_supports_protection(uint32 protection) 635393fceb5SAxel Dörfler { 636393fceb5SAxel Dörfler // x86 always has the same read/write properties for userland and the 637393fceb5SAxel Dörfler // kernel. 638393fceb5SAxel Dörfler // That's why we do not support user-read/kernel-write access. While the 639393fceb5SAxel Dörfler // other way around is not supported either, we don't care in this case 640393fceb5SAxel Dörfler // and give the kernel full access. 641393fceb5SAxel Dörfler if ((protection & (B_READ_AREA | B_WRITE_AREA)) == B_READ_AREA 642393fceb5SAxel Dörfler && protection & B_KERNEL_WRITE_AREA) 643393fceb5SAxel Dörfler return false; 644393fceb5SAxel Dörfler 645393fceb5SAxel Dörfler return true; 646393fceb5SAxel Dörfler } 647393fceb5SAxel Dörfler 648393fceb5SAxel Dörfler 649393fceb5SAxel Dörfler void 650*a99eb6b5SIngo Weinhold arch_vm_unset_memory_type(struct VMArea *area) 651393fceb5SAxel Dörfler { 652393fceb5SAxel Dörfler if (area->memory_type == 0) 653393fceb5SAxel Dörfler return; 654393fceb5SAxel Dörfler 655bb163c02SIngo Weinhold remove_memory_type_range(area->id); 656393fceb5SAxel Dörfler } 657393fceb5SAxel Dörfler 658393fceb5SAxel Dörfler 659393fceb5SAxel Dörfler status_t 660*a99eb6b5SIngo Weinhold arch_vm_set_memory_type(struct VMArea *area, addr_t physicalBase, 661393fceb5SAxel Dörfler uint32 type) 662393fceb5SAxel Dörfler { 663393fceb5SAxel Dörfler area->memory_type = type >> MEMORY_TYPE_SHIFT; 664bb163c02SIngo Weinhold return add_memory_type_range(area->id, physicalBase, area->size, type); 665393fceb5SAxel Dörfler } 666