1*62caef87SFrançois Revol /* 2*62caef87SFrançois Revol * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3*62caef87SFrançois Revol * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 4*62caef87SFrançois Revol * Distributed under the terms of the MIT License. 5*62caef87SFrançois Revol * 6*62caef87SFrançois Revol * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7*62caef87SFrançois Revol * Distributed under the terms of the NewOS License. 8*62caef87SFrançois Revol */ 9*62caef87SFrançois Revol 10*62caef87SFrançois Revol /* (bonefish) Some explanatory words on how address translation is implemented 11*62caef87SFrançois Revol for the 32 bit PPC architecture. 12*62caef87SFrançois Revol 13*62caef87SFrançois Revol I use the address type nomenclature as used in the PPC architecture 14*62caef87SFrançois Revol specs, i.e. 15*62caef87SFrançois Revol - effective address: An address as used by program instructions, i.e. 16*62caef87SFrançois Revol that's what elsewhere (e.g. in the VM implementation) is called 17*62caef87SFrançois Revol virtual address. 18*62caef87SFrançois Revol - virtual address: An intermediate address computed from the effective 19*62caef87SFrançois Revol address via the segment registers. 20*62caef87SFrançois Revol - physical address: An address referring to physical storage. 21*62caef87SFrançois Revol 22*62caef87SFrançois Revol The hardware translates an effective address to a physical address using 23*62caef87SFrançois Revol either of two mechanisms: 1) Block Address Translation (BAT) or 24*62caef87SFrançois Revol 2) segment + page translation. The first mechanism does this directly 25*62caef87SFrançois Revol using two sets (for data/instructions) of special purpose registers. 26*62caef87SFrançois Revol The latter mechanism is of more relevance here, though: 27*62caef87SFrançois Revol 28*62caef87SFrançois Revol effective address (32 bit): [ 0 ESID 3 | 4 PIX 19 | 20 Byte 31 ] 29*62caef87SFrançois Revol | | | 30*62caef87SFrançois Revol (segment registers) | | 31*62caef87SFrançois Revol | | | 32*62caef87SFrançois Revol virtual address (52 bit): [ 0 VSID 23 | 24 PIX 39 | 40 Byte 51 ] 33*62caef87SFrançois Revol [ 0 VPN 39 | 40 Byte 51 ] 34*62caef87SFrançois Revol | | 35*62caef87SFrançois Revol (page table) | 36*62caef87SFrançois Revol | | 37*62caef87SFrançois Revol physical address (32 bit): [ 0 PPN 19 | 20 Byte 31 ] 38*62caef87SFrançois Revol 39*62caef87SFrançois Revol 40*62caef87SFrançois Revol ESID: Effective Segment ID 41*62caef87SFrançois Revol VSID: Virtual Segment ID 42*62caef87SFrançois Revol PIX: Page Index 43*62caef87SFrançois Revol VPN: Virtual Page Number 44*62caef87SFrançois Revol PPN: Physical Page Number 45*62caef87SFrançois Revol 46*62caef87SFrançois Revol 47*62caef87SFrançois Revol Unlike on x86 we can't just switch the context to another team by just 48*62caef87SFrançois Revol setting a register to another page directory, since we only have one 49*62caef87SFrançois Revol page table containing both kernel and user address mappings. Instead we 50*62caef87SFrançois Revol map the effective address space of kernel and *all* teams 51*62caef87SFrançois Revol non-intersectingly into the virtual address space (which fortunately is 52*62caef87SFrançois Revol 20 bits wider), and use the segment registers to select the section of 53*62caef87SFrançois Revol the virtual address space for the current team. Half of the 16 segment 54*62caef87SFrançois Revol registers (8 - 15) map the kernel addresses, so they remain unchanged. 55*62caef87SFrançois Revol 56*62caef87SFrançois Revol The range of the virtual address space a team's effective address space 57*62caef87SFrançois Revol is mapped to is defined by its PPCVMTranslationMap::fVSIDBase, 58*62caef87SFrançois Revol which is the first of the 8 successive VSID values used for the team. 59*62caef87SFrançois Revol 60*62caef87SFrançois Revol Which fVSIDBase values are already taken is defined by the set bits in 61*62caef87SFrançois Revol the bitmap sVSIDBaseBitmap. 62*62caef87SFrançois Revol 63*62caef87SFrançois Revol 64*62caef87SFrançois Revol TODO: 65*62caef87SFrançois Revol * If we want to continue to use the OF services, we would need to add 66*62caef87SFrançois Revol its address mappings to the kernel space. Unfortunately some stuff 67*62caef87SFrançois Revol (especially RAM) is mapped in an address range without the kernel 68*62caef87SFrançois Revol address space. We probably need to map those into each team's address 69*62caef87SFrançois Revol space as kernel read/write areas. 70*62caef87SFrançois Revol * The current locking scheme is insufficient. The page table is a resource 71*62caef87SFrançois Revol shared by all teams. We need to synchronize access to it. Probably via a 72*62caef87SFrançois Revol spinlock. 73*62caef87SFrançois Revol */ 74*62caef87SFrançois Revol 75*62caef87SFrançois Revol #include "paging/classic/PPCVMTranslationMapClassic.h" 76*62caef87SFrançois Revol 77*62caef87SFrançois Revol #include <stdlib.h> 78*62caef87SFrançois Revol #include <string.h> 79*62caef87SFrançois Revol 80*62caef87SFrançois Revol #include <arch/cpu.h> 81*62caef87SFrançois Revol #include <arch_mmu.h> 82*62caef87SFrançois Revol #include <int.h> 83*62caef87SFrançois Revol #include <thread.h> 84*62caef87SFrançois Revol #include <slab/Slab.h> 85*62caef87SFrançois Revol #include <smp.h> 86*62caef87SFrançois Revol #include <util/AutoLock.h> 87*62caef87SFrançois Revol #include <util/queue.h> 88*62caef87SFrançois Revol #include <vm/vm_page.h> 89*62caef87SFrançois Revol #include <vm/vm_priv.h> 90*62caef87SFrançois Revol #include <vm/VMAddressSpace.h> 91*62caef87SFrançois Revol #include <vm/VMCache.h> 92*62caef87SFrançois Revol 93*62caef87SFrançois Revol #include "paging/classic/PPCPagingMethodClassic.h" 94*62caef87SFrançois Revol #include "paging/classic/PPCPagingStructuresClassic.h" 95*62caef87SFrançois Revol #include "generic_vm_physical_page_mapper.h" 96*62caef87SFrançois Revol #include "generic_vm_physical_page_ops.h" 97*62caef87SFrançois Revol #include "GenericVMPhysicalPageMapper.h" 98*62caef87SFrançois Revol 99*62caef87SFrançois Revol 100*62caef87SFrançois Revol //#define TRACE_PPC_VM_TRANSLATION_MAP_CLASSIC 101*62caef87SFrançois Revol #ifdef TRACE_PPC_VM_TRANSLATION_MAP_CLASSIC 102*62caef87SFrançois Revol # define TRACE(x...) dprintf(x) 103*62caef87SFrançois Revol #else 104*62caef87SFrançois Revol # define TRACE(x...) ; 105*62caef87SFrançois Revol #endif 106*62caef87SFrançois Revol 107*62caef87SFrançois Revol 108*62caef87SFrançois Revol // The VSID is a 24 bit number. The lower three bits are defined by the 109*62caef87SFrançois Revol // (effective) segment number, which leaves us with a 21 bit space of 110*62caef87SFrançois Revol // VSID bases (= 2 * 1024 * 1024). 111*62caef87SFrançois Revol #define MAX_VSID_BASES (PAGE_SIZE * 8) 112*62caef87SFrançois Revol static uint32 sVSIDBaseBitmap[MAX_VSID_BASES / (sizeof(uint32) * 8)]; 113*62caef87SFrançois Revol static spinlock sVSIDBaseBitmapLock; 114*62caef87SFrançois Revol 115*62caef87SFrançois Revol #define VSID_BASE_SHIFT 3 116*62caef87SFrançois Revol #define VADDR_TO_VSID(vsidBase, vaddr) (vsidBase + ((vaddr) >> 28)) 117*62caef87SFrançois Revol 118*62caef87SFrançois Revol 119*62caef87SFrançois Revol // #pragma mark - 120*62caef87SFrançois Revol 121*62caef87SFrançois Revol 122*62caef87SFrançois Revol PPCVMTranslationMapClassic::PPCVMTranslationMapClassic() 123*62caef87SFrançois Revol : 124*62caef87SFrançois Revol fPagingStructures(NULL) 125*62caef87SFrançois Revol { 126*62caef87SFrançois Revol } 127*62caef87SFrançois Revol 128*62caef87SFrançois Revol 129*62caef87SFrançois Revol PPCVMTranslationMapClassic::~PPCVMTranslationMapClassic() 130*62caef87SFrançois Revol { 131*62caef87SFrançois Revol if (fPagingStructures == NULL) 132*62caef87SFrançois Revol return; 133*62caef87SFrançois Revol 134*62caef87SFrançois Revol #if 0//X86 135*62caef87SFrançois Revol if (fPageMapper != NULL) 136*62caef87SFrançois Revol fPageMapper->Delete(); 137*62caef87SFrançois Revol #endif 138*62caef87SFrançois Revol 139*62caef87SFrançois Revol if (fMapCount > 0) { 140*62caef87SFrançois Revol panic("vm_translation_map.destroy_tmap: map %p has positive map count %ld\n", 141*62caef87SFrançois Revol this, fMapCount); 142*62caef87SFrançois Revol } 143*62caef87SFrançois Revol 144*62caef87SFrançois Revol // mark the vsid base not in use 145*62caef87SFrançois Revol int baseBit = fVSIDBase >> VSID_BASE_SHIFT; 146*62caef87SFrançois Revol atomic_and((int32 *)&sVSIDBaseBitmap[baseBit / 32], 147*62caef87SFrançois Revol ~(1 << (baseBit % 32))); 148*62caef87SFrançois Revol 149*62caef87SFrançois Revol #if 0//X86 150*62caef87SFrançois Revol if (fPagingStructures->pgdir_virt != NULL) { 151*62caef87SFrançois Revol // cycle through and free all of the user space pgtables 152*62caef87SFrançois Revol for (uint32 i = VADDR_TO_PDENT(USER_BASE); 153*62caef87SFrançois Revol i <= VADDR_TO_PDENT(USER_BASE + (USER_SIZE - 1)); i++) { 154*62caef87SFrançois Revol if ((fPagingStructures->pgdir_virt[i] & PPC_PDE_PRESENT) != 0) { 155*62caef87SFrançois Revol addr_t address = fPagingStructures->pgdir_virt[i] 156*62caef87SFrançois Revol & PPC_PDE_ADDRESS_MASK; 157*62caef87SFrançois Revol vm_page* page = vm_lookup_page(address / B_PAGE_SIZE); 158*62caef87SFrançois Revol if (!page) 159*62caef87SFrançois Revol panic("destroy_tmap: didn't find pgtable page\n"); 160*62caef87SFrançois Revol DEBUG_PAGE_ACCESS_START(page); 161*62caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_FREE); 162*62caef87SFrançois Revol } 163*62caef87SFrançois Revol } 164*62caef87SFrançois Revol } 165*62caef87SFrançois Revol #endif 166*62caef87SFrançois Revol 167*62caef87SFrançois Revol fPagingStructures->RemoveReference(); 168*62caef87SFrançois Revol } 169*62caef87SFrançois Revol 170*62caef87SFrançois Revol 171*62caef87SFrançois Revol status_t 172*62caef87SFrançois Revol PPCVMTranslationMapClassic::Init(bool kernel) 173*62caef87SFrançois Revol { 174*62caef87SFrançois Revol TRACE("PPCVMTranslationMapClassic::Init()\n"); 175*62caef87SFrançois Revol 176*62caef87SFrançois Revol PPCVMTranslationMap::Init(kernel); 177*62caef87SFrançois Revol 178*62caef87SFrançois Revol cpu_status state = disable_interrupts(); 179*62caef87SFrançois Revol acquire_spinlock(&sVSIDBaseBitmapLock); 180*62caef87SFrançois Revol 181*62caef87SFrançois Revol // allocate a VSID base for this one 182*62caef87SFrançois Revol if (kernel) { 183*62caef87SFrançois Revol // The boot loader has set up the segment registers for identical 184*62caef87SFrançois Revol // mapping. Two VSID bases are reserved for the kernel: 0 and 8. The 185*62caef87SFrançois Revol // latter one for mapping the kernel address space (0x80000000...), the 186*62caef87SFrançois Revol // former one for the lower addresses required by the Open Firmware 187*62caef87SFrançois Revol // services. 188*62caef87SFrançois Revol fVSIDBase = 0; 189*62caef87SFrançois Revol sVSIDBaseBitmap[0] |= 0x3; 190*62caef87SFrançois Revol } else { 191*62caef87SFrançois Revol int i = 0; 192*62caef87SFrançois Revol 193*62caef87SFrançois Revol while (i < MAX_VSID_BASES) { 194*62caef87SFrançois Revol if (sVSIDBaseBitmap[i / 32] == 0xffffffff) { 195*62caef87SFrançois Revol i += 32; 196*62caef87SFrançois Revol continue; 197*62caef87SFrançois Revol } 198*62caef87SFrançois Revol if ((sVSIDBaseBitmap[i / 32] & (1 << (i % 32))) == 0) { 199*62caef87SFrançois Revol // we found it 200*62caef87SFrançois Revol sVSIDBaseBitmap[i / 32] |= 1 << (i % 32); 201*62caef87SFrançois Revol break; 202*62caef87SFrançois Revol } 203*62caef87SFrançois Revol i++; 204*62caef87SFrançois Revol } 205*62caef87SFrançois Revol if (i >= MAX_VSID_BASES) 206*62caef87SFrançois Revol panic("vm_translation_map_create: out of VSID bases\n"); 207*62caef87SFrançois Revol fVSIDBase = i << VSID_BASE_SHIFT; 208*62caef87SFrançois Revol } 209*62caef87SFrançois Revol 210*62caef87SFrançois Revol release_spinlock(&sVSIDBaseBitmapLock); 211*62caef87SFrançois Revol restore_interrupts(state); 212*62caef87SFrançois Revol 213*62caef87SFrançois Revol fPagingStructures = new(std::nothrow) PPCPagingStructuresClassic; 214*62caef87SFrançois Revol if (fPagingStructures == NULL) 215*62caef87SFrançois Revol return B_NO_MEMORY; 216*62caef87SFrançois Revol 217*62caef87SFrançois Revol PPCPagingMethodClassic* method = PPCPagingMethodClassic::Method(); 218*62caef87SFrançois Revol 219*62caef87SFrançois Revol if (!kernel) { 220*62caef87SFrançois Revol // user 221*62caef87SFrançois Revol #if 0//X86 222*62caef87SFrançois Revol // allocate a physical page mapper 223*62caef87SFrançois Revol status_t error = method->PhysicalPageMapper() 224*62caef87SFrançois Revol ->CreateTranslationMapPhysicalPageMapper(&fPageMapper); 225*62caef87SFrançois Revol if (error != B_OK) 226*62caef87SFrançois Revol return error; 227*62caef87SFrançois Revol #endif 228*62caef87SFrançois Revol #if 0//X86 229*62caef87SFrançois Revol // allocate the page directory 230*62caef87SFrançois Revol page_directory_entry* virtualPageDir = (page_directory_entry*)memalign( 231*62caef87SFrançois Revol B_PAGE_SIZE, B_PAGE_SIZE); 232*62caef87SFrançois Revol if (virtualPageDir == NULL) 233*62caef87SFrançois Revol return B_NO_MEMORY; 234*62caef87SFrançois Revol 235*62caef87SFrançois Revol // look up the page directory's physical address 236*62caef87SFrançois Revol phys_addr_t physicalPageDir; 237*62caef87SFrançois Revol vm_get_page_mapping(VMAddressSpace::KernelID(), 238*62caef87SFrançois Revol (addr_t)virtualPageDir, &physicalPageDir); 239*62caef87SFrançois Revol #endif 240*62caef87SFrançois Revol 241*62caef87SFrançois Revol fPagingStructures->Init(/*NULL, 0, 242*62caef87SFrançois Revol method->KernelVirtualPageDirectory()*/method->PageTable()); 243*62caef87SFrançois Revol } else { 244*62caef87SFrançois Revol // kernel 245*62caef87SFrançois Revol #if 0//X86 246*62caef87SFrançois Revol // get the physical page mapper 247*62caef87SFrançois Revol fPageMapper = method->KernelPhysicalPageMapper(); 248*62caef87SFrançois Revol #endif 249*62caef87SFrançois Revol 250*62caef87SFrançois Revol // we already know the kernel pgdir mapping 251*62caef87SFrançois Revol fPagingStructures->Init(/*method->KernelVirtualPageDirectory(), 252*62caef87SFrançois Revol method->KernelPhysicalPageDirectory(), NULL*/method->PageTable()); 253*62caef87SFrançois Revol } 254*62caef87SFrançois Revol 255*62caef87SFrançois Revol return B_OK; 256*62caef87SFrançois Revol } 257*62caef87SFrançois Revol 258*62caef87SFrançois Revol 259*62caef87SFrançois Revol void 260*62caef87SFrançois Revol PPCVMTranslationMapClassic::ChangeASID() 261*62caef87SFrançois Revol { 262*62caef87SFrançois Revol // this code depends on the kernel being at 0x80000000, fix if we change that 263*62caef87SFrançois Revol #if KERNEL_BASE != 0x80000000 264*62caef87SFrançois Revol #error fix me 265*62caef87SFrançois Revol #endif 266*62caef87SFrançois Revol int vsidBase = VSIDBase(); 267*62caef87SFrançois Revol 268*62caef87SFrançois Revol isync(); // synchronize context 269*62caef87SFrançois Revol asm("mtsr 0,%0" : : "g"(vsidBase)); 270*62caef87SFrançois Revol asm("mtsr 1,%0" : : "g"(vsidBase + 1)); 271*62caef87SFrançois Revol asm("mtsr 2,%0" : : "g"(vsidBase + 2)); 272*62caef87SFrançois Revol asm("mtsr 3,%0" : : "g"(vsidBase + 3)); 273*62caef87SFrançois Revol asm("mtsr 4,%0" : : "g"(vsidBase + 4)); 274*62caef87SFrançois Revol asm("mtsr 5,%0" : : "g"(vsidBase + 5)); 275*62caef87SFrançois Revol asm("mtsr 6,%0" : : "g"(vsidBase + 6)); 276*62caef87SFrançois Revol asm("mtsr 7,%0" : : "g"(vsidBase + 7)); 277*62caef87SFrançois Revol isync(); // synchronize context 278*62caef87SFrançois Revol } 279*62caef87SFrançois Revol 280*62caef87SFrançois Revol 281*62caef87SFrançois Revol page_table_entry * 282*62caef87SFrançois Revol PPCVMTranslationMapClassic::LookupPageTableEntry(addr_t virtualAddress) 283*62caef87SFrançois Revol { 284*62caef87SFrançois Revol // lookup the vsid based off the va 285*62caef87SFrançois Revol uint32 virtualSegmentID = VADDR_TO_VSID(fVSIDBase, virtualAddress); 286*62caef87SFrançois Revol 287*62caef87SFrançois Revol // dprintf("vm_translation_map.lookup_page_table_entry: vsid %ld, va 0x%lx\n", virtualSegmentID, virtualAddress); 288*62caef87SFrançois Revol 289*62caef87SFrançois Revol PPCPagingMethodClassic* m = PPCPagingMethodClassic::Method(); 290*62caef87SFrançois Revol 291*62caef87SFrançois Revol // Search for the page table entry using the primary hash value 292*62caef87SFrançois Revol 293*62caef87SFrançois Revol uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, virtualAddress); 294*62caef87SFrançois Revol page_table_entry_group *group = &(m->PageTable())[hash & m->PageTableHashMask()]; 295*62caef87SFrançois Revol 296*62caef87SFrançois Revol for (int i = 0; i < 8; i++) { 297*62caef87SFrançois Revol page_table_entry *entry = &group->entry[i]; 298*62caef87SFrançois Revol 299*62caef87SFrançois Revol if (entry->virtual_segment_id == virtualSegmentID 300*62caef87SFrançois Revol && entry->secondary_hash == false 301*62caef87SFrançois Revol && entry->abbr_page_index == ((virtualAddress >> 22) & 0x3f)) 302*62caef87SFrançois Revol return entry; 303*62caef87SFrançois Revol } 304*62caef87SFrançois Revol 305*62caef87SFrançois Revol // didn't find it, try the secondary hash value 306*62caef87SFrançois Revol 307*62caef87SFrançois Revol hash = page_table_entry::SecondaryHash(hash); 308*62caef87SFrançois Revol group = &(m->PageTable())[hash & m->PageTableHashMask()]; 309*62caef87SFrançois Revol 310*62caef87SFrançois Revol for (int i = 0; i < 8; i++) { 311*62caef87SFrançois Revol page_table_entry *entry = &group->entry[i]; 312*62caef87SFrançois Revol 313*62caef87SFrançois Revol if (entry->virtual_segment_id == virtualSegmentID 314*62caef87SFrançois Revol && entry->secondary_hash == true 315*62caef87SFrançois Revol && entry->abbr_page_index == ((virtualAddress >> 22) & 0x3f)) 316*62caef87SFrançois Revol return entry; 317*62caef87SFrançois Revol } 318*62caef87SFrançois Revol 319*62caef87SFrançois Revol return NULL; 320*62caef87SFrançois Revol } 321*62caef87SFrançois Revol 322*62caef87SFrançois Revol 323*62caef87SFrançois Revol bool 324*62caef87SFrançois Revol PPCVMTranslationMapClassic::RemovePageTableEntry(addr_t virtualAddress) 325*62caef87SFrançois Revol { 326*62caef87SFrançois Revol page_table_entry *entry = LookupPageTableEntry(virtualAddress); 327*62caef87SFrançois Revol if (entry == NULL) 328*62caef87SFrançois Revol return false; 329*62caef87SFrançois Revol 330*62caef87SFrançois Revol entry->valid = 0; 331*62caef87SFrançois Revol ppc_sync(); 332*62caef87SFrançois Revol tlbie(virtualAddress); 333*62caef87SFrançois Revol eieio(); 334*62caef87SFrançois Revol tlbsync(); 335*62caef87SFrançois Revol ppc_sync(); 336*62caef87SFrançois Revol 337*62caef87SFrançois Revol return true; 338*62caef87SFrançois Revol } 339*62caef87SFrançois Revol 340*62caef87SFrançois Revol 341*62caef87SFrançois Revol size_t 342*62caef87SFrançois Revol PPCVMTranslationMapClassic::MaxPagesNeededToMap(addr_t start, addr_t end) const 343*62caef87SFrançois Revol { 344*62caef87SFrançois Revol return 0; 345*62caef87SFrançois Revol } 346*62caef87SFrançois Revol 347*62caef87SFrançois Revol 348*62caef87SFrançois Revol status_t 349*62caef87SFrançois Revol PPCVMTranslationMapClassic::Map(addr_t virtualAddress, 350*62caef87SFrançois Revol phys_addr_t physicalAddress, uint32 attributes, 351*62caef87SFrançois Revol uint32 memoryType, vm_page_reservation* reservation) 352*62caef87SFrançois Revol { 353*62caef87SFrançois Revol TRACE("map_tmap: entry pa 0x%lx va 0x%lx\n", pa, va); 354*62caef87SFrançois Revol 355*62caef87SFrançois Revol // lookup the vsid based off the va 356*62caef87SFrançois Revol uint32 virtualSegmentID = VADDR_TO_VSID(fVSIDBase, virtualAddress); 357*62caef87SFrançois Revol uint32 protection = 0; 358*62caef87SFrançois Revol 359*62caef87SFrançois Revol // ToDo: check this 360*62caef87SFrançois Revol // all kernel mappings are R/W to supervisor code 361*62caef87SFrançois Revol if (attributes & (B_READ_AREA | B_WRITE_AREA)) 362*62caef87SFrançois Revol protection = (attributes & B_WRITE_AREA) ? PTE_READ_WRITE : PTE_READ_ONLY; 363*62caef87SFrançois Revol 364*62caef87SFrançois Revol //dprintf("vm_translation_map.map_tmap: vsid %d, pa 0x%lx, va 0x%lx\n", vsid, pa, va); 365*62caef87SFrançois Revol 366*62caef87SFrançois Revol PPCPagingMethodClassic* m = PPCPagingMethodClassic::Method(); 367*62caef87SFrançois Revol 368*62caef87SFrançois Revol // Search for a free page table slot using the primary hash value 369*62caef87SFrançois Revol uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, virtualAddress); 370*62caef87SFrançois Revol page_table_entry_group *group = &(m->PageTable())[hash & m->PageTableHashMask()]; 371*62caef87SFrançois Revol 372*62caef87SFrançois Revol for (int i = 0; i < 8; i++) { 373*62caef87SFrançois Revol page_table_entry *entry = &group->entry[i]; 374*62caef87SFrançois Revol 375*62caef87SFrançois Revol if (entry->valid) 376*62caef87SFrançois Revol continue; 377*62caef87SFrançois Revol 378*62caef87SFrançois Revol m->FillPageTableEntry(entry, virtualSegmentID, virtualAddress, 379*62caef87SFrançois Revol physicalAddress, protection, memoryType, false); 380*62caef87SFrançois Revol fMapCount++; 381*62caef87SFrançois Revol return B_OK; 382*62caef87SFrançois Revol } 383*62caef87SFrançois Revol 384*62caef87SFrançois Revol // Didn't found one, try the secondary hash value 385*62caef87SFrançois Revol 386*62caef87SFrançois Revol hash = page_table_entry::SecondaryHash(hash); 387*62caef87SFrançois Revol group = &(m->PageTable())[hash & m->PageTableHashMask()]; 388*62caef87SFrançois Revol 389*62caef87SFrançois Revol for (int i = 0; i < 8; i++) { 390*62caef87SFrançois Revol page_table_entry *entry = &group->entry[i]; 391*62caef87SFrançois Revol 392*62caef87SFrançois Revol if (entry->valid) 393*62caef87SFrançois Revol continue; 394*62caef87SFrançois Revol 395*62caef87SFrançois Revol m->FillPageTableEntry(entry, virtualSegmentID, virtualAddress, 396*62caef87SFrançois Revol physicalAddress, protection, memoryType, false); 397*62caef87SFrançois Revol fMapCount++; 398*62caef87SFrançois Revol return B_OK; 399*62caef87SFrançois Revol } 400*62caef87SFrançois Revol 401*62caef87SFrançois Revol panic("vm_translation_map.map_tmap: hash table full\n"); 402*62caef87SFrançois Revol return B_ERROR; 403*62caef87SFrançois Revol 404*62caef87SFrançois Revol #if 0//X86 405*62caef87SFrançois Revol /* 406*62caef87SFrançois Revol dprintf("pgdir at 0x%x\n", pgdir); 407*62caef87SFrançois Revol dprintf("index is %d\n", va / B_PAGE_SIZE / 1024); 408*62caef87SFrançois Revol dprintf("final at 0x%x\n", &pgdir[va / B_PAGE_SIZE / 1024]); 409*62caef87SFrançois Revol dprintf("value is 0x%x\n", *(int *)&pgdir[va / B_PAGE_SIZE / 1024]); 410*62caef87SFrançois Revol dprintf("present bit is %d\n", pgdir[va / B_PAGE_SIZE / 1024].present); 411*62caef87SFrançois Revol dprintf("addr is %d\n", pgdir[va / B_PAGE_SIZE / 1024].addr); 412*62caef87SFrançois Revol */ 413*62caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt; 414*62caef87SFrançois Revol 415*62caef87SFrançois Revol // check to see if a page table exists for this range 416*62caef87SFrançois Revol uint32 index = VADDR_TO_PDENT(va); 417*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 418*62caef87SFrançois Revol phys_addr_t pgtable; 419*62caef87SFrançois Revol vm_page *page; 420*62caef87SFrançois Revol 421*62caef87SFrançois Revol // we need to allocate a pgtable 422*62caef87SFrançois Revol page = vm_page_allocate_page(reservation, 423*62caef87SFrançois Revol PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR); 424*62caef87SFrançois Revol 425*62caef87SFrançois Revol DEBUG_PAGE_ACCESS_END(page); 426*62caef87SFrançois Revol 427*62caef87SFrançois Revol pgtable = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE; 428*62caef87SFrançois Revol 429*62caef87SFrançois Revol TRACE("map_tmap: asked for free page for pgtable. 0x%lx\n", pgtable); 430*62caef87SFrançois Revol 431*62caef87SFrançois Revol // put it in the pgdir 432*62caef87SFrançois Revol PPCPagingMethodClassic::PutPageTableInPageDir(&pd[index], pgtable, 433*62caef87SFrançois Revol attributes 434*62caef87SFrançois Revol | ((attributes & B_USER_PROTECTION) != 0 435*62caef87SFrançois Revol ? B_WRITE_AREA : B_KERNEL_WRITE_AREA)); 436*62caef87SFrançois Revol 437*62caef87SFrançois Revol // update any other page directories, if it maps kernel space 438*62caef87SFrançois Revol if (index >= FIRST_KERNEL_PGDIR_ENT 439*62caef87SFrançois Revol && index < (FIRST_KERNEL_PGDIR_ENT + NUM_KERNEL_PGDIR_ENTS)) { 440*62caef87SFrançois Revol PPCPagingStructuresClassic::UpdateAllPageDirs(index, pd[index]); 441*62caef87SFrançois Revol } 442*62caef87SFrançois Revol 443*62caef87SFrançois Revol fMapCount++; 444*62caef87SFrançois Revol } 445*62caef87SFrançois Revol 446*62caef87SFrançois Revol // now, fill in the pentry 447*62caef87SFrançois Revol Thread* thread = thread_get_current_thread(); 448*62caef87SFrançois Revol ThreadCPUPinner pinner(thread); 449*62caef87SFrançois Revol 450*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 451*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 452*62caef87SFrançois Revol index = VADDR_TO_PTENT(va); 453*62caef87SFrançois Revol 454*62caef87SFrançois Revol ASSERT_PRINT((pt[index] & PPC_PTE_PRESENT) == 0, 455*62caef87SFrançois Revol "virtual address: %#" B_PRIxADDR ", existing pte: %#" B_PRIx32, va, 456*62caef87SFrançois Revol pt[index]); 457*62caef87SFrançois Revol 458*62caef87SFrançois Revol PPCPagingMethodClassic::PutPageTableEntryInTable(&pt[index], pa, attributes, 459*62caef87SFrançois Revol memoryType, fIsKernelMap); 460*62caef87SFrançois Revol 461*62caef87SFrançois Revol pinner.Unlock(); 462*62caef87SFrançois Revol 463*62caef87SFrançois Revol // Note: We don't need to invalidate the TLB for this address, as previously 464*62caef87SFrançois Revol // the entry was not present and the TLB doesn't cache those entries. 465*62caef87SFrançois Revol 466*62caef87SFrançois Revol fMapCount++; 467*62caef87SFrançois Revol 468*62caef87SFrançois Revol return 0; 469*62caef87SFrançois Revol #endif 470*62caef87SFrançois Revol } 471*62caef87SFrançois Revol 472*62caef87SFrançois Revol 473*62caef87SFrançois Revol status_t 474*62caef87SFrançois Revol PPCVMTranslationMapClassic::Unmap(addr_t start, addr_t end) 475*62caef87SFrançois Revol { 476*62caef87SFrançois Revol page_table_entry *entry; 477*62caef87SFrançois Revol 478*62caef87SFrançois Revol start = ROUNDDOWN(start, B_PAGE_SIZE); 479*62caef87SFrançois Revol end = ROUNDUP(end, B_PAGE_SIZE); 480*62caef87SFrançois Revol 481*62caef87SFrançois Revol if (start >= end) 482*62caef87SFrançois Revol return B_OK; 483*62caef87SFrançois Revol 484*62caef87SFrançois Revol TRACE("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end); 485*62caef87SFrançois Revol 486*62caef87SFrançois Revol // dprintf("vm_translation_map.unmap_tmap: start 0x%lx, end 0x%lx\n", start, end); 487*62caef87SFrançois Revol 488*62caef87SFrançois Revol while (start < end) { 489*62caef87SFrançois Revol if (RemovePageTableEntry(start)) 490*62caef87SFrançois Revol fMapCount--; 491*62caef87SFrançois Revol 492*62caef87SFrançois Revol start += B_PAGE_SIZE; 493*62caef87SFrançois Revol } 494*62caef87SFrançois Revol 495*62caef87SFrançois Revol return B_OK; 496*62caef87SFrançois Revol 497*62caef87SFrançois Revol #if 0//X86 498*62caef87SFrançois Revol 499*62caef87SFrançois Revol start = ROUNDDOWN(start, B_PAGE_SIZE); 500*62caef87SFrançois Revol if (start >= end) 501*62caef87SFrançois Revol return B_OK; 502*62caef87SFrançois Revol 503*62caef87SFrançois Revol TRACE("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end); 504*62caef87SFrançois Revol 505*62caef87SFrançois Revol page_directory_entry *pd = fPagingStructures->pgdir_virt; 506*62caef87SFrançois Revol 507*62caef87SFrançois Revol do { 508*62caef87SFrançois Revol int index = VADDR_TO_PDENT(start); 509*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 510*62caef87SFrançois Revol // no page table here, move the start up to access the next page 511*62caef87SFrançois Revol // table 512*62caef87SFrançois Revol start = ROUNDUP(start + 1, kPageTableAlignment); 513*62caef87SFrançois Revol continue; 514*62caef87SFrançois Revol } 515*62caef87SFrançois Revol 516*62caef87SFrançois Revol Thread* thread = thread_get_current_thread(); 517*62caef87SFrançois Revol ThreadCPUPinner pinner(thread); 518*62caef87SFrançois Revol 519*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 520*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 521*62caef87SFrançois Revol 522*62caef87SFrançois Revol for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end); 523*62caef87SFrançois Revol index++, start += B_PAGE_SIZE) { 524*62caef87SFrançois Revol if ((pt[index] & PPC_PTE_PRESENT) == 0) { 525*62caef87SFrançois Revol // page mapping not valid 526*62caef87SFrançois Revol continue; 527*62caef87SFrançois Revol } 528*62caef87SFrançois Revol 529*62caef87SFrançois Revol TRACE("unmap_tmap: removing page 0x%lx\n", start); 530*62caef87SFrançois Revol 531*62caef87SFrançois Revol page_table_entry oldEntry 532*62caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntryFlags(&pt[index], 533*62caef87SFrançois Revol PPC_PTE_PRESENT); 534*62caef87SFrançois Revol fMapCount--; 535*62caef87SFrançois Revol 536*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) { 537*62caef87SFrançois Revol // Note, that we only need to invalidate the address, if the 538*62caef87SFrançois Revol // accessed flags was set, since only then the entry could have 539*62caef87SFrançois Revol // been in any TLB. 540*62caef87SFrançois Revol InvalidatePage(start); 541*62caef87SFrançois Revol } 542*62caef87SFrançois Revol } 543*62caef87SFrançois Revol } while (start != 0 && start < end); 544*62caef87SFrançois Revol 545*62caef87SFrançois Revol return B_OK; 546*62caef87SFrançois Revol #endif 547*62caef87SFrançois Revol } 548*62caef87SFrançois Revol 549*62caef87SFrançois Revol 550*62caef87SFrançois Revol status_t 551*62caef87SFrançois Revol PPCVMTranslationMapClassic::RemapAddressRange(addr_t *_virtualAddress, 552*62caef87SFrançois Revol size_t size, bool unmap) 553*62caef87SFrançois Revol { 554*62caef87SFrançois Revol addr_t virtualAddress = ROUNDDOWN(*_virtualAddress, B_PAGE_SIZE); 555*62caef87SFrançois Revol size = ROUNDUP(*_virtualAddress + size - virtualAddress, B_PAGE_SIZE); 556*62caef87SFrançois Revol 557*62caef87SFrançois Revol VMAddressSpace *addressSpace = VMAddressSpace::Kernel(); 558*62caef87SFrançois Revol 559*62caef87SFrançois Revol // reserve space in the address space 560*62caef87SFrançois Revol void *newAddress = NULL; 561*62caef87SFrançois Revol status_t error = vm_reserve_address_range(addressSpace->ID(), &newAddress, 562*62caef87SFrançois Revol B_ANY_KERNEL_ADDRESS, size, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 563*62caef87SFrançois Revol if (error != B_OK) 564*62caef87SFrançois Revol return error; 565*62caef87SFrançois Revol 566*62caef87SFrançois Revol // get the area's first physical page 567*62caef87SFrançois Revol page_table_entry *entry = LookupPageTableEntry(virtualAddress); 568*62caef87SFrançois Revol if (!entry) 569*62caef87SFrançois Revol return B_ERROR; 570*62caef87SFrançois Revol phys_addr_t physicalBase = (phys_addr_t)entry->physical_page_number << 12; 571*62caef87SFrançois Revol 572*62caef87SFrançois Revol // map the pages 573*62caef87SFrançois Revol error = ppc_map_address_range((addr_t)newAddress, physicalBase, size); 574*62caef87SFrançois Revol if (error != B_OK) 575*62caef87SFrançois Revol return error; 576*62caef87SFrançois Revol 577*62caef87SFrançois Revol *_virtualAddress = (addr_t)newAddress; 578*62caef87SFrançois Revol 579*62caef87SFrançois Revol // unmap the old pages 580*62caef87SFrançois Revol if (unmap) 581*62caef87SFrançois Revol ppc_unmap_address_range(virtualAddress, size); 582*62caef87SFrançois Revol 583*62caef87SFrançois Revol return B_OK; 584*62caef87SFrançois Revol } 585*62caef87SFrançois Revol 586*62caef87SFrançois Revol 587*62caef87SFrançois Revol status_t 588*62caef87SFrançois Revol PPCVMTranslationMapClassic::DebugMarkRangePresent(addr_t start, addr_t end, 589*62caef87SFrançois Revol bool markPresent) 590*62caef87SFrançois Revol { 591*62caef87SFrançois Revol panic("%s: UNIMPLEMENTED", __FUNCTION__); 592*62caef87SFrançois Revol return B_ERROR; 593*62caef87SFrançois Revol #if 0//X86 594*62caef87SFrançois Revol start = ROUNDDOWN(start, B_PAGE_SIZE); 595*62caef87SFrançois Revol if (start >= end) 596*62caef87SFrançois Revol return B_OK; 597*62caef87SFrançois Revol 598*62caef87SFrançois Revol page_directory_entry *pd = fPagingStructures->pgdir_virt; 599*62caef87SFrançois Revol 600*62caef87SFrançois Revol do { 601*62caef87SFrançois Revol int index = VADDR_TO_PDENT(start); 602*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 603*62caef87SFrançois Revol // no page table here, move the start up to access the next page 604*62caef87SFrançois Revol // table 605*62caef87SFrançois Revol start = ROUNDUP(start + 1, kPageTableAlignment); 606*62caef87SFrançois Revol continue; 607*62caef87SFrançois Revol } 608*62caef87SFrançois Revol 609*62caef87SFrançois Revol Thread* thread = thread_get_current_thread(); 610*62caef87SFrançois Revol ThreadCPUPinner pinner(thread); 611*62caef87SFrançois Revol 612*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 613*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 614*62caef87SFrançois Revol 615*62caef87SFrançois Revol for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end); 616*62caef87SFrançois Revol index++, start += B_PAGE_SIZE) { 617*62caef87SFrançois Revol if ((pt[index] & PPC_PTE_PRESENT) == 0) { 618*62caef87SFrançois Revol if (!markPresent) 619*62caef87SFrançois Revol continue; 620*62caef87SFrançois Revol 621*62caef87SFrançois Revol PPCPagingMethodClassic::SetPageTableEntryFlags(&pt[index], 622*62caef87SFrançois Revol PPC_PTE_PRESENT); 623*62caef87SFrançois Revol } else { 624*62caef87SFrançois Revol if (markPresent) 625*62caef87SFrançois Revol continue; 626*62caef87SFrançois Revol 627*62caef87SFrançois Revol page_table_entry oldEntry 628*62caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntryFlags(&pt[index], 629*62caef87SFrançois Revol PPC_PTE_PRESENT); 630*62caef87SFrançois Revol 631*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) { 632*62caef87SFrançois Revol // Note, that we only need to invalidate the address, if the 633*62caef87SFrançois Revol // accessed flags was set, since only then the entry could 634*62caef87SFrançois Revol // have been in any TLB. 635*62caef87SFrançois Revol InvalidatePage(start); 636*62caef87SFrançois Revol } 637*62caef87SFrançois Revol } 638*62caef87SFrançois Revol } 639*62caef87SFrançois Revol } while (start != 0 && start < end); 640*62caef87SFrançois Revol 641*62caef87SFrançois Revol return B_OK; 642*62caef87SFrançois Revol #endif 643*62caef87SFrançois Revol } 644*62caef87SFrançois Revol 645*62caef87SFrançois Revol 646*62caef87SFrançois Revol /*! Caller must have locked the cache of the page to be unmapped. 647*62caef87SFrançois Revol This object shouldn't be locked. 648*62caef87SFrançois Revol */ 649*62caef87SFrançois Revol status_t 650*62caef87SFrançois Revol PPCVMTranslationMapClassic::UnmapPage(VMArea* area, addr_t address, 651*62caef87SFrançois Revol bool updatePageQueue) 652*62caef87SFrançois Revol { 653*62caef87SFrançois Revol ASSERT(address % B_PAGE_SIZE == 0); 654*62caef87SFrançois Revol 655*62caef87SFrançois Revol RecursiveLocker locker(fLock); 656*62caef87SFrançois Revol 657*62caef87SFrançois Revol if (area->cache_type == CACHE_TYPE_DEVICE) { 658*62caef87SFrançois Revol if (!RemovePageTableEntry(address)) 659*62caef87SFrançois Revol return B_ENTRY_NOT_FOUND; 660*62caef87SFrançois Revol 661*62caef87SFrançois Revol fMapCount--; 662*62caef87SFrançois Revol return B_OK; 663*62caef87SFrançois Revol } 664*62caef87SFrançois Revol 665*62caef87SFrançois Revol page_table_entry* entry = LookupPageTableEntry(address); 666*62caef87SFrançois Revol if (entry == NULL) 667*62caef87SFrançois Revol return B_ENTRY_NOT_FOUND; 668*62caef87SFrançois Revol 669*62caef87SFrançois Revol page_num_t pageNumber = entry->physical_page_number; 670*62caef87SFrançois Revol bool accessed = entry->referenced; 671*62caef87SFrançois Revol bool modified = entry->changed; 672*62caef87SFrançois Revol 673*62caef87SFrançois Revol RemovePageTableEntry(address); 674*62caef87SFrançois Revol 675*62caef87SFrançois Revol fMapCount--; 676*62caef87SFrançois Revol 677*62caef87SFrançois Revol locker.Detach(); 678*62caef87SFrançois Revol // PageUnmapped() will unlock for us 679*62caef87SFrançois Revol 680*62caef87SFrançois Revol PageUnmapped(area, pageNumber, accessed, modified, updatePageQueue); 681*62caef87SFrançois Revol 682*62caef87SFrançois Revol return B_OK; 683*62caef87SFrançois Revol 684*62caef87SFrançois Revol #if 0//X86 685*62caef87SFrançois Revol 686*62caef87SFrançois Revol ASSERT(address % B_PAGE_SIZE == 0); 687*62caef87SFrançois Revol 688*62caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt; 689*62caef87SFrançois Revol 690*62caef87SFrançois Revol TRACE("PPCVMTranslationMapClassic::UnmapPage(%#" B_PRIxADDR ")\n", address); 691*62caef87SFrançois Revol 692*62caef87SFrançois Revol RecursiveLocker locker(fLock); 693*62caef87SFrançois Revol 694*62caef87SFrançois Revol int index = VADDR_TO_PDENT(address); 695*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) 696*62caef87SFrançois Revol return B_ENTRY_NOT_FOUND; 697*62caef87SFrançois Revol 698*62caef87SFrançois Revol ThreadCPUPinner pinner(thread_get_current_thread()); 699*62caef87SFrançois Revol 700*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 701*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 702*62caef87SFrançois Revol 703*62caef87SFrançois Revol index = VADDR_TO_PTENT(address); 704*62caef87SFrançois Revol page_table_entry oldEntry = PPCPagingMethodClassic::ClearPageTableEntry( 705*62caef87SFrançois Revol &pt[index]); 706*62caef87SFrançois Revol 707*62caef87SFrançois Revol pinner.Unlock(); 708*62caef87SFrançois Revol 709*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_PRESENT) == 0) { 710*62caef87SFrançois Revol // page mapping not valid 711*62caef87SFrançois Revol return B_ENTRY_NOT_FOUND; 712*62caef87SFrançois Revol } 713*62caef87SFrançois Revol 714*62caef87SFrançois Revol fMapCount--; 715*62caef87SFrançois Revol 716*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) { 717*62caef87SFrançois Revol // Note, that we only need to invalidate the address, if the 718*62caef87SFrançois Revol // accessed flags was set, since only then the entry could have been 719*62caef87SFrançois Revol // in any TLB. 720*62caef87SFrançois Revol InvalidatePage(address); 721*62caef87SFrançois Revol Flush(); 722*62caef87SFrançois Revol 723*62caef87SFrançois Revol // NOTE: Between clearing the page table entry and Flush() other 724*62caef87SFrançois Revol // processors (actually even this processor with another thread of the 725*62caef87SFrançois Revol // same team) could still access the page in question via their cached 726*62caef87SFrançois Revol // entry. We can obviously lose a modified flag in this case, with the 727*62caef87SFrançois Revol // effect that the page looks unmodified (and might thus be recycled), 728*62caef87SFrançois Revol // but is actually modified. 729*62caef87SFrançois Revol // In most cases this is harmless, but for vm_remove_all_page_mappings() 730*62caef87SFrançois Revol // this is actually a problem. 731*62caef87SFrançois Revol // Interestingly FreeBSD seems to ignore this problem as well 732*62caef87SFrançois Revol // (cf. pmap_remove_all()), unless I've missed something. 733*62caef87SFrançois Revol } 734*62caef87SFrançois Revol 735*62caef87SFrançois Revol locker.Detach(); 736*62caef87SFrançois Revol // PageUnmapped() will unlock for us 737*62caef87SFrançois Revol 738*62caef87SFrançois Revol PageUnmapped(area, (oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE, 739*62caef87SFrançois Revol (oldEntry & PPC_PTE_ACCESSED) != 0, (oldEntry & PPC_PTE_DIRTY) != 0, 740*62caef87SFrançois Revol updatePageQueue); 741*62caef87SFrançois Revol 742*62caef87SFrançois Revol return B_OK; 743*62caef87SFrançois Revol #endif 744*62caef87SFrançois Revol } 745*62caef87SFrançois Revol 746*62caef87SFrançois Revol 747*62caef87SFrançois Revol void 748*62caef87SFrançois Revol PPCVMTranslationMapClassic::UnmapPages(VMArea* area, addr_t base, size_t size, 749*62caef87SFrançois Revol bool updatePageQueue) 750*62caef87SFrançois Revol { 751*62caef87SFrançois Revol panic("%s: UNIMPLEMENTED", __FUNCTION__); 752*62caef87SFrançois Revol #if 0//X86 753*62caef87SFrançois Revol if (size == 0) 754*62caef87SFrançois Revol return; 755*62caef87SFrançois Revol 756*62caef87SFrançois Revol addr_t start = base; 757*62caef87SFrançois Revol addr_t end = base + size - 1; 758*62caef87SFrançois Revol 759*62caef87SFrançois Revol TRACE("PPCVMTranslationMapClassic::UnmapPages(%p, %#" B_PRIxADDR ", %#" 760*62caef87SFrançois Revol B_PRIxADDR ")\n", area, start, end); 761*62caef87SFrançois Revol 762*62caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt; 763*62caef87SFrançois Revol 764*62caef87SFrançois Revol VMAreaMappings queue; 765*62caef87SFrançois Revol 766*62caef87SFrançois Revol RecursiveLocker locker(fLock); 767*62caef87SFrançois Revol 768*62caef87SFrançois Revol do { 769*62caef87SFrançois Revol int index = VADDR_TO_PDENT(start); 770*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 771*62caef87SFrançois Revol // no page table here, move the start up to access the next page 772*62caef87SFrançois Revol // table 773*62caef87SFrançois Revol start = ROUNDUP(start + 1, kPageTableAlignment); 774*62caef87SFrançois Revol continue; 775*62caef87SFrançois Revol } 776*62caef87SFrançois Revol 777*62caef87SFrançois Revol Thread* thread = thread_get_current_thread(); 778*62caef87SFrançois Revol ThreadCPUPinner pinner(thread); 779*62caef87SFrançois Revol 780*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 781*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 782*62caef87SFrançois Revol 783*62caef87SFrançois Revol for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end); 784*62caef87SFrançois Revol index++, start += B_PAGE_SIZE) { 785*62caef87SFrançois Revol page_table_entry oldEntry 786*62caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntry(&pt[index]); 787*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_PRESENT) == 0) 788*62caef87SFrançois Revol continue; 789*62caef87SFrançois Revol 790*62caef87SFrançois Revol fMapCount--; 791*62caef87SFrançois Revol 792*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) { 793*62caef87SFrançois Revol // Note, that we only need to invalidate the address, if the 794*62caef87SFrançois Revol // accessed flags was set, since only then the entry could have 795*62caef87SFrançois Revol // been in any TLB. 796*62caef87SFrançois Revol InvalidatePage(start); 797*62caef87SFrançois Revol } 798*62caef87SFrançois Revol 799*62caef87SFrançois Revol if (area->cache_type != CACHE_TYPE_DEVICE) { 800*62caef87SFrançois Revol // get the page 801*62caef87SFrançois Revol vm_page* page = vm_lookup_page( 802*62caef87SFrançois Revol (oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE); 803*62caef87SFrançois Revol ASSERT(page != NULL); 804*62caef87SFrançois Revol 805*62caef87SFrançois Revol DEBUG_PAGE_ACCESS_START(page); 806*62caef87SFrançois Revol 807*62caef87SFrançois Revol // transfer the accessed/dirty flags to the page 808*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) 809*62caef87SFrançois Revol page->accessed = true; 810*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_DIRTY) != 0) 811*62caef87SFrançois Revol page->modified = true; 812*62caef87SFrançois Revol 813*62caef87SFrançois Revol // remove the mapping object/decrement the wired_count of the 814*62caef87SFrançois Revol // page 815*62caef87SFrançois Revol if (area->wiring == B_NO_LOCK) { 816*62caef87SFrançois Revol vm_page_mapping* mapping = NULL; 817*62caef87SFrançois Revol vm_page_mappings::Iterator iterator 818*62caef87SFrançois Revol = page->mappings.GetIterator(); 819*62caef87SFrançois Revol while ((mapping = iterator.Next()) != NULL) { 820*62caef87SFrançois Revol if (mapping->area == area) 821*62caef87SFrançois Revol break; 822*62caef87SFrançois Revol } 823*62caef87SFrançois Revol 824*62caef87SFrançois Revol ASSERT(mapping != NULL); 825*62caef87SFrançois Revol 826*62caef87SFrançois Revol area->mappings.Remove(mapping); 827*62caef87SFrançois Revol page->mappings.Remove(mapping); 828*62caef87SFrançois Revol queue.Add(mapping); 829*62caef87SFrançois Revol } else 830*62caef87SFrançois Revol page->DecrementWiredCount(); 831*62caef87SFrançois Revol 832*62caef87SFrançois Revol if (!page->IsMapped()) { 833*62caef87SFrançois Revol atomic_add(&gMappedPagesCount, -1); 834*62caef87SFrançois Revol 835*62caef87SFrançois Revol if (updatePageQueue) { 836*62caef87SFrançois Revol if (page->Cache()->temporary) 837*62caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_INACTIVE); 838*62caef87SFrançois Revol else if (page->modified) 839*62caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_MODIFIED); 840*62caef87SFrançois Revol else 841*62caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_CACHED); 842*62caef87SFrançois Revol } 843*62caef87SFrançois Revol } 844*62caef87SFrançois Revol 845*62caef87SFrançois Revol DEBUG_PAGE_ACCESS_END(page); 846*62caef87SFrançois Revol } 847*62caef87SFrançois Revol } 848*62caef87SFrançois Revol 849*62caef87SFrançois Revol Flush(); 850*62caef87SFrançois Revol // flush explicitly, since we directly use the lock 851*62caef87SFrançois Revol } while (start != 0 && start < end); 852*62caef87SFrançois Revol 853*62caef87SFrançois Revol // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not 854*62caef87SFrançois Revol // really critical here, as in all cases this method is used, the unmapped 855*62caef87SFrançois Revol // area range is unmapped for good (resized/cut) and the pages will likely 856*62caef87SFrançois Revol // be freed. 857*62caef87SFrançois Revol 858*62caef87SFrançois Revol locker.Unlock(); 859*62caef87SFrançois Revol 860*62caef87SFrançois Revol // free removed mappings 861*62caef87SFrançois Revol bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); 862*62caef87SFrançois Revol uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY 863*62caef87SFrançois Revol | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); 864*62caef87SFrançois Revol while (vm_page_mapping* mapping = queue.RemoveHead()) 865*62caef87SFrançois Revol object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); 866*62caef87SFrançois Revol #endif 867*62caef87SFrançois Revol } 868*62caef87SFrançois Revol 869*62caef87SFrançois Revol 870*62caef87SFrançois Revol void 871*62caef87SFrançois Revol PPCVMTranslationMapClassic::UnmapArea(VMArea* area, bool deletingAddressSpace, 872*62caef87SFrançois Revol bool ignoreTopCachePageFlags) 873*62caef87SFrançois Revol { 874*62caef87SFrançois Revol panic("%s: UNIMPLEMENTED", __FUNCTION__); 875*62caef87SFrançois Revol #if 0//X86 876*62caef87SFrançois Revol if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) { 877*62caef87SFrançois Revol PPCVMTranslationMapClassic::UnmapPages(area, area->Base(), area->Size(), 878*62caef87SFrançois Revol true); 879*62caef87SFrançois Revol return; 880*62caef87SFrançois Revol } 881*62caef87SFrançois Revol 882*62caef87SFrançois Revol bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags; 883*62caef87SFrançois Revol 884*62caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt; 885*62caef87SFrançois Revol 886*62caef87SFrançois Revol RecursiveLocker locker(fLock); 887*62caef87SFrançois Revol 888*62caef87SFrançois Revol VMAreaMappings mappings; 889*62caef87SFrançois Revol mappings.MoveFrom(&area->mappings); 890*62caef87SFrançois Revol 891*62caef87SFrançois Revol for (VMAreaMappings::Iterator it = mappings.GetIterator(); 892*62caef87SFrançois Revol vm_page_mapping* mapping = it.Next();) { 893*62caef87SFrançois Revol vm_page* page = mapping->page; 894*62caef87SFrançois Revol page->mappings.Remove(mapping); 895*62caef87SFrançois Revol 896*62caef87SFrançois Revol VMCache* cache = page->Cache(); 897*62caef87SFrançois Revol 898*62caef87SFrançois Revol bool pageFullyUnmapped = false; 899*62caef87SFrançois Revol if (!page->IsMapped()) { 900*62caef87SFrançois Revol atomic_add(&gMappedPagesCount, -1); 901*62caef87SFrançois Revol pageFullyUnmapped = true; 902*62caef87SFrançois Revol } 903*62caef87SFrançois Revol 904*62caef87SFrançois Revol if (unmapPages || cache != area->cache) { 905*62caef87SFrançois Revol addr_t address = area->Base() 906*62caef87SFrançois Revol + ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset); 907*62caef87SFrançois Revol 908*62caef87SFrançois Revol int index = VADDR_TO_PDENT(address); 909*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 910*62caef87SFrançois Revol panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " 911*62caef87SFrançois Revol "has no page dir entry", page, area, address); 912*62caef87SFrançois Revol continue; 913*62caef87SFrançois Revol } 914*62caef87SFrançois Revol 915*62caef87SFrançois Revol ThreadCPUPinner pinner(thread_get_current_thread()); 916*62caef87SFrançois Revol 917*62caef87SFrançois Revol page_table_entry* pt 918*62caef87SFrançois Revol = (page_table_entry*)fPageMapper->GetPageTableAt( 919*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 920*62caef87SFrançois Revol page_table_entry oldEntry 921*62caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntry( 922*62caef87SFrançois Revol &pt[VADDR_TO_PTENT(address)]); 923*62caef87SFrançois Revol 924*62caef87SFrançois Revol pinner.Unlock(); 925*62caef87SFrançois Revol 926*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_PRESENT) == 0) { 927*62caef87SFrançois Revol panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but " 928*62caef87SFrançois Revol "has no page table entry", page, area, address); 929*62caef87SFrançois Revol continue; 930*62caef87SFrançois Revol } 931*62caef87SFrançois Revol 932*62caef87SFrançois Revol // transfer the accessed/dirty flags to the page and invalidate 933*62caef87SFrançois Revol // the mapping, if necessary 934*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) { 935*62caef87SFrançois Revol page->accessed = true; 936*62caef87SFrançois Revol 937*62caef87SFrançois Revol if (!deletingAddressSpace) 938*62caef87SFrançois Revol InvalidatePage(address); 939*62caef87SFrançois Revol } 940*62caef87SFrançois Revol 941*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_DIRTY) != 0) 942*62caef87SFrançois Revol page->modified = true; 943*62caef87SFrançois Revol 944*62caef87SFrançois Revol if (pageFullyUnmapped) { 945*62caef87SFrançois Revol DEBUG_PAGE_ACCESS_START(page); 946*62caef87SFrançois Revol 947*62caef87SFrançois Revol if (cache->temporary) 948*62caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_INACTIVE); 949*62caef87SFrançois Revol else if (page->modified) 950*62caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_MODIFIED); 951*62caef87SFrançois Revol else 952*62caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_CACHED); 953*62caef87SFrançois Revol 954*62caef87SFrançois Revol DEBUG_PAGE_ACCESS_END(page); 955*62caef87SFrançois Revol } 956*62caef87SFrançois Revol } 957*62caef87SFrançois Revol 958*62caef87SFrançois Revol fMapCount--; 959*62caef87SFrançois Revol } 960*62caef87SFrançois Revol 961*62caef87SFrançois Revol Flush(); 962*62caef87SFrançois Revol // flush explicitely, since we directly use the lock 963*62caef87SFrançois Revol 964*62caef87SFrançois Revol locker.Unlock(); 965*62caef87SFrançois Revol 966*62caef87SFrançois Revol bool isKernelSpace = area->address_space == VMAddressSpace::Kernel(); 967*62caef87SFrançois Revol uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY 968*62caef87SFrançois Revol | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0); 969*62caef87SFrançois Revol while (vm_page_mapping* mapping = mappings.RemoveHead()) 970*62caef87SFrançois Revol object_cache_free(gPageMappingsObjectCache, mapping, freeFlags); 971*62caef87SFrançois Revol #endif 972*62caef87SFrançois Revol } 973*62caef87SFrançois Revol 974*62caef87SFrançois Revol 975*62caef87SFrançois Revol status_t 976*62caef87SFrançois Revol PPCVMTranslationMapClassic::Query(addr_t va, phys_addr_t *_outPhysical, 977*62caef87SFrançois Revol uint32 *_outFlags) 978*62caef87SFrançois Revol { 979*62caef87SFrançois Revol page_table_entry *entry; 980*62caef87SFrançois Revol 981*62caef87SFrançois Revol // default the flags to not present 982*62caef87SFrançois Revol *_outFlags = 0; 983*62caef87SFrançois Revol *_outPhysical = 0; 984*62caef87SFrançois Revol 985*62caef87SFrançois Revol entry = LookupPageTableEntry(va); 986*62caef87SFrançois Revol if (entry == NULL) 987*62caef87SFrançois Revol return B_NO_ERROR; 988*62caef87SFrançois Revol 989*62caef87SFrançois Revol // ToDo: check this! 990*62caef87SFrançois Revol if (IS_KERNEL_ADDRESS(va)) 991*62caef87SFrançois Revol *_outFlags |= B_KERNEL_READ_AREA | (entry->page_protection == PTE_READ_ONLY ? 0 : B_KERNEL_WRITE_AREA); 992*62caef87SFrançois Revol else 993*62caef87SFrançois Revol *_outFlags |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | (entry->page_protection == PTE_READ_ONLY ? 0 : B_WRITE_AREA); 994*62caef87SFrançois Revol 995*62caef87SFrançois Revol *_outFlags |= entry->changed ? PAGE_MODIFIED : 0; 996*62caef87SFrançois Revol *_outFlags |= entry->referenced ? PAGE_ACCESSED : 0; 997*62caef87SFrançois Revol *_outFlags |= entry->valid ? PAGE_PRESENT : 0; 998*62caef87SFrançois Revol 999*62caef87SFrançois Revol *_outPhysical = entry->physical_page_number * B_PAGE_SIZE; 1000*62caef87SFrançois Revol 1001*62caef87SFrançois Revol return B_OK; 1002*62caef87SFrançois Revol 1003*62caef87SFrançois Revol #if 0//X86 1004*62caef87SFrançois Revol // default the flags to not present 1005*62caef87SFrançois Revol *_flags = 0; 1006*62caef87SFrançois Revol *_physical = 0; 1007*62caef87SFrançois Revol 1008*62caef87SFrançois Revol int index = VADDR_TO_PDENT(va); 1009*62caef87SFrançois Revol page_directory_entry *pd = fPagingStructures->pgdir_virt; 1010*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 1011*62caef87SFrançois Revol // no pagetable here 1012*62caef87SFrançois Revol return B_OK; 1013*62caef87SFrançois Revol } 1014*62caef87SFrançois Revol 1015*62caef87SFrançois Revol Thread* thread = thread_get_current_thread(); 1016*62caef87SFrançois Revol ThreadCPUPinner pinner(thread); 1017*62caef87SFrançois Revol 1018*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 1019*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 1020*62caef87SFrançois Revol page_table_entry entry = pt[VADDR_TO_PTENT(va)]; 1021*62caef87SFrançois Revol 1022*62caef87SFrançois Revol *_physical = entry & PPC_PDE_ADDRESS_MASK; 1023*62caef87SFrançois Revol 1024*62caef87SFrançois Revol // read in the page state flags 1025*62caef87SFrançois Revol if ((entry & PPC_PTE_USER) != 0) { 1026*62caef87SFrançois Revol *_flags |= ((entry & PPC_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0) 1027*62caef87SFrançois Revol | B_READ_AREA; 1028*62caef87SFrançois Revol } 1029*62caef87SFrançois Revol 1030*62caef87SFrançois Revol *_flags |= ((entry & PPC_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0) 1031*62caef87SFrançois Revol | B_KERNEL_READ_AREA 1032*62caef87SFrançois Revol | ((entry & PPC_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0) 1033*62caef87SFrançois Revol | ((entry & PPC_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0) 1034*62caef87SFrançois Revol | ((entry & PPC_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0); 1035*62caef87SFrançois Revol 1036*62caef87SFrançois Revol pinner.Unlock(); 1037*62caef87SFrançois Revol 1038*62caef87SFrançois Revol TRACE("query_tmap: returning pa 0x%lx for va 0x%lx\n", *_physical, va); 1039*62caef87SFrançois Revol 1040*62caef87SFrançois Revol return B_OK; 1041*62caef87SFrançois Revol #endif 1042*62caef87SFrançois Revol } 1043*62caef87SFrançois Revol 1044*62caef87SFrançois Revol 1045*62caef87SFrançois Revol status_t 1046*62caef87SFrançois Revol PPCVMTranslationMapClassic::QueryInterrupt(addr_t virtualAddress, 1047*62caef87SFrançois Revol phys_addr_t *_physicalAddress, uint32 *_flags) 1048*62caef87SFrançois Revol { 1049*62caef87SFrançois Revol return PPCVMTranslationMapClassic::Query(virtualAddress, _physicalAddress, _flags); 1050*62caef87SFrançois Revol 1051*62caef87SFrançois Revol #if 0//X86 1052*62caef87SFrançois Revol *_flags = 0; 1053*62caef87SFrançois Revol *_physical = 0; 1054*62caef87SFrançois Revol 1055*62caef87SFrançois Revol int index = VADDR_TO_PDENT(va); 1056*62caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt; 1057*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 1058*62caef87SFrançois Revol // no pagetable here 1059*62caef87SFrançois Revol return B_OK; 1060*62caef87SFrançois Revol } 1061*62caef87SFrançois Revol 1062*62caef87SFrançois Revol // map page table entry 1063*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)PPCPagingMethodClassic::Method() 1064*62caef87SFrançois Revol ->PhysicalPageMapper()->InterruptGetPageTableAt( 1065*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 1066*62caef87SFrançois Revol page_table_entry entry = pt[VADDR_TO_PTENT(va)]; 1067*62caef87SFrançois Revol 1068*62caef87SFrançois Revol *_physical = entry & PPC_PDE_ADDRESS_MASK; 1069*62caef87SFrançois Revol 1070*62caef87SFrançois Revol // read in the page state flags 1071*62caef87SFrançois Revol if ((entry & PPC_PTE_USER) != 0) { 1072*62caef87SFrançois Revol *_flags |= ((entry & PPC_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0) 1073*62caef87SFrançois Revol | B_READ_AREA; 1074*62caef87SFrançois Revol } 1075*62caef87SFrançois Revol 1076*62caef87SFrançois Revol *_flags |= ((entry & PPC_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0) 1077*62caef87SFrançois Revol | B_KERNEL_READ_AREA 1078*62caef87SFrançois Revol | ((entry & PPC_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0) 1079*62caef87SFrançois Revol | ((entry & PPC_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0) 1080*62caef87SFrançois Revol | ((entry & PPC_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0); 1081*62caef87SFrançois Revol 1082*62caef87SFrançois Revol return B_OK; 1083*62caef87SFrançois Revol #endif 1084*62caef87SFrançois Revol } 1085*62caef87SFrançois Revol 1086*62caef87SFrançois Revol 1087*62caef87SFrançois Revol status_t 1088*62caef87SFrançois Revol PPCVMTranslationMapClassic::Protect(addr_t start, addr_t end, uint32 attributes, 1089*62caef87SFrançois Revol uint32 memoryType) 1090*62caef87SFrançois Revol { 1091*62caef87SFrançois Revol // XXX finish 1092*62caef87SFrançois Revol return B_ERROR; 1093*62caef87SFrançois Revol #if 0//X86 1094*62caef87SFrançois Revol start = ROUNDDOWN(start, B_PAGE_SIZE); 1095*62caef87SFrançois Revol if (start >= end) 1096*62caef87SFrançois Revol return B_OK; 1097*62caef87SFrançois Revol 1098*62caef87SFrançois Revol TRACE("protect_tmap: pages 0x%lx to 0x%lx, attributes %lx\n", start, end, 1099*62caef87SFrançois Revol attributes); 1100*62caef87SFrançois Revol 1101*62caef87SFrançois Revol // compute protection flags 1102*62caef87SFrançois Revol uint32 newProtectionFlags = 0; 1103*62caef87SFrançois Revol if ((attributes & B_USER_PROTECTION) != 0) { 1104*62caef87SFrançois Revol newProtectionFlags = PPC_PTE_USER; 1105*62caef87SFrançois Revol if ((attributes & B_WRITE_AREA) != 0) 1106*62caef87SFrançois Revol newProtectionFlags |= PPC_PTE_WRITABLE; 1107*62caef87SFrançois Revol } else if ((attributes & B_KERNEL_WRITE_AREA) != 0) 1108*62caef87SFrançois Revol newProtectionFlags = PPC_PTE_WRITABLE; 1109*62caef87SFrançois Revol 1110*62caef87SFrançois Revol page_directory_entry *pd = fPagingStructures->pgdir_virt; 1111*62caef87SFrançois Revol 1112*62caef87SFrançois Revol do { 1113*62caef87SFrançois Revol int index = VADDR_TO_PDENT(start); 1114*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 1115*62caef87SFrançois Revol // no page table here, move the start up to access the next page 1116*62caef87SFrançois Revol // table 1117*62caef87SFrançois Revol start = ROUNDUP(start + 1, kPageTableAlignment); 1118*62caef87SFrançois Revol continue; 1119*62caef87SFrançois Revol } 1120*62caef87SFrançois Revol 1121*62caef87SFrançois Revol Thread* thread = thread_get_current_thread(); 1122*62caef87SFrançois Revol ThreadCPUPinner pinner(thread); 1123*62caef87SFrançois Revol 1124*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 1125*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 1126*62caef87SFrançois Revol 1127*62caef87SFrançois Revol for (index = VADDR_TO_PTENT(start); index < 1024 && start < end; 1128*62caef87SFrançois Revol index++, start += B_PAGE_SIZE) { 1129*62caef87SFrançois Revol page_table_entry entry = pt[index]; 1130*62caef87SFrançois Revol if ((entry & PPC_PTE_PRESENT) == 0) { 1131*62caef87SFrançois Revol // page mapping not valid 1132*62caef87SFrançois Revol continue; 1133*62caef87SFrançois Revol } 1134*62caef87SFrançois Revol 1135*62caef87SFrançois Revol TRACE("protect_tmap: protect page 0x%lx\n", start); 1136*62caef87SFrançois Revol 1137*62caef87SFrançois Revol // set the new protection flags -- we want to do that atomically, 1138*62caef87SFrançois Revol // without changing the accessed or dirty flag 1139*62caef87SFrançois Revol page_table_entry oldEntry; 1140*62caef87SFrançois Revol while (true) { 1141*62caef87SFrançois Revol oldEntry = PPCPagingMethodClassic::TestAndSetPageTableEntry( 1142*62caef87SFrançois Revol &pt[index], 1143*62caef87SFrançois Revol (entry & ~(PPC_PTE_PROTECTION_MASK 1144*62caef87SFrançois Revol | PPC_PTE_MEMORY_TYPE_MASK)) 1145*62caef87SFrançois Revol | newProtectionFlags 1146*62caef87SFrançois Revol | PPCPagingMethodClassic::MemoryTypeToPageTableEntryFlags( 1147*62caef87SFrançois Revol memoryType), 1148*62caef87SFrançois Revol entry); 1149*62caef87SFrançois Revol if (oldEntry == entry) 1150*62caef87SFrançois Revol break; 1151*62caef87SFrançois Revol entry = oldEntry; 1152*62caef87SFrançois Revol } 1153*62caef87SFrançois Revol 1154*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) { 1155*62caef87SFrançois Revol // Note, that we only need to invalidate the address, if the 1156*62caef87SFrançois Revol // accessed flag was set, since only then the entry could have 1157*62caef87SFrançois Revol // been in any TLB. 1158*62caef87SFrançois Revol InvalidatePage(start); 1159*62caef87SFrançois Revol } 1160*62caef87SFrançois Revol } 1161*62caef87SFrançois Revol } while (start != 0 && start < end); 1162*62caef87SFrançois Revol 1163*62caef87SFrançois Revol return B_OK; 1164*62caef87SFrançois Revol #endif 1165*62caef87SFrançois Revol } 1166*62caef87SFrançois Revol 1167*62caef87SFrançois Revol 1168*62caef87SFrançois Revol status_t 1169*62caef87SFrançois Revol PPCVMTranslationMapClassic::ClearFlags(addr_t virtualAddress, uint32 flags) 1170*62caef87SFrançois Revol { 1171*62caef87SFrançois Revol page_table_entry *entry = LookupPageTableEntry(virtualAddress); 1172*62caef87SFrançois Revol if (entry == NULL) 1173*62caef87SFrançois Revol return B_NO_ERROR; 1174*62caef87SFrançois Revol 1175*62caef87SFrançois Revol bool modified = false; 1176*62caef87SFrançois Revol 1177*62caef87SFrançois Revol // clear the bits 1178*62caef87SFrançois Revol if (flags & PAGE_MODIFIED && entry->changed) { 1179*62caef87SFrançois Revol entry->changed = false; 1180*62caef87SFrançois Revol modified = true; 1181*62caef87SFrançois Revol } 1182*62caef87SFrançois Revol if (flags & PAGE_ACCESSED && entry->referenced) { 1183*62caef87SFrançois Revol entry->referenced = false; 1184*62caef87SFrançois Revol modified = true; 1185*62caef87SFrançois Revol } 1186*62caef87SFrançois Revol 1187*62caef87SFrançois Revol // synchronize 1188*62caef87SFrançois Revol if (modified) { 1189*62caef87SFrançois Revol tlbie(virtualAddress); 1190*62caef87SFrançois Revol eieio(); 1191*62caef87SFrançois Revol tlbsync(); 1192*62caef87SFrançois Revol ppc_sync(); 1193*62caef87SFrançois Revol } 1194*62caef87SFrançois Revol 1195*62caef87SFrançois Revol return B_OK; 1196*62caef87SFrançois Revol 1197*62caef87SFrançois Revol #if 0//X86 1198*62caef87SFrançois Revol int index = VADDR_TO_PDENT(va); 1199*62caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt; 1200*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) { 1201*62caef87SFrançois Revol // no pagetable here 1202*62caef87SFrançois Revol return B_OK; 1203*62caef87SFrançois Revol } 1204*62caef87SFrançois Revol 1205*62caef87SFrançois Revol uint32 flagsToClear = ((flags & PAGE_MODIFIED) ? PPC_PTE_DIRTY : 0) 1206*62caef87SFrançois Revol | ((flags & PAGE_ACCESSED) ? PPC_PTE_ACCESSED : 0); 1207*62caef87SFrançois Revol 1208*62caef87SFrançois Revol Thread* thread = thread_get_current_thread(); 1209*62caef87SFrançois Revol ThreadCPUPinner pinner(thread); 1210*62caef87SFrançois Revol 1211*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 1212*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 1213*62caef87SFrançois Revol index = VADDR_TO_PTENT(va); 1214*62caef87SFrançois Revol 1215*62caef87SFrançois Revol // clear out the flags we've been requested to clear 1216*62caef87SFrançois Revol page_table_entry oldEntry 1217*62caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntryFlags(&pt[index], 1218*62caef87SFrançois Revol flagsToClear); 1219*62caef87SFrançois Revol 1220*62caef87SFrançois Revol pinner.Unlock(); 1221*62caef87SFrançois Revol 1222*62caef87SFrançois Revol if ((oldEntry & flagsToClear) != 0) 1223*62caef87SFrançois Revol InvalidatePage(va); 1224*62caef87SFrançois Revol 1225*62caef87SFrançois Revol return B_OK; 1226*62caef87SFrançois Revol #endif 1227*62caef87SFrançois Revol } 1228*62caef87SFrançois Revol 1229*62caef87SFrançois Revol 1230*62caef87SFrançois Revol bool 1231*62caef87SFrançois Revol PPCVMTranslationMapClassic::ClearAccessedAndModified(VMArea* area, 1232*62caef87SFrançois Revol addr_t address, bool unmapIfUnaccessed, bool& _modified) 1233*62caef87SFrançois Revol { 1234*62caef87SFrançois Revol ASSERT(address % B_PAGE_SIZE == 0); 1235*62caef87SFrançois Revol 1236*62caef87SFrançois Revol // TODO: Implement for real! ATM this is just an approximation using 1237*62caef87SFrançois Revol // Query(), ClearFlags(), and UnmapPage(). See below! 1238*62caef87SFrançois Revol 1239*62caef87SFrançois Revol RecursiveLocker locker(fLock); 1240*62caef87SFrançois Revol 1241*62caef87SFrançois Revol uint32 flags; 1242*62caef87SFrançois Revol phys_addr_t physicalAddress; 1243*62caef87SFrançois Revol if (Query(address, &physicalAddress, &flags) != B_OK 1244*62caef87SFrançois Revol || (flags & PAGE_PRESENT) == 0) { 1245*62caef87SFrançois Revol return false; 1246*62caef87SFrançois Revol } 1247*62caef87SFrançois Revol 1248*62caef87SFrançois Revol _modified = (flags & PAGE_MODIFIED) != 0; 1249*62caef87SFrançois Revol 1250*62caef87SFrançois Revol if ((flags & (PAGE_ACCESSED | PAGE_MODIFIED)) != 0) 1251*62caef87SFrançois Revol ClearFlags(address, flags & (PAGE_ACCESSED | PAGE_MODIFIED)); 1252*62caef87SFrançois Revol 1253*62caef87SFrançois Revol if ((flags & PAGE_ACCESSED) != 0) 1254*62caef87SFrançois Revol return true; 1255*62caef87SFrançois Revol 1256*62caef87SFrançois Revol if (!unmapIfUnaccessed) 1257*62caef87SFrançois Revol return false; 1258*62caef87SFrançois Revol 1259*62caef87SFrançois Revol locker.Unlock(); 1260*62caef87SFrançois Revol 1261*62caef87SFrançois Revol UnmapPage(area, address, false); 1262*62caef87SFrançois Revol // TODO: Obvious race condition: Between querying and unmapping the 1263*62caef87SFrançois Revol // page could have been accessed. We try to compensate by considering 1264*62caef87SFrançois Revol // vm_page::{accessed,modified} (which would have been updated by 1265*62caef87SFrançois Revol // UnmapPage()) below, but that doesn't quite match the required 1266*62caef87SFrançois Revol // semantics of the method. 1267*62caef87SFrançois Revol 1268*62caef87SFrançois Revol vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 1269*62caef87SFrançois Revol if (page == NULL) 1270*62caef87SFrançois Revol return false; 1271*62caef87SFrançois Revol 1272*62caef87SFrançois Revol _modified |= page->modified; 1273*62caef87SFrançois Revol 1274*62caef87SFrançois Revol return page->accessed; 1275*62caef87SFrançois Revol 1276*62caef87SFrançois Revol #if 0//X86 1277*62caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt; 1278*62caef87SFrançois Revol 1279*62caef87SFrançois Revol TRACE("PPCVMTranslationMapClassic::ClearAccessedAndModified(%#" B_PRIxADDR 1280*62caef87SFrançois Revol ")\n", address); 1281*62caef87SFrançois Revol 1282*62caef87SFrançois Revol RecursiveLocker locker(fLock); 1283*62caef87SFrançois Revol 1284*62caef87SFrançois Revol int index = VADDR_TO_PDENT(address); 1285*62caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) 1286*62caef87SFrançois Revol return false; 1287*62caef87SFrançois Revol 1288*62caef87SFrançois Revol ThreadCPUPinner pinner(thread_get_current_thread()); 1289*62caef87SFrançois Revol 1290*62caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt( 1291*62caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK); 1292*62caef87SFrançois Revol 1293*62caef87SFrançois Revol index = VADDR_TO_PTENT(address); 1294*62caef87SFrançois Revol 1295*62caef87SFrançois Revol // perform the deed 1296*62caef87SFrançois Revol page_table_entry oldEntry; 1297*62caef87SFrançois Revol 1298*62caef87SFrançois Revol if (unmapIfUnaccessed) { 1299*62caef87SFrançois Revol while (true) { 1300*62caef87SFrançois Revol oldEntry = pt[index]; 1301*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_PRESENT) == 0) { 1302*62caef87SFrançois Revol // page mapping not valid 1303*62caef87SFrançois Revol return false; 1304*62caef87SFrançois Revol } 1305*62caef87SFrançois Revol 1306*62caef87SFrançois Revol if (oldEntry & PPC_PTE_ACCESSED) { 1307*62caef87SFrançois Revol // page was accessed -- just clear the flags 1308*62caef87SFrançois Revol oldEntry = PPCPagingMethodClassic::ClearPageTableEntryFlags( 1309*62caef87SFrançois Revol &pt[index], PPC_PTE_ACCESSED | PPC_PTE_DIRTY); 1310*62caef87SFrançois Revol break; 1311*62caef87SFrançois Revol } 1312*62caef87SFrançois Revol 1313*62caef87SFrançois Revol // page hasn't been accessed -- unmap it 1314*62caef87SFrançois Revol if (PPCPagingMethodClassic::TestAndSetPageTableEntry(&pt[index], 0, 1315*62caef87SFrançois Revol oldEntry) == oldEntry) { 1316*62caef87SFrançois Revol break; 1317*62caef87SFrançois Revol } 1318*62caef87SFrançois Revol 1319*62caef87SFrançois Revol // something changed -- check again 1320*62caef87SFrançois Revol } 1321*62caef87SFrançois Revol } else { 1322*62caef87SFrançois Revol oldEntry = PPCPagingMethodClassic::ClearPageTableEntryFlags(&pt[index], 1323*62caef87SFrançois Revol PPC_PTE_ACCESSED | PPC_PTE_DIRTY); 1324*62caef87SFrançois Revol } 1325*62caef87SFrançois Revol 1326*62caef87SFrançois Revol pinner.Unlock(); 1327*62caef87SFrançois Revol 1328*62caef87SFrançois Revol _modified = (oldEntry & PPC_PTE_DIRTY) != 0; 1329*62caef87SFrançois Revol 1330*62caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) { 1331*62caef87SFrançois Revol // Note, that we only need to invalidate the address, if the 1332*62caef87SFrançois Revol // accessed flags was set, since only then the entry could have been 1333*62caef87SFrançois Revol // in any TLB. 1334*62caef87SFrançois Revol InvalidatePage(address); 1335*62caef87SFrançois Revol 1336*62caef87SFrançois Revol Flush(); 1337*62caef87SFrançois Revol 1338*62caef87SFrançois Revol return true; 1339*62caef87SFrançois Revol } 1340*62caef87SFrançois Revol 1341*62caef87SFrançois Revol if (!unmapIfUnaccessed) 1342*62caef87SFrançois Revol return false; 1343*62caef87SFrançois Revol 1344*62caef87SFrançois Revol // We have unmapped the address. Do the "high level" stuff. 1345*62caef87SFrançois Revol 1346*62caef87SFrançois Revol fMapCount--; 1347*62caef87SFrançois Revol 1348*62caef87SFrançois Revol locker.Detach(); 1349*62caef87SFrançois Revol // UnaccessedPageUnmapped() will unlock for us 1350*62caef87SFrançois Revol 1351*62caef87SFrançois Revol UnaccessedPageUnmapped(area, 1352*62caef87SFrançois Revol (oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE); 1353*62caef87SFrançois Revol 1354*62caef87SFrançois Revol return false; 1355*62caef87SFrançois Revol #endif 1356*62caef87SFrançois Revol } 1357*62caef87SFrançois Revol 1358*62caef87SFrançois Revol 1359*62caef87SFrançois Revol PPCPagingStructures* 1360*62caef87SFrançois Revol PPCVMTranslationMapClassic::PagingStructures() const 1361*62caef87SFrançois Revol { 1362*62caef87SFrançois Revol return fPagingStructures; 1363*62caef87SFrançois Revol } 1364