1*c917cd62SIthamar R. Adema /* 2*c917cd62SIthamar R. Adema * Copyirght 2010, Ithamar R. Adema, ithamar.adema@team-embedded.nl 3*c917cd62SIthamar R. Adema * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4*c917cd62SIthamar R. Adema * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 5*c917cd62SIthamar R. Adema * Distributed under the terms of the MIT License. 6*c917cd62SIthamar R. Adema * 7*c917cd62SIthamar R. Adema * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 8*c917cd62SIthamar R. Adema * Distributed under the terms of the NewOS License. 9*c917cd62SIthamar R. Adema */ 10*c917cd62SIthamar R. Adema 11*c917cd62SIthamar R. Adema 12*c917cd62SIthamar R. Adema #include "paging/32bit/ARMPagingMethod32Bit.h" 13*c917cd62SIthamar R. Adema 14*c917cd62SIthamar R. Adema #include <stdlib.h> 15*c917cd62SIthamar R. Adema #include <string.h> 16*c917cd62SIthamar R. Adema 17*c917cd62SIthamar R. Adema #include <AutoDeleter.h> 18*c917cd62SIthamar R. Adema 19*c917cd62SIthamar R. Adema #include <arch_system_info.h> 20*c917cd62SIthamar R. Adema #include <boot/kernel_args.h> 21*c917cd62SIthamar R. Adema #include <int.h> 22*c917cd62SIthamar R. Adema #include <thread.h> 23*c917cd62SIthamar R. Adema #include <vm/vm.h> 24*c917cd62SIthamar R. Adema #include <vm/VMAddressSpace.h> 25*c917cd62SIthamar R. Adema #include <arm_mmu.h> 26*c917cd62SIthamar R. Adema 27*c917cd62SIthamar R. Adema #include "paging/32bit/ARMPagingStructures32Bit.h" 28*c917cd62SIthamar R. Adema #include "paging/32bit/ARMVMTranslationMap32Bit.h" 29*c917cd62SIthamar R. Adema #include "paging/arm_physical_page_mapper.h" 30*c917cd62SIthamar R. Adema #include "paging/arm_physical_page_mapper_large_memory.h" 31*c917cd62SIthamar R. Adema 32*c917cd62SIthamar R. Adema 33*c917cd62SIthamar R. Adema #define TRACE_ARM_PAGING_METHOD_32_BIT 34*c917cd62SIthamar R. Adema #ifdef TRACE_ARM_PAGING_METHOD_32_BIT 35*c917cd62SIthamar R. Adema # define TRACE(x...) dprintf(x) 36*c917cd62SIthamar R. Adema #else 37*c917cd62SIthamar R. Adema # define TRACE(x...) ; 38*c917cd62SIthamar R. Adema #endif 39*c917cd62SIthamar R. Adema 40*c917cd62SIthamar R. Adema 41*c917cd62SIthamar R. Adema using ARMLargePhysicalPageMapper::PhysicalPageSlot; 42*c917cd62SIthamar R. Adema 43*c917cd62SIthamar R. Adema 44*c917cd62SIthamar R. Adema // #pragma mark - ARMPagingMethod32Bit::PhysicalPageSlotPool 45*c917cd62SIthamar R. Adema 46*c917cd62SIthamar R. Adema 47*c917cd62SIthamar R. Adema struct ARMPagingMethod32Bit::PhysicalPageSlotPool 48*c917cd62SIthamar R. Adema : ARMLargePhysicalPageMapper::PhysicalPageSlotPool { 49*c917cd62SIthamar R. Adema public: 50*c917cd62SIthamar R. Adema virtual ~PhysicalPageSlotPool(); 51*c917cd62SIthamar R. Adema 52*c917cd62SIthamar R. Adema status_t InitInitial(kernel_args* args); 53*c917cd62SIthamar R. Adema status_t InitInitialPostArea(kernel_args* args); 54*c917cd62SIthamar R. Adema 55*c917cd62SIthamar R. Adema void Init(area_id dataArea, void* data, 56*c917cd62SIthamar R. Adema area_id virtualArea, addr_t virtualBase); 57*c917cd62SIthamar R. Adema 58*c917cd62SIthamar R. Adema virtual status_t AllocatePool( 59*c917cd62SIthamar R. Adema ARMLargePhysicalPageMapper 60*c917cd62SIthamar R. Adema ::PhysicalPageSlotPool*& _pool); 61*c917cd62SIthamar R. Adema virtual void Map(phys_addr_t physicalAddress, 62*c917cd62SIthamar R. Adema addr_t virtualAddress); 63*c917cd62SIthamar R. Adema 64*c917cd62SIthamar R. Adema public: 65*c917cd62SIthamar R. Adema static PhysicalPageSlotPool sInitialPhysicalPagePool; 66*c917cd62SIthamar R. Adema 67*c917cd62SIthamar R. Adema private: 68*c917cd62SIthamar R. Adema area_id fDataArea; 69*c917cd62SIthamar R. Adema area_id fVirtualArea; 70*c917cd62SIthamar R. Adema addr_t fVirtualBase; 71*c917cd62SIthamar R. Adema page_table_entry* fPageTable; 72*c917cd62SIthamar R. Adema }; 73*c917cd62SIthamar R. Adema 74*c917cd62SIthamar R. Adema 75*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool 76*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::sInitialPhysicalPagePool; 77*c917cd62SIthamar R. Adema 78*c917cd62SIthamar R. Adema 79*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::~PhysicalPageSlotPool() 80*c917cd62SIthamar R. Adema { 81*c917cd62SIthamar R. Adema } 82*c917cd62SIthamar R. Adema 83*c917cd62SIthamar R. Adema 84*c917cd62SIthamar R. Adema status_t 85*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::InitInitial(kernel_args* args) 86*c917cd62SIthamar R. Adema { 87*c917cd62SIthamar R. Adema // allocate a virtual address range for the pages to be mapped into 88*c917cd62SIthamar R. Adema addr_t virtualBase = vm_allocate_early(args, 1024 * B_PAGE_SIZE, 0, 0, 89*c917cd62SIthamar R. Adema kPageTableAlignment); 90*c917cd62SIthamar R. Adema if (virtualBase == 0) { 91*c917cd62SIthamar R. Adema panic("LargeMemoryPhysicalPageMapper::Init(): Failed to reserve " 92*c917cd62SIthamar R. Adema "physical page pool space in virtual address space!"); 93*c917cd62SIthamar R. Adema return B_ERROR; 94*c917cd62SIthamar R. Adema } 95*c917cd62SIthamar R. Adema 96*c917cd62SIthamar R. Adema // allocate memory for the page table and data 97*c917cd62SIthamar R. Adema size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]); 98*c917cd62SIthamar R. Adema page_table_entry* pageTable = (page_table_entry*)vm_allocate_early(args, 99*c917cd62SIthamar R. Adema areaSize, ~0L, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 0); 100*c917cd62SIthamar R. Adema 101*c917cd62SIthamar R. Adema // prepare the page table 102*c917cd62SIthamar R. Adema _EarlyPreparePageTables(pageTable, virtualBase, 1024 * B_PAGE_SIZE); 103*c917cd62SIthamar R. Adema 104*c917cd62SIthamar R. Adema // init the pool structure and add the initial pool 105*c917cd62SIthamar R. Adema Init(-1, pageTable, -1, (addr_t)virtualBase); 106*c917cd62SIthamar R. Adema 107*c917cd62SIthamar R. Adema return B_OK; 108*c917cd62SIthamar R. Adema } 109*c917cd62SIthamar R. Adema 110*c917cd62SIthamar R. Adema 111*c917cd62SIthamar R. Adema status_t 112*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::InitInitialPostArea( 113*c917cd62SIthamar R. Adema kernel_args* args) 114*c917cd62SIthamar R. Adema { 115*c917cd62SIthamar R. Adema // create an area for the (already allocated) data 116*c917cd62SIthamar R. Adema size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]); 117*c917cd62SIthamar R. Adema void* temp = fPageTable; 118*c917cd62SIthamar R. Adema area_id area = create_area("physical page pool", &temp, 119*c917cd62SIthamar R. Adema B_EXACT_ADDRESS, areaSize, B_ALREADY_WIRED, 120*c917cd62SIthamar R. Adema B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 121*c917cd62SIthamar R. Adema if (area < B_OK) { 122*c917cd62SIthamar R. Adema panic("LargeMemoryPhysicalPageMapper::InitPostArea(): Failed to " 123*c917cd62SIthamar R. Adema "create area for physical page pool."); 124*c917cd62SIthamar R. Adema return area; 125*c917cd62SIthamar R. Adema } 126*c917cd62SIthamar R. Adema fDataArea = area; 127*c917cd62SIthamar R. Adema 128*c917cd62SIthamar R. Adema // create an area for the virtual address space 129*c917cd62SIthamar R. Adema temp = (void*)fVirtualBase; 130*c917cd62SIthamar R. Adema area = vm_create_null_area(VMAddressSpace::KernelID(), 131*c917cd62SIthamar R. Adema "physical page pool space", &temp, B_EXACT_ADDRESS, 132*c917cd62SIthamar R. Adema 1024 * B_PAGE_SIZE, 0); 133*c917cd62SIthamar R. Adema if (area < B_OK) { 134*c917cd62SIthamar R. Adema panic("LargeMemoryPhysicalPageMapper::InitPostArea(): Failed to " 135*c917cd62SIthamar R. Adema "create area for physical page pool space."); 136*c917cd62SIthamar R. Adema return area; 137*c917cd62SIthamar R. Adema } 138*c917cd62SIthamar R. Adema fVirtualArea = area; 139*c917cd62SIthamar R. Adema 140*c917cd62SIthamar R. Adema return B_OK; 141*c917cd62SIthamar R. Adema } 142*c917cd62SIthamar R. Adema 143*c917cd62SIthamar R. Adema 144*c917cd62SIthamar R. Adema void 145*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::Init(area_id dataArea, void* data, 146*c917cd62SIthamar R. Adema area_id virtualArea, addr_t virtualBase) 147*c917cd62SIthamar R. Adema { 148*c917cd62SIthamar R. Adema fDataArea = dataArea; 149*c917cd62SIthamar R. Adema fVirtualArea = virtualArea; 150*c917cd62SIthamar R. Adema fVirtualBase = virtualBase; 151*c917cd62SIthamar R. Adema fPageTable = (page_table_entry*)data; 152*c917cd62SIthamar R. Adema 153*c917cd62SIthamar R. Adema // init slot list 154*c917cd62SIthamar R. Adema fSlots = (PhysicalPageSlot*)(fPageTable + 1024); 155*c917cd62SIthamar R. Adema addr_t slotAddress = virtualBase; 156*c917cd62SIthamar R. Adema for (int32 i = 0; i < 1024; i++, slotAddress += B_PAGE_SIZE) { 157*c917cd62SIthamar R. Adema PhysicalPageSlot* slot = &fSlots[i]; 158*c917cd62SIthamar R. Adema slot->next = slot + 1; 159*c917cd62SIthamar R. Adema slot->pool = this; 160*c917cd62SIthamar R. Adema slot->address = slotAddress; 161*c917cd62SIthamar R. Adema } 162*c917cd62SIthamar R. Adema 163*c917cd62SIthamar R. Adema fSlots[1023].next = NULL; 164*c917cd62SIthamar R. Adema // terminate list 165*c917cd62SIthamar R. Adema } 166*c917cd62SIthamar R. Adema 167*c917cd62SIthamar R. Adema 168*c917cd62SIthamar R. Adema void 169*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::Map(phys_addr_t physicalAddress, 170*c917cd62SIthamar R. Adema addr_t virtualAddress) 171*c917cd62SIthamar R. Adema { 172*c917cd62SIthamar R. Adema page_table_entry& pte = fPageTable[(virtualAddress - fVirtualBase) / B_PAGE_SIZE]; 173*c917cd62SIthamar R. Adema pte = (physicalAddress & ARM_PTE_ADDRESS_MASK) 174*c917cd62SIthamar R. Adema | ARM_PTE_TYPE_SMALL_PAGE; 175*c917cd62SIthamar R. Adema 176*c917cd62SIthamar R. Adema arch_cpu_invalidate_TLB_range(virtualAddress, virtualAddress + B_PAGE_SIZE); 177*c917cd62SIthamar R. Adema // invalidate_TLB(virtualAddress); 178*c917cd62SIthamar R. Adema } 179*c917cd62SIthamar R. Adema 180*c917cd62SIthamar R. Adema 181*c917cd62SIthamar R. Adema status_t 182*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::AllocatePool( 183*c917cd62SIthamar R. Adema ARMLargePhysicalPageMapper::PhysicalPageSlotPool*& _pool) 184*c917cd62SIthamar R. Adema { 185*c917cd62SIthamar R. Adema // create the pool structure 186*c917cd62SIthamar R. Adema PhysicalPageSlotPool* pool = new(std::nothrow) PhysicalPageSlotPool; 187*c917cd62SIthamar R. Adema if (pool == NULL) 188*c917cd62SIthamar R. Adema return B_NO_MEMORY; 189*c917cd62SIthamar R. Adema ObjectDeleter<PhysicalPageSlotPool> poolDeleter(pool); 190*c917cd62SIthamar R. Adema 191*c917cd62SIthamar R. Adema // create an area that can contain the page table and the slot 192*c917cd62SIthamar R. Adema // structures 193*c917cd62SIthamar R. Adema size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]); 194*c917cd62SIthamar R. Adema void* data; 195*c917cd62SIthamar R. Adema virtual_address_restrictions virtualRestrictions = {}; 196*c917cd62SIthamar R. Adema virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS; 197*c917cd62SIthamar R. Adema physical_address_restrictions physicalRestrictions = {}; 198*c917cd62SIthamar R. Adema area_id dataArea = create_area_etc(B_SYSTEM_TEAM, "physical page pool", 199*c917cd62SIthamar R. Adema PAGE_ALIGN(areaSize), B_FULL_LOCK, 200*c917cd62SIthamar R. Adema B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT, 201*c917cd62SIthamar R. Adema &virtualRestrictions, &physicalRestrictions, &data); 202*c917cd62SIthamar R. Adema if (dataArea < 0) 203*c917cd62SIthamar R. Adema return dataArea; 204*c917cd62SIthamar R. Adema 205*c917cd62SIthamar R. Adema // create the null area for the virtual address space 206*c917cd62SIthamar R. Adema void* virtualBase; 207*c917cd62SIthamar R. Adema area_id virtualArea = vm_create_null_area( 208*c917cd62SIthamar R. Adema VMAddressSpace::KernelID(), "physical page pool space", 209*c917cd62SIthamar R. Adema &virtualBase, B_ANY_KERNEL_BLOCK_ADDRESS, 1024 * B_PAGE_SIZE, 210*c917cd62SIthamar R. Adema CREATE_AREA_PRIORITY_VIP); 211*c917cd62SIthamar R. Adema if (virtualArea < 0) { 212*c917cd62SIthamar R. Adema delete_area(dataArea); 213*c917cd62SIthamar R. Adema return virtualArea; 214*c917cd62SIthamar R. Adema } 215*c917cd62SIthamar R. Adema 216*c917cd62SIthamar R. Adema // prepare the page table 217*c917cd62SIthamar R. Adema memset(data, 0, B_PAGE_SIZE); 218*c917cd62SIthamar R. Adema 219*c917cd62SIthamar R. Adema // get the page table's physical address 220*c917cd62SIthamar R. Adema phys_addr_t physicalTable; 221*c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit* map = static_cast<ARMVMTranslationMap32Bit*>( 222*c917cd62SIthamar R. Adema VMAddressSpace::Kernel()->TranslationMap()); 223*c917cd62SIthamar R. Adema uint32 dummyFlags; 224*c917cd62SIthamar R. Adema cpu_status state = disable_interrupts(); 225*c917cd62SIthamar R. Adema map->QueryInterrupt((addr_t)data, &physicalTable, &dummyFlags); 226*c917cd62SIthamar R. Adema restore_interrupts(state); 227*c917cd62SIthamar R. Adema 228*c917cd62SIthamar R. Adema // put the page table into the page directory 229*c917cd62SIthamar R. Adema int32 index = VADDR_TO_PDENT((addr_t)virtualBase); 230*c917cd62SIthamar R. Adema page_directory_entry* entry 231*c917cd62SIthamar R. Adema = &map->PagingStructures32Bit()->pgdir_virt[index]; 232*c917cd62SIthamar R. Adema PutPageTableInPageDir(entry, physicalTable, 233*c917cd62SIthamar R. Adema B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 234*c917cd62SIthamar R. Adema ARMPagingStructures32Bit::UpdateAllPageDirs(index, *entry); 235*c917cd62SIthamar R. Adema 236*c917cd62SIthamar R. Adema // init the pool structure 237*c917cd62SIthamar R. Adema pool->Init(dataArea, data, virtualArea, (addr_t)virtualBase); 238*c917cd62SIthamar R. Adema poolDeleter.Detach(); 239*c917cd62SIthamar R. Adema _pool = pool; 240*c917cd62SIthamar R. Adema return B_OK; 241*c917cd62SIthamar R. Adema } 242*c917cd62SIthamar R. Adema 243*c917cd62SIthamar R. Adema 244*c917cd62SIthamar R. Adema // #pragma mark - ARMPagingMethod32Bit 245*c917cd62SIthamar R. Adema 246*c917cd62SIthamar R. Adema 247*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::ARMPagingMethod32Bit() 248*c917cd62SIthamar R. Adema : 249*c917cd62SIthamar R. Adema fKernelPhysicalPageDirectory(0), 250*c917cd62SIthamar R. Adema fKernelVirtualPageDirectory(NULL), 251*c917cd62SIthamar R. Adema fPhysicalPageMapper(NULL), 252*c917cd62SIthamar R. Adema fKernelPhysicalPageMapper(NULL) 253*c917cd62SIthamar R. Adema { 254*c917cd62SIthamar R. Adema } 255*c917cd62SIthamar R. Adema 256*c917cd62SIthamar R. Adema 257*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::~ARMPagingMethod32Bit() 258*c917cd62SIthamar R. Adema { 259*c917cd62SIthamar R. Adema } 260*c917cd62SIthamar R. Adema 261*c917cd62SIthamar R. Adema 262*c917cd62SIthamar R. Adema status_t 263*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::Init(kernel_args* args, 264*c917cd62SIthamar R. Adema VMPhysicalPageMapper** _physicalPageMapper) 265*c917cd62SIthamar R. Adema { 266*c917cd62SIthamar R. Adema TRACE("vm_translation_map_init: entry\n"); 267*c917cd62SIthamar R. Adema 268*c917cd62SIthamar R. Adema fKernelPhysicalPageDirectory = args->arch_args.phys_pgdir; 269*c917cd62SIthamar R. Adema fKernelVirtualPageDirectory = (page_directory_entry*) 270*c917cd62SIthamar R. Adema args->arch_args.vir_pgdir; 271*c917cd62SIthamar R. Adema 272*c917cd62SIthamar R. Adema TRACE("page dir: %p (physical: %#" B_PRIx32 ")\n", 273*c917cd62SIthamar R. Adema fKernelVirtualPageDirectory, fKernelPhysicalPageDirectory); 274*c917cd62SIthamar R. Adema 275*c917cd62SIthamar R. Adema ARMPagingStructures32Bit::StaticInit(); 276*c917cd62SIthamar R. Adema 277*c917cd62SIthamar R. Adema // create the initial pool for the physical page mapper 278*c917cd62SIthamar R. Adema PhysicalPageSlotPool* pool 279*c917cd62SIthamar R. Adema = new(&PhysicalPageSlotPool::sInitialPhysicalPagePool) 280*c917cd62SIthamar R. Adema PhysicalPageSlotPool; 281*c917cd62SIthamar R. Adema status_t error = pool->InitInitial(args); 282*c917cd62SIthamar R. Adema if (error != B_OK) { 283*c917cd62SIthamar R. Adema panic("ARMPagingMethod32Bit::Init(): Failed to create initial pool " 284*c917cd62SIthamar R. Adema "for physical page mapper!"); 285*c917cd62SIthamar R. Adema return error; 286*c917cd62SIthamar R. Adema } 287*c917cd62SIthamar R. Adema 288*c917cd62SIthamar R. Adema // create physical page mapper 289*c917cd62SIthamar R. Adema large_memory_physical_page_ops_init(args, pool, fPhysicalPageMapper, 290*c917cd62SIthamar R. Adema fKernelPhysicalPageMapper); 291*c917cd62SIthamar R. Adema // TODO: Select the best page mapper! 292*c917cd62SIthamar R. Adema 293*c917cd62SIthamar R. Adema // enable global page feature if available 294*c917cd62SIthamar R. Adema #if 0 //IRA: check for ARMv6!! 295*c917cd62SIthamar R. Adema if (x86_check_feature(IA32_FEATURE_PGE, FEATURE_COMMON)) { 296*c917cd62SIthamar R. Adema // this prevents kernel pages from being flushed from TLB on 297*c917cd62SIthamar R. Adema // context-switch 298*c917cd62SIthamar R. Adema x86_write_cr4(x86_read_cr4() | IA32_CR4_GLOBAL_PAGES); 299*c917cd62SIthamar R. Adema } 300*c917cd62SIthamar R. Adema #endif 301*c917cd62SIthamar R. Adema TRACE("vm_translation_map_init: done\n"); 302*c917cd62SIthamar R. Adema 303*c917cd62SIthamar R. Adema *_physicalPageMapper = fPhysicalPageMapper; 304*c917cd62SIthamar R. Adema return B_OK; 305*c917cd62SIthamar R. Adema } 306*c917cd62SIthamar R. Adema 307*c917cd62SIthamar R. Adema 308*c917cd62SIthamar R. Adema status_t 309*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::InitPostArea(kernel_args* args) 310*c917cd62SIthamar R. Adema { 311*c917cd62SIthamar R. Adema void *temp; 312*c917cd62SIthamar R. Adema status_t error; 313*c917cd62SIthamar R. Adema area_id area; 314*c917cd62SIthamar R. Adema 315*c917cd62SIthamar R. Adema temp = (void*)fKernelVirtualPageDirectory; 316*c917cd62SIthamar R. Adema area = create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, MMU_L1_TABLE_SIZE, 317*c917cd62SIthamar R. Adema B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 318*c917cd62SIthamar R. Adema if (area < B_OK) 319*c917cd62SIthamar R. Adema return area; 320*c917cd62SIthamar R. Adema 321*c917cd62SIthamar R. Adema error = PhysicalPageSlotPool::sInitialPhysicalPagePool 322*c917cd62SIthamar R. Adema .InitInitialPostArea(args); 323*c917cd62SIthamar R. Adema if (error != B_OK) 324*c917cd62SIthamar R. Adema return error; 325*c917cd62SIthamar R. Adema 326*c917cd62SIthamar R. Adema return B_OK; 327*c917cd62SIthamar R. Adema } 328*c917cd62SIthamar R. Adema 329*c917cd62SIthamar R. Adema 330*c917cd62SIthamar R. Adema status_t 331*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::CreateTranslationMap(bool kernel, VMTranslationMap** _map) 332*c917cd62SIthamar R. Adema { 333*c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit* map = new(std::nothrow) ARMVMTranslationMap32Bit; 334*c917cd62SIthamar R. Adema if (map == NULL) 335*c917cd62SIthamar R. Adema return B_NO_MEMORY; 336*c917cd62SIthamar R. Adema 337*c917cd62SIthamar R. Adema status_t error = map->Init(kernel); 338*c917cd62SIthamar R. Adema if (error != B_OK) { 339*c917cd62SIthamar R. Adema delete map; 340*c917cd62SIthamar R. Adema return error; 341*c917cd62SIthamar R. Adema } 342*c917cd62SIthamar R. Adema 343*c917cd62SIthamar R. Adema *_map = map; 344*c917cd62SIthamar R. Adema return B_OK; 345*c917cd62SIthamar R. Adema } 346*c917cd62SIthamar R. Adema 347*c917cd62SIthamar R. Adema 348*c917cd62SIthamar R. Adema status_t 349*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress, 350*c917cd62SIthamar R. Adema phys_addr_t physicalAddress, uint8 attributes, 351*c917cd62SIthamar R. Adema phys_addr_t (*get_free_page)(kernel_args*)) 352*c917cd62SIthamar R. Adema { 353*c917cd62SIthamar R. Adema // check to see if a page table exists for this range 354*c917cd62SIthamar R. Adema int index = VADDR_TO_PDENT(virtualAddress); 355*c917cd62SIthamar R. Adema if ((fKernelVirtualPageDirectory[index] & ARM_PDE_TYPE_MASK) == 0) { 356*c917cd62SIthamar R. Adema phys_addr_t pgtable; 357*c917cd62SIthamar R. Adema page_directory_entry *e; 358*c917cd62SIthamar R. Adema // we need to allocate a pgtable 359*c917cd62SIthamar R. Adema pgtable = get_free_page(args); 360*c917cd62SIthamar R. Adema // pgtable is in pages, convert to physical address 361*c917cd62SIthamar R. Adema pgtable *= B_PAGE_SIZE; 362*c917cd62SIthamar R. Adema 363*c917cd62SIthamar R. Adema TRACE("ARMPagingMethod32Bit::MapEarly(): asked for free page for " 364*c917cd62SIthamar R. Adema "pgtable. %#" B_PRIxPHYSADDR "\n", pgtable); 365*c917cd62SIthamar R. Adema 366*c917cd62SIthamar R. Adema // put it in the pgdir 367*c917cd62SIthamar R. Adema e = &fKernelVirtualPageDirectory[index]; 368*c917cd62SIthamar R. Adema PutPageTableInPageDir(e, pgtable, attributes); 369*c917cd62SIthamar R. Adema 370*c917cd62SIthamar R. Adema // zero it out in it's new mapping 371*c917cd62SIthamar R. Adema memset((void*)pgtable, 0, B_PAGE_SIZE); 372*c917cd62SIthamar R. Adema } 373*c917cd62SIthamar R. Adema 374*c917cd62SIthamar R. Adema page_table_entry *ptEntry = (page_table_entry*) 375*c917cd62SIthamar R. Adema (fKernelVirtualPageDirectory[index] & ARM_PDE_ADDRESS_MASK); 376*c917cd62SIthamar R. Adema ptEntry += VADDR_TO_PTENT(virtualAddress); 377*c917cd62SIthamar R. Adema 378*c917cd62SIthamar R. Adema ASSERT_PRINT( 379*c917cd62SIthamar R. Adema (*ptEntry & ARM_PTE_TYPE_MASK) == 0, 380*c917cd62SIthamar R. Adema "virtual address: %#" B_PRIxADDR ", pde: %#" B_PRIx32 381*c917cd62SIthamar R. Adema ", existing pte: %#" B_PRIx32, virtualAddress, fKernelVirtualPageDirectory[index], 382*c917cd62SIthamar R. Adema *ptEntry); 383*c917cd62SIthamar R. Adema 384*c917cd62SIthamar R. Adema // now, fill in the pentry 385*c917cd62SIthamar R. Adema PutPageTableEntryInTable(ptEntry, 386*c917cd62SIthamar R. Adema physicalAddress, attributes, 0, IS_KERNEL_ADDRESS(virtualAddress)); 387*c917cd62SIthamar R. Adema 388*c917cd62SIthamar R. Adema return B_OK; 389*c917cd62SIthamar R. Adema } 390*c917cd62SIthamar R. Adema 391*c917cd62SIthamar R. Adema 392*c917cd62SIthamar R. Adema bool 393*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::IsKernelPageAccessible(addr_t virtualAddress, 394*c917cd62SIthamar R. Adema uint32 protection) 395*c917cd62SIthamar R. Adema { 396*c917cd62SIthamar R. Adema #if 0 397*c917cd62SIthamar R. Adema // We only trust the kernel team's page directory. So switch to it first. 398*c917cd62SIthamar R. Adema // Always set it to make sure the TLBs don't contain obsolete data. 399*c917cd62SIthamar R. Adema uint32 physicalPageDirectory; 400*c917cd62SIthamar R. Adema read_cr3(physicalPageDirectory); 401*c917cd62SIthamar R. Adema write_cr3(fKernelPhysicalPageDirectory); 402*c917cd62SIthamar R. Adema 403*c917cd62SIthamar R. Adema // get the page directory entry for the address 404*c917cd62SIthamar R. Adema page_directory_entry pageDirectoryEntry; 405*c917cd62SIthamar R. Adema uint32 index = VADDR_TO_PDENT(virtualAddress); 406*c917cd62SIthamar R. Adema 407*c917cd62SIthamar R. Adema if (physicalPageDirectory == fKernelPhysicalPageDirectory) { 408*c917cd62SIthamar R. Adema pageDirectoryEntry = fKernelVirtualPageDirectory[index]; 409*c917cd62SIthamar R. Adema } else if (fPhysicalPageMapper != NULL) { 410*c917cd62SIthamar R. Adema // map the original page directory and get the entry 411*c917cd62SIthamar R. Adema void* handle; 412*c917cd62SIthamar R. Adema addr_t virtualPageDirectory; 413*c917cd62SIthamar R. Adema status_t error = fPhysicalPageMapper->GetPageDebug( 414*c917cd62SIthamar R. Adema physicalPageDirectory, &virtualPageDirectory, &handle); 415*c917cd62SIthamar R. Adema if (error == B_OK) { 416*c917cd62SIthamar R. Adema pageDirectoryEntry 417*c917cd62SIthamar R. Adema = ((page_directory_entry*)virtualPageDirectory)[index]; 418*c917cd62SIthamar R. Adema fPhysicalPageMapper->PutPageDebug(virtualPageDirectory, handle); 419*c917cd62SIthamar R. Adema } else 420*c917cd62SIthamar R. Adema pageDirectoryEntry = 0; 421*c917cd62SIthamar R. Adema } else 422*c917cd62SIthamar R. Adema pageDirectoryEntry = 0; 423*c917cd62SIthamar R. Adema 424*c917cd62SIthamar R. Adema // map the page table and get the entry 425*c917cd62SIthamar R. Adema page_table_entry pageTableEntry; 426*c917cd62SIthamar R. Adema index = VADDR_TO_PTENT(virtualAddress); 427*c917cd62SIthamar R. Adema 428*c917cd62SIthamar R. Adema if ((pageDirectoryEntry & ARM_PDE_PRESENT) != 0 429*c917cd62SIthamar R. Adema && fPhysicalPageMapper != NULL) { 430*c917cd62SIthamar R. Adema void* handle; 431*c917cd62SIthamar R. Adema addr_t virtualPageTable; 432*c917cd62SIthamar R. Adema status_t error = fPhysicalPageMapper->GetPageDebug( 433*c917cd62SIthamar R. Adema pageDirectoryEntry & ARM_PDE_ADDRESS_MASK, &virtualPageTable, 434*c917cd62SIthamar R. Adema &handle); 435*c917cd62SIthamar R. Adema if (error == B_OK) { 436*c917cd62SIthamar R. Adema pageTableEntry = ((page_table_entry*)virtualPageTable)[index]; 437*c917cd62SIthamar R. Adema fPhysicalPageMapper->PutPageDebug(virtualPageTable, handle); 438*c917cd62SIthamar R. Adema } else 439*c917cd62SIthamar R. Adema pageTableEntry = 0; 440*c917cd62SIthamar R. Adema } else 441*c917cd62SIthamar R. Adema pageTableEntry = 0; 442*c917cd62SIthamar R. Adema 443*c917cd62SIthamar R. Adema // switch back to the original page directory 444*c917cd62SIthamar R. Adema if (physicalPageDirectory != fKernelPhysicalPageDirectory) 445*c917cd62SIthamar R. Adema write_cr3(physicalPageDirectory); 446*c917cd62SIthamar R. Adema 447*c917cd62SIthamar R. Adema if ((pageTableEntry & ARM_PTE_PRESENT) == 0) 448*c917cd62SIthamar R. Adema return false; 449*c917cd62SIthamar R. Adema 450*c917cd62SIthamar R. Adema // present means kernel-readable, so check for writable 451*c917cd62SIthamar R. Adema return (protection & B_KERNEL_WRITE_AREA) == 0 452*c917cd62SIthamar R. Adema || (pageTableEntry & ARM_PTE_WRITABLE) != 0; 453*c917cd62SIthamar R. Adema #endif 454*c917cd62SIthamar R. Adema //IRA: fix the above! 455*c917cd62SIthamar R. Adema return true; 456*c917cd62SIthamar R. Adema } 457*c917cd62SIthamar R. Adema 458*c917cd62SIthamar R. Adema 459*c917cd62SIthamar R. Adema /*static*/ void 460*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PutPageTableInPageDir(page_directory_entry* entry, 461*c917cd62SIthamar R. Adema phys_addr_t pgtablePhysical, uint32 attributes) 462*c917cd62SIthamar R. Adema { 463*c917cd62SIthamar R. Adema *entry = (pgtablePhysical & ARM_PDE_ADDRESS_MASK) 464*c917cd62SIthamar R. Adema | ARM_PDE_TYPE_COARSE_L2_PAGE_TABLE; 465*c917cd62SIthamar R. Adema // TODO: we ignore the attributes of the page table - for compatibility 466*c917cd62SIthamar R. Adema // with BeOS we allow having user accessible areas in the kernel address 467*c917cd62SIthamar R. Adema // space. This is currently being used by some drivers, mainly for the 468*c917cd62SIthamar R. Adema // frame buffer. Our current real time data implementation makes use of 469*c917cd62SIthamar R. Adema // this fact, too. 470*c917cd62SIthamar R. Adema // We might want to get rid of this possibility one day, especially if 471*c917cd62SIthamar R. Adema // we intend to port it to a platform that does not support this. 472*c917cd62SIthamar R. Adema } 473*c917cd62SIthamar R. Adema 474*c917cd62SIthamar R. Adema 475*c917cd62SIthamar R. Adema /*static*/ void 476*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PutPageTableEntryInTable(page_table_entry* entry, 477*c917cd62SIthamar R. Adema phys_addr_t physicalAddress, uint32 attributes, uint32 memoryType, 478*c917cd62SIthamar R. Adema bool globalPage) 479*c917cd62SIthamar R. Adema { 480*c917cd62SIthamar R. Adema page_table_entry page = (physicalAddress & ARM_PTE_ADDRESS_MASK) 481*c917cd62SIthamar R. Adema | ARM_PTE_TYPE_SMALL_PAGE; 482*c917cd62SIthamar R. Adema #if 0 //IRA 483*c917cd62SIthamar R. Adema | ARM_PTE_PRESENT | (globalPage ? ARM_PTE_GLOBAL : 0) 484*c917cd62SIthamar R. Adema | MemoryTypeToPageTableEntryFlags(memoryType); 485*c917cd62SIthamar R. Adema 486*c917cd62SIthamar R. Adema // if the page is user accessible, it's automatically 487*c917cd62SIthamar R. Adema // accessible in kernel space, too (but with the same 488*c917cd62SIthamar R. Adema // protection) 489*c917cd62SIthamar R. Adema if ((attributes & B_USER_PROTECTION) != 0) { 490*c917cd62SIthamar R. Adema page |= ARM_PTE_USER; 491*c917cd62SIthamar R. Adema if ((attributes & B_WRITE_AREA) != 0) 492*c917cd62SIthamar R. Adema page |= ARM_PTE_WRITABLE; 493*c917cd62SIthamar R. Adema } else if ((attributes & B_KERNEL_WRITE_AREA) != 0) 494*c917cd62SIthamar R. Adema page |= ARM_PTE_WRITABLE; 495*c917cd62SIthamar R. Adema #endif 496*c917cd62SIthamar R. Adema // put it in the page table 497*c917cd62SIthamar R. Adema *(volatile page_table_entry*)entry = page; 498*c917cd62SIthamar R. Adema } 499*c917cd62SIthamar R. Adema 500*c917cd62SIthamar R. Adema 501*c917cd62SIthamar R. Adema /*static*/ void 502*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::_EarlyPreparePageTables(page_table_entry* pageTables, 503*c917cd62SIthamar R. Adema addr_t address, size_t size) 504*c917cd62SIthamar R. Adema { 505*c917cd62SIthamar R. Adema ARMPagingMethod32Bit* method = ARMPagingMethod32Bit::Method(); 506*c917cd62SIthamar R. Adema memset(pageTables, 0, 256 * (size / (B_PAGE_SIZE * 256))); 507*c917cd62SIthamar R. Adema 508*c917cd62SIthamar R. Adema // put the array of pgtables directly into the kernel pagedir 509*c917cd62SIthamar R. Adema // these will be wired and kept mapped into virtual space to be easy to get 510*c917cd62SIthamar R. Adema // to 511*c917cd62SIthamar R. Adema { 512*c917cd62SIthamar R. Adema addr_t virtualTable = (addr_t)pageTables; 513*c917cd62SIthamar R. Adema 514*c917cd62SIthamar R. Adema for (size_t i = 0; i < (size / (B_PAGE_SIZE * 256)); 515*c917cd62SIthamar R. Adema i++, virtualTable += 256*sizeof(page_directory_entry)) { 516*c917cd62SIthamar R. Adema phys_addr_t physicalTable = 0; 517*c917cd62SIthamar R. Adema _EarlyQuery(virtualTable, &physicalTable); 518*c917cd62SIthamar R. Adema page_directory_entry* entry = method->KernelVirtualPageDirectory() 519*c917cd62SIthamar R. Adema + VADDR_TO_PDENT(address) + i; 520*c917cd62SIthamar R. Adema PutPageTableInPageDir(entry, physicalTable, 521*c917cd62SIthamar R. Adema B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 522*c917cd62SIthamar R. Adema } 523*c917cd62SIthamar R. Adema } 524*c917cd62SIthamar R. Adema } 525*c917cd62SIthamar R. Adema 526*c917cd62SIthamar R. Adema 527*c917cd62SIthamar R. Adema //! TODO: currently assumes this translation map is active 528*c917cd62SIthamar R. Adema /*static*/ status_t 529*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::_EarlyQuery(addr_t virtualAddress, 530*c917cd62SIthamar R. Adema phys_addr_t *_physicalAddress) 531*c917cd62SIthamar R. Adema { 532*c917cd62SIthamar R. Adema ARMPagingMethod32Bit* method = ARMPagingMethod32Bit::Method(); 533*c917cd62SIthamar R. Adema int index = VADDR_TO_PDENT(virtualAddress); 534*c917cd62SIthamar R. Adema if ((method->KernelVirtualPageDirectory()[index] & ARM_PDE_TYPE_MASK) == 0) { 535*c917cd62SIthamar R. Adema // no pagetable here 536*c917cd62SIthamar R. Adema return B_ERROR; 537*c917cd62SIthamar R. Adema } 538*c917cd62SIthamar R. Adema 539*c917cd62SIthamar R. Adema page_table_entry* entry = (page_table_entry*) 540*c917cd62SIthamar R. Adema (method->KernelVirtualPageDirectory()[index] & ARM_PDE_ADDRESS_MASK); 541*c917cd62SIthamar R. Adema entry += VADDR_TO_PTENT(virtualAddress); 542*c917cd62SIthamar R. Adema 543*c917cd62SIthamar R. Adema if ((*entry & ARM_PTE_TYPE_MASK) == 0) { 544*c917cd62SIthamar R. Adema // page mapping not valid 545*c917cd62SIthamar R. Adema return B_ERROR; 546*c917cd62SIthamar R. Adema } 547*c917cd62SIthamar R. Adema 548*c917cd62SIthamar R. Adema *_physicalAddress = (*entry & ARM_PTE_ADDRESS_MASK) 549*c917cd62SIthamar R. Adema | VADDR_TO_PGOFF(virtualAddress); 550*c917cd62SIthamar R. Adema 551*c917cd62SIthamar R. Adema return B_OK; 552*c917cd62SIthamar R. Adema } 553