1393fceb5SAxel Dörfler /* 2393fceb5SAxel Dörfler * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. 3393fceb5SAxel Dörfler * Distributed under the terms of the MIT License. 4393fceb5SAxel Dörfler * 5393fceb5SAxel Dörfler * Copyright 2001, Travis Geiselbrecht. All rights reserved. 6393fceb5SAxel Dörfler * Distributed under the terms of the NewOS License. 7393fceb5SAxel Dörfler */ 8393fceb5SAxel Dörfler 9393fceb5SAxel Dörfler 10393fceb5SAxel Dörfler #include <KernelExport.h> 11393fceb5SAxel Dörfler #include <smp.h> 12393fceb5SAxel Dörfler #include <util/AutoLock.h> 13393fceb5SAxel Dörfler #include <vm.h> 14393fceb5SAxel Dörfler #include <vm_page.h> 15393fceb5SAxel Dörfler #include <vm_priv.h> 16393fceb5SAxel Dörfler 17393fceb5SAxel Dörfler #include <arch/vm.h> 18393fceb5SAxel Dörfler #include <arch/int.h> 19393fceb5SAxel Dörfler #include <arch/cpu.h> 20393fceb5SAxel Dörfler 21393fceb5SAxel Dörfler #include <arch/x86/bios.h> 22393fceb5SAxel Dörfler 23393fceb5SAxel Dörfler #include <stdlib.h> 24393fceb5SAxel Dörfler #include <string.h> 25393fceb5SAxel Dörfler 26393fceb5SAxel Dörfler 27393fceb5SAxel Dörfler //#define TRACE_ARCH_VM 28393fceb5SAxel Dörfler #ifdef TRACE_ARCH_VM 29393fceb5SAxel Dörfler # define TRACE(x) dprintf x 30393fceb5SAxel Dörfler #else 31393fceb5SAxel Dörfler # define TRACE(x) ; 32393fceb5SAxel Dörfler #endif 33393fceb5SAxel Dörfler 34393fceb5SAxel Dörfler 35393fceb5SAxel Dörfler #define kMaxMemoryTypeRegisters 32 36393fceb5SAxel Dörfler 37393fceb5SAxel Dörfler void *gDmaAddress; 38393fceb5SAxel Dörfler 39393fceb5SAxel Dörfler static uint32 sMemoryTypeBitmap; 40393fceb5SAxel Dörfler static int32 sMemoryTypeIDs[kMaxMemoryTypeRegisters]; 41393fceb5SAxel Dörfler static uint32 sMemoryTypeRegisterCount; 42393fceb5SAxel Dörfler static spinlock sMemoryTypeLock; 43393fceb5SAxel Dörfler 44393fceb5SAxel Dörfler 45393fceb5SAxel Dörfler static int32 46393fceb5SAxel Dörfler allocate_mtrr(void) 47393fceb5SAxel Dörfler { 48393fceb5SAxel Dörfler InterruptsSpinLocker _(&sMemoryTypeLock); 49393fceb5SAxel Dörfler 50393fceb5SAxel Dörfler // find free bit 51393fceb5SAxel Dörfler 52393fceb5SAxel Dörfler for (uint32 index = 0; index < sMemoryTypeRegisterCount; index++) { 53393fceb5SAxel Dörfler if (sMemoryTypeBitmap & (1UL << index)) 54393fceb5SAxel Dörfler continue; 55393fceb5SAxel Dörfler 56393fceb5SAxel Dörfler sMemoryTypeBitmap |= 1UL << index; 57393fceb5SAxel Dörfler return index; 58393fceb5SAxel Dörfler } 59393fceb5SAxel Dörfler 60393fceb5SAxel Dörfler return -1; 61393fceb5SAxel Dörfler } 62393fceb5SAxel Dörfler 63393fceb5SAxel Dörfler 64393fceb5SAxel Dörfler static void 65393fceb5SAxel Dörfler free_mtrr(int32 index) 66393fceb5SAxel Dörfler { 67393fceb5SAxel Dörfler InterruptsSpinLocker _(&sMemoryTypeLock); 68393fceb5SAxel Dörfler 69393fceb5SAxel Dörfler sMemoryTypeBitmap &= ~(1UL << index); 70393fceb5SAxel Dörfler } 71393fceb5SAxel Dörfler 72393fceb5SAxel Dörfler 73393fceb5SAxel Dörfler static uint64 74393fceb5SAxel Dörfler nearest_power(addr_t value) 75393fceb5SAxel Dörfler { 76393fceb5SAxel Dörfler uint64 power = 1UL << 12; 77393fceb5SAxel Dörfler // 12 bits is the smallest supported alignment/length 78393fceb5SAxel Dörfler 79393fceb5SAxel Dörfler while (value > power) 80393fceb5SAxel Dörfler power <<= 1; 81393fceb5SAxel Dörfler 82393fceb5SAxel Dörfler return power; 83393fceb5SAxel Dörfler } 84393fceb5SAxel Dörfler 85393fceb5SAxel Dörfler 86393fceb5SAxel Dörfler static status_t 87393fceb5SAxel Dörfler set_memory_type(int32 id, uint64 base, uint64 length, uint32 type) 88393fceb5SAxel Dörfler { 89393fceb5SAxel Dörfler int32 index; 90393fceb5SAxel Dörfler 91393fceb5SAxel Dörfler if (type == 0) 92393fceb5SAxel Dörfler return B_OK; 93393fceb5SAxel Dörfler 94*2d2212bdSJérôme Duval uint32 newType; 95*2d2212bdSJérôme Duval 96393fceb5SAxel Dörfler switch (type) { 97393fceb5SAxel Dörfler case B_MTR_UC: 98*2d2212bdSJérôme Duval newType = IA32_MTR_UNCACHED; 99393fceb5SAxel Dörfler break; 100393fceb5SAxel Dörfler case B_MTR_WC: 101*2d2212bdSJérôme Duval newType = IA32_MTR_WRITE_COMBINING; 102393fceb5SAxel Dörfler break; 103393fceb5SAxel Dörfler case B_MTR_WT: 104*2d2212bdSJérôme Duval newType = IA32_MTR_WRITE_THROUGH; 105393fceb5SAxel Dörfler break; 106393fceb5SAxel Dörfler case B_MTR_WP: 107*2d2212bdSJérôme Duval newType = IA32_MTR_WRITE_PROTECTED; 108393fceb5SAxel Dörfler break; 109393fceb5SAxel Dörfler case B_MTR_WB: 110*2d2212bdSJérôme Duval newType = IA32_MTR_WRITE_BACK; 111393fceb5SAxel Dörfler break; 112393fceb5SAxel Dörfler 113393fceb5SAxel Dörfler default: 114393fceb5SAxel Dörfler return B_BAD_VALUE; 115393fceb5SAxel Dörfler } 116393fceb5SAxel Dörfler 117393fceb5SAxel Dörfler if (sMemoryTypeRegisterCount == 0) 118393fceb5SAxel Dörfler return B_NOT_SUPPORTED; 119393fceb5SAxel Dörfler 120393fceb5SAxel Dörfler // length must be a power of 2; just round it up to the next value 121*2d2212bdSJérôme Duval uint64 newLength = nearest_power(length); 122*2d2212bdSJérôme Duval 123*2d2212bdSJérôme Duval // avoids more than 2GB slots 124*2d2212bdSJérôme Duval if (newLength > 0x80000000) 125*2d2212bdSJérôme Duval newLength = 0x80000000; 126*2d2212bdSJérôme Duval 127*2d2212bdSJérôme Duval if (newLength + base <= base) { 128393fceb5SAxel Dörfler // 4GB overflow 129393fceb5SAxel Dörfler return B_BAD_VALUE; 130393fceb5SAxel Dörfler } 131393fceb5SAxel Dörfler 132393fceb5SAxel Dörfler // base must be aligned to the length 133*2d2212bdSJérôme Duval if (base & (newLength - 1)) 134393fceb5SAxel Dörfler return B_BAD_VALUE; 135393fceb5SAxel Dörfler 136393fceb5SAxel Dörfler index = allocate_mtrr(); 137393fceb5SAxel Dörfler if (index < 0) 138393fceb5SAxel Dörfler return B_ERROR; 139393fceb5SAxel Dörfler 140393fceb5SAxel Dörfler TRACE(("allocate MTRR slot %ld, base = %Lx, length = %Lx\n", index, 141*2d2212bdSJérôme Duval base, newLength)); 142393fceb5SAxel Dörfler 143393fceb5SAxel Dörfler sMemoryTypeIDs[index] = id; 144*2d2212bdSJérôme Duval x86_set_mtrr(index, base, newLength, newType); 145*2d2212bdSJérôme Duval 146*2d2212bdSJérôme Duval // now handle remaining memory 147*2d2212bdSJérôme Duval if (length > newLength) { 148*2d2212bdSJérôme Duval // TODO iterate over smaller lengths to avoid the PCI hole after the physical memory. 149*2d2212bdSJérôme Duval set_memory_type(id, base + newLength, length - newLength, type); 150*2d2212bdSJérôme Duval } 151393fceb5SAxel Dörfler 152393fceb5SAxel Dörfler return B_OK; 153393fceb5SAxel Dörfler } 154393fceb5SAxel Dörfler 155393fceb5SAxel Dörfler 156393fceb5SAxel Dörfler // #pragma mark - 157393fceb5SAxel Dörfler 158393fceb5SAxel Dörfler 159393fceb5SAxel Dörfler status_t 160393fceb5SAxel Dörfler arch_vm_init(kernel_args *args) 161393fceb5SAxel Dörfler { 162393fceb5SAxel Dörfler TRACE(("arch_vm_init: entry\n")); 163393fceb5SAxel Dörfler return 0; 164393fceb5SAxel Dörfler } 165393fceb5SAxel Dörfler 166393fceb5SAxel Dörfler 167393fceb5SAxel Dörfler /*! Marks DMA region as in-use, and maps it into the kernel space */ 168393fceb5SAxel Dörfler status_t 169393fceb5SAxel Dörfler arch_vm_init_post_area(kernel_args *args) 170393fceb5SAxel Dörfler { 171393fceb5SAxel Dörfler area_id id; 172393fceb5SAxel Dörfler 173393fceb5SAxel Dörfler TRACE(("arch_vm_init_post_area: entry\n")); 174393fceb5SAxel Dörfler 175393fceb5SAxel Dörfler // account for DMA area and mark the pages unusable 176393fceb5SAxel Dörfler vm_mark_page_range_inuse(0x0, 0xa0000 / B_PAGE_SIZE); 177393fceb5SAxel Dörfler 178393fceb5SAxel Dörfler // map 0 - 0xa0000 directly 179393fceb5SAxel Dörfler id = map_physical_memory("dma_region", (void *)0x0, 0xa0000, 180393fceb5SAxel Dörfler B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 181393fceb5SAxel Dörfler &gDmaAddress); 182393fceb5SAxel Dörfler if (id < 0) { 183393fceb5SAxel Dörfler panic("arch_vm_init_post_area: unable to map dma region\n"); 184393fceb5SAxel Dörfler return B_NO_MEMORY; 185393fceb5SAxel Dörfler } 186393fceb5SAxel Dörfler 187393fceb5SAxel Dörfler return bios_init(); 188393fceb5SAxel Dörfler } 189393fceb5SAxel Dörfler 190393fceb5SAxel Dörfler 191393fceb5SAxel Dörfler /*! Gets rid of all yet unmapped (and therefore now unused) page tables */ 192393fceb5SAxel Dörfler status_t 193393fceb5SAxel Dörfler arch_vm_init_end(kernel_args *args) 194393fceb5SAxel Dörfler { 195393fceb5SAxel Dörfler TRACE(("arch_vm_init_endvm: entry\n")); 196393fceb5SAxel Dörfler 197393fceb5SAxel Dörfler // throw away anything in the kernel_args.pgtable[] that's not yet mapped 198393fceb5SAxel Dörfler vm_free_unused_boot_loader_range(KERNEL_BASE, 199393fceb5SAxel Dörfler 0x400000 * args->arch_args.num_pgtables); 200393fceb5SAxel Dörfler 201393fceb5SAxel Dörfler return B_OK; 202393fceb5SAxel Dörfler } 203393fceb5SAxel Dörfler 204393fceb5SAxel Dörfler 205393fceb5SAxel Dörfler status_t 206393fceb5SAxel Dörfler arch_vm_init_post_modules(kernel_args *args) 207393fceb5SAxel Dörfler { 208393fceb5SAxel Dörfler // void *cookie; 209393fceb5SAxel Dörfler 210393fceb5SAxel Dörfler // the x86 CPU modules are now accessible 211393fceb5SAxel Dörfler 212393fceb5SAxel Dörfler sMemoryTypeRegisterCount = x86_count_mtrrs(); 213393fceb5SAxel Dörfler if (sMemoryTypeRegisterCount == 0) 214393fceb5SAxel Dörfler return B_OK; 215393fceb5SAxel Dörfler 216393fceb5SAxel Dörfler // not very likely, but play safe here 217393fceb5SAxel Dörfler if (sMemoryTypeRegisterCount > kMaxMemoryTypeRegisters) 218393fceb5SAxel Dörfler sMemoryTypeRegisterCount = kMaxMemoryTypeRegisters; 219393fceb5SAxel Dörfler 220393fceb5SAxel Dörfler // init memory type ID table 221393fceb5SAxel Dörfler 222393fceb5SAxel Dörfler for (uint32 i = 0; i < sMemoryTypeRegisterCount; i++) { 223393fceb5SAxel Dörfler sMemoryTypeIDs[i] = -1; 224393fceb5SAxel Dörfler } 225393fceb5SAxel Dörfler 226393fceb5SAxel Dörfler // set the physical memory ranges to write-back mode 227393fceb5SAxel Dörfler 228393fceb5SAxel Dörfler for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) { 229393fceb5SAxel Dörfler set_memory_type(-1, args->physical_memory_range[i].start, 230393fceb5SAxel Dörfler args->physical_memory_range[i].size, B_MTR_WB); 231393fceb5SAxel Dörfler } 232393fceb5SAxel Dörfler 233393fceb5SAxel Dörfler return B_OK; 234393fceb5SAxel Dörfler } 235393fceb5SAxel Dörfler 236393fceb5SAxel Dörfler 237393fceb5SAxel Dörfler void 238393fceb5SAxel Dörfler arch_vm_aspace_swap(vm_address_space *aspace) 239393fceb5SAxel Dörfler { 240393fceb5SAxel Dörfler i386_swap_pgdir((addr_t)i386_translation_map_get_pgdir( 241393fceb5SAxel Dörfler &aspace->translation_map)); 242393fceb5SAxel Dörfler } 243393fceb5SAxel Dörfler 244393fceb5SAxel Dörfler 245393fceb5SAxel Dörfler bool 246393fceb5SAxel Dörfler arch_vm_supports_protection(uint32 protection) 247393fceb5SAxel Dörfler { 248393fceb5SAxel Dörfler // x86 always has the same read/write properties for userland and the 249393fceb5SAxel Dörfler // kernel. 250393fceb5SAxel Dörfler // That's why we do not support user-read/kernel-write access. While the 251393fceb5SAxel Dörfler // other way around is not supported either, we don't care in this case 252393fceb5SAxel Dörfler // and give the kernel full access. 253393fceb5SAxel Dörfler if ((protection & (B_READ_AREA | B_WRITE_AREA)) == B_READ_AREA 254393fceb5SAxel Dörfler && protection & B_KERNEL_WRITE_AREA) 255393fceb5SAxel Dörfler return false; 256393fceb5SAxel Dörfler 257393fceb5SAxel Dörfler return true; 258393fceb5SAxel Dörfler } 259393fceb5SAxel Dörfler 260393fceb5SAxel Dörfler 261393fceb5SAxel Dörfler void 262393fceb5SAxel Dörfler arch_vm_unset_memory_type(struct vm_area *area) 263393fceb5SAxel Dörfler { 264393fceb5SAxel Dörfler uint32 index; 265393fceb5SAxel Dörfler 266393fceb5SAxel Dörfler if (area->memory_type == 0) 267393fceb5SAxel Dörfler return; 268393fceb5SAxel Dörfler 269393fceb5SAxel Dörfler // find index for area ID 270393fceb5SAxel Dörfler 271393fceb5SAxel Dörfler for (index = 0; index < sMemoryTypeRegisterCount; index++) { 272393fceb5SAxel Dörfler if (sMemoryTypeIDs[index] == area->id) { 273393fceb5SAxel Dörfler x86_set_mtrr(index, 0, 0, 0); 274393fceb5SAxel Dörfler 275393fceb5SAxel Dörfler sMemoryTypeIDs[index] = -1; 276393fceb5SAxel Dörfler free_mtrr(index); 277393fceb5SAxel Dörfler break; 278393fceb5SAxel Dörfler } 279393fceb5SAxel Dörfler } 280393fceb5SAxel Dörfler } 281393fceb5SAxel Dörfler 282393fceb5SAxel Dörfler 283393fceb5SAxel Dörfler status_t 284393fceb5SAxel Dörfler arch_vm_set_memory_type(struct vm_area *area, addr_t physicalBase, 285393fceb5SAxel Dörfler uint32 type) 286393fceb5SAxel Dörfler { 287393fceb5SAxel Dörfler area->memory_type = type >> MEMORY_TYPE_SHIFT; 288393fceb5SAxel Dörfler return set_memory_type(area->id, physicalBase, area->size, type); 289393fceb5SAxel Dörfler } 290