162caef87SFrançois Revol /*
262caef87SFrançois Revol * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
362caef87SFrançois Revol * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
462caef87SFrançois Revol * Distributed under the terms of the MIT License.
562caef87SFrançois Revol *
662caef87SFrançois Revol * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
762caef87SFrançois Revol * Distributed under the terms of the NewOS License.
862caef87SFrançois Revol */
962caef87SFrançois Revol
1062caef87SFrançois Revol /* (bonefish) Some explanatory words on how address translation is implemented
1162caef87SFrançois Revol for the 32 bit PPC architecture.
1262caef87SFrançois Revol
1362caef87SFrançois Revol I use the address type nomenclature as used in the PPC architecture
1462caef87SFrançois Revol specs, i.e.
1562caef87SFrançois Revol - effective address: An address as used by program instructions, i.e.
1662caef87SFrançois Revol that's what elsewhere (e.g. in the VM implementation) is called
1762caef87SFrançois Revol virtual address.
1862caef87SFrançois Revol - virtual address: An intermediate address computed from the effective
1962caef87SFrançois Revol address via the segment registers.
2062caef87SFrançois Revol - physical address: An address referring to physical storage.
2162caef87SFrançois Revol
2262caef87SFrançois Revol The hardware translates an effective address to a physical address using
2362caef87SFrançois Revol either of two mechanisms: 1) Block Address Translation (BAT) or
2462caef87SFrançois Revol 2) segment + page translation. The first mechanism does this directly
2562caef87SFrançois Revol using two sets (for data/instructions) of special purpose registers.
2662caef87SFrançois Revol The latter mechanism is of more relevance here, though:
2762caef87SFrançois Revol
2862caef87SFrançois Revol effective address (32 bit): [ 0 ESID 3 | 4 PIX 19 | 20 Byte 31 ]
2962caef87SFrançois Revol | | |
3062caef87SFrançois Revol (segment registers) | |
3162caef87SFrançois Revol | | |
3262caef87SFrançois Revol virtual address (52 bit): [ 0 VSID 23 | 24 PIX 39 | 40 Byte 51 ]
3362caef87SFrançois Revol [ 0 VPN 39 | 40 Byte 51 ]
3462caef87SFrançois Revol | |
3562caef87SFrançois Revol (page table) |
3662caef87SFrançois Revol | |
3762caef87SFrançois Revol physical address (32 bit): [ 0 PPN 19 | 20 Byte 31 ]
3862caef87SFrançois Revol
3962caef87SFrançois Revol
4062caef87SFrançois Revol ESID: Effective Segment ID
4162caef87SFrançois Revol VSID: Virtual Segment ID
4262caef87SFrançois Revol PIX: Page Index
4362caef87SFrançois Revol VPN: Virtual Page Number
4462caef87SFrançois Revol PPN: Physical Page Number
4562caef87SFrançois Revol
4662caef87SFrançois Revol
4762caef87SFrançois Revol Unlike on x86 we can't just switch the context to another team by just
4862caef87SFrançois Revol setting a register to another page directory, since we only have one
4962caef87SFrançois Revol page table containing both kernel and user address mappings. Instead we
5062caef87SFrançois Revol map the effective address space of kernel and *all* teams
5162caef87SFrançois Revol non-intersectingly into the virtual address space (which fortunately is
5262caef87SFrançois Revol 20 bits wider), and use the segment registers to select the section of
5362caef87SFrançois Revol the virtual address space for the current team. Half of the 16 segment
5462caef87SFrançois Revol registers (8 - 15) map the kernel addresses, so they remain unchanged.
5562caef87SFrançois Revol
5662caef87SFrançois Revol The range of the virtual address space a team's effective address space
5762caef87SFrançois Revol is mapped to is defined by its PPCVMTranslationMap::fVSIDBase,
5862caef87SFrançois Revol which is the first of the 8 successive VSID values used for the team.
5962caef87SFrançois Revol
6062caef87SFrançois Revol Which fVSIDBase values are already taken is defined by the set bits in
6162caef87SFrançois Revol the bitmap sVSIDBaseBitmap.
6262caef87SFrançois Revol
6362caef87SFrançois Revol
6462caef87SFrançois Revol TODO:
6562caef87SFrançois Revol * If we want to continue to use the OF services, we would need to add
6662caef87SFrançois Revol its address mappings to the kernel space. Unfortunately some stuff
6762caef87SFrançois Revol (especially RAM) is mapped in an address range without the kernel
6862caef87SFrançois Revol address space. We probably need to map those into each team's address
6962caef87SFrançois Revol space as kernel read/write areas.
7062caef87SFrançois Revol * The current locking scheme is insufficient. The page table is a resource
7162caef87SFrançois Revol shared by all teams. We need to synchronize access to it. Probably via a
7262caef87SFrançois Revol spinlock.
7362caef87SFrançois Revol */
7462caef87SFrançois Revol
7562caef87SFrançois Revol #include "paging/classic/PPCVMTranslationMapClassic.h"
7662caef87SFrançois Revol
7762caef87SFrançois Revol #include <stdlib.h>
7862caef87SFrançois Revol #include <string.h>
7962caef87SFrançois Revol
8062caef87SFrançois Revol #include <arch/cpu.h>
8162caef87SFrançois Revol #include <arch_mmu.h>
8262caef87SFrançois Revol #include <int.h>
8362caef87SFrançois Revol #include <thread.h>
8462caef87SFrançois Revol #include <slab/Slab.h>
8562caef87SFrançois Revol #include <smp.h>
8662caef87SFrançois Revol #include <util/AutoLock.h>
87057fe191SAugustin Cavalier #include <util/ThreadAutoLock.h>
8862caef87SFrançois Revol #include <util/queue.h>
8962caef87SFrançois Revol #include <vm/vm_page.h>
9062caef87SFrançois Revol #include <vm/vm_priv.h>
9162caef87SFrançois Revol #include <vm/VMAddressSpace.h>
9262caef87SFrançois Revol #include <vm/VMCache.h>
9362caef87SFrançois Revol
9462caef87SFrançois Revol #include "paging/classic/PPCPagingMethodClassic.h"
9562caef87SFrançois Revol #include "paging/classic/PPCPagingStructuresClassic.h"
9662caef87SFrançois Revol #include "generic_vm_physical_page_mapper.h"
9762caef87SFrançois Revol #include "generic_vm_physical_page_ops.h"
9862caef87SFrançois Revol #include "GenericVMPhysicalPageMapper.h"
9962caef87SFrançois Revol
10062caef87SFrançois Revol
10162caef87SFrançois Revol //#define TRACE_PPC_VM_TRANSLATION_MAP_CLASSIC
10262caef87SFrançois Revol #ifdef TRACE_PPC_VM_TRANSLATION_MAP_CLASSIC
10362caef87SFrançois Revol # define TRACE(x...) dprintf(x)
10462caef87SFrançois Revol #else
10562caef87SFrançois Revol # define TRACE(x...) ;
10662caef87SFrançois Revol #endif
10762caef87SFrançois Revol
10862caef87SFrançois Revol
10962caef87SFrançois Revol // The VSID is a 24 bit number. The lower three bits are defined by the
11062caef87SFrançois Revol // (effective) segment number, which leaves us with a 21 bit space of
11162caef87SFrançois Revol // VSID bases (= 2 * 1024 * 1024).
112a736630cSAdrien Destugues #define MAX_VSID_BASES (B_PAGE_SIZE * 8)
11362caef87SFrançois Revol static uint32 sVSIDBaseBitmap[MAX_VSID_BASES / (sizeof(uint32) * 8)];
11462caef87SFrançois Revol static spinlock sVSIDBaseBitmapLock;
11562caef87SFrançois Revol
11662caef87SFrançois Revol #define VSID_BASE_SHIFT 3
11762caef87SFrançois Revol #define VADDR_TO_VSID(vsidBase, vaddr) (vsidBase + ((vaddr) >> 28))
11862caef87SFrançois Revol
11962caef87SFrançois Revol
12062caef87SFrançois Revol // #pragma mark -
12162caef87SFrançois Revol
12262caef87SFrançois Revol
PPCVMTranslationMapClassic()12362caef87SFrançois Revol PPCVMTranslationMapClassic::PPCVMTranslationMapClassic()
12462caef87SFrançois Revol :
12562caef87SFrançois Revol fPagingStructures(NULL)
12662caef87SFrançois Revol {
12762caef87SFrançois Revol }
12862caef87SFrançois Revol
12962caef87SFrançois Revol
~PPCVMTranslationMapClassic()13062caef87SFrançois Revol PPCVMTranslationMapClassic::~PPCVMTranslationMapClassic()
13162caef87SFrançois Revol {
13262caef87SFrançois Revol if (fPagingStructures == NULL)
13362caef87SFrançois Revol return;
13462caef87SFrançois Revol
13562caef87SFrançois Revol #if 0//X86
13662caef87SFrançois Revol if (fPageMapper != NULL)
13762caef87SFrançois Revol fPageMapper->Delete();
13862caef87SFrançois Revol #endif
13962caef87SFrançois Revol
14062caef87SFrançois Revol if (fMapCount > 0) {
14162caef87SFrançois Revol panic("vm_translation_map.destroy_tmap: map %p has positive map count %ld\n",
14262caef87SFrançois Revol this, fMapCount);
14362caef87SFrançois Revol }
14462caef87SFrançois Revol
14562caef87SFrançois Revol // mark the vsid base not in use
14662caef87SFrançois Revol int baseBit = fVSIDBase >> VSID_BASE_SHIFT;
14762caef87SFrançois Revol atomic_and((int32 *)&sVSIDBaseBitmap[baseBit / 32],
14862caef87SFrançois Revol ~(1 << (baseBit % 32)));
14962caef87SFrançois Revol
15062caef87SFrançois Revol #if 0//X86
15162caef87SFrançois Revol if (fPagingStructures->pgdir_virt != NULL) {
15262caef87SFrançois Revol // cycle through and free all of the user space pgtables
15362caef87SFrançois Revol for (uint32 i = VADDR_TO_PDENT(USER_BASE);
15462caef87SFrançois Revol i <= VADDR_TO_PDENT(USER_BASE + (USER_SIZE - 1)); i++) {
15562caef87SFrançois Revol if ((fPagingStructures->pgdir_virt[i] & PPC_PDE_PRESENT) != 0) {
15662caef87SFrançois Revol addr_t address = fPagingStructures->pgdir_virt[i]
15762caef87SFrançois Revol & PPC_PDE_ADDRESS_MASK;
15862caef87SFrançois Revol vm_page* page = vm_lookup_page(address / B_PAGE_SIZE);
15962caef87SFrançois Revol if (!page)
16062caef87SFrançois Revol panic("destroy_tmap: didn't find pgtable page\n");
16162caef87SFrançois Revol DEBUG_PAGE_ACCESS_START(page);
16262caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_FREE);
16362caef87SFrançois Revol }
16462caef87SFrançois Revol }
16562caef87SFrançois Revol }
16662caef87SFrançois Revol #endif
16762caef87SFrançois Revol
16862caef87SFrançois Revol fPagingStructures->RemoveReference();
16962caef87SFrançois Revol }
17062caef87SFrançois Revol
17162caef87SFrançois Revol
17262caef87SFrançois Revol status_t
Init(bool kernel)17362caef87SFrançois Revol PPCVMTranslationMapClassic::Init(bool kernel)
17462caef87SFrançois Revol {
17562caef87SFrançois Revol TRACE("PPCVMTranslationMapClassic::Init()\n");
17662caef87SFrançois Revol
17762caef87SFrançois Revol PPCVMTranslationMap::Init(kernel);
17862caef87SFrançois Revol
17962caef87SFrançois Revol cpu_status state = disable_interrupts();
18062caef87SFrançois Revol acquire_spinlock(&sVSIDBaseBitmapLock);
18162caef87SFrançois Revol
18262caef87SFrançois Revol // allocate a VSID base for this one
18362caef87SFrançois Revol if (kernel) {
18462caef87SFrançois Revol // The boot loader has set up the segment registers for identical
18562caef87SFrançois Revol // mapping. Two VSID bases are reserved for the kernel: 0 and 8. The
18662caef87SFrançois Revol // latter one for mapping the kernel address space (0x80000000...), the
18762caef87SFrançois Revol // former one for the lower addresses required by the Open Firmware
18862caef87SFrançois Revol // services.
18962caef87SFrançois Revol fVSIDBase = 0;
19062caef87SFrançois Revol sVSIDBaseBitmap[0] |= 0x3;
19162caef87SFrançois Revol } else {
19262caef87SFrançois Revol int i = 0;
19362caef87SFrançois Revol
19462caef87SFrançois Revol while (i < MAX_VSID_BASES) {
19562caef87SFrançois Revol if (sVSIDBaseBitmap[i / 32] == 0xffffffff) {
19662caef87SFrançois Revol i += 32;
19762caef87SFrançois Revol continue;
19862caef87SFrançois Revol }
19962caef87SFrançois Revol if ((sVSIDBaseBitmap[i / 32] & (1 << (i % 32))) == 0) {
20062caef87SFrançois Revol // we found it
20162caef87SFrançois Revol sVSIDBaseBitmap[i / 32] |= 1 << (i % 32);
20262caef87SFrançois Revol break;
20362caef87SFrançois Revol }
20462caef87SFrançois Revol i++;
20562caef87SFrançois Revol }
20662caef87SFrançois Revol if (i >= MAX_VSID_BASES)
20762caef87SFrançois Revol panic("vm_translation_map_create: out of VSID bases\n");
20862caef87SFrançois Revol fVSIDBase = i << VSID_BASE_SHIFT;
20962caef87SFrançois Revol }
21062caef87SFrançois Revol
21162caef87SFrançois Revol release_spinlock(&sVSIDBaseBitmapLock);
21262caef87SFrançois Revol restore_interrupts(state);
21362caef87SFrançois Revol
21462caef87SFrançois Revol fPagingStructures = new(std::nothrow) PPCPagingStructuresClassic;
21562caef87SFrançois Revol if (fPagingStructures == NULL)
21662caef87SFrançois Revol return B_NO_MEMORY;
21762caef87SFrançois Revol
21862caef87SFrançois Revol PPCPagingMethodClassic* method = PPCPagingMethodClassic::Method();
21962caef87SFrançois Revol
22062caef87SFrançois Revol if (!kernel) {
22162caef87SFrançois Revol // user
22262caef87SFrançois Revol #if 0//X86
22362caef87SFrançois Revol // allocate a physical page mapper
22462caef87SFrançois Revol status_t error = method->PhysicalPageMapper()
22562caef87SFrançois Revol ->CreateTranslationMapPhysicalPageMapper(&fPageMapper);
22662caef87SFrançois Revol if (error != B_OK)
22762caef87SFrançois Revol return error;
22862caef87SFrançois Revol #endif
22962caef87SFrançois Revol #if 0//X86
23062caef87SFrançois Revol // allocate the page directory
23162caef87SFrançois Revol page_directory_entry* virtualPageDir = (page_directory_entry*)memalign(
23262caef87SFrançois Revol B_PAGE_SIZE, B_PAGE_SIZE);
23362caef87SFrançois Revol if (virtualPageDir == NULL)
23462caef87SFrançois Revol return B_NO_MEMORY;
23562caef87SFrançois Revol
23662caef87SFrançois Revol // look up the page directory's physical address
23762caef87SFrançois Revol phys_addr_t physicalPageDir;
23862caef87SFrançois Revol vm_get_page_mapping(VMAddressSpace::KernelID(),
23962caef87SFrançois Revol (addr_t)virtualPageDir, &physicalPageDir);
24062caef87SFrançois Revol #endif
24162caef87SFrançois Revol
24262caef87SFrançois Revol fPagingStructures->Init(/*NULL, 0,
24362caef87SFrançois Revol method->KernelVirtualPageDirectory()*/method->PageTable());
24462caef87SFrançois Revol } else {
24562caef87SFrançois Revol // kernel
24662caef87SFrançois Revol #if 0//X86
24762caef87SFrançois Revol // get the physical page mapper
24862caef87SFrançois Revol fPageMapper = method->KernelPhysicalPageMapper();
24962caef87SFrançois Revol #endif
25062caef87SFrançois Revol
25162caef87SFrançois Revol // we already know the kernel pgdir mapping
25262caef87SFrançois Revol fPagingStructures->Init(/*method->KernelVirtualPageDirectory(),
25362caef87SFrançois Revol method->KernelPhysicalPageDirectory(), NULL*/method->PageTable());
25462caef87SFrançois Revol }
25562caef87SFrançois Revol
25662caef87SFrançois Revol return B_OK;
25762caef87SFrançois Revol }
25862caef87SFrançois Revol
25962caef87SFrançois Revol
26062caef87SFrançois Revol void
ChangeASID()26162caef87SFrançois Revol PPCVMTranslationMapClassic::ChangeASID()
26262caef87SFrançois Revol {
26362caef87SFrançois Revol // this code depends on the kernel being at 0x80000000, fix if we change that
26462caef87SFrançois Revol #if KERNEL_BASE != 0x80000000
26562caef87SFrançois Revol #error fix me
26662caef87SFrançois Revol #endif
26762caef87SFrançois Revol int vsidBase = VSIDBase();
26862caef87SFrançois Revol
26962caef87SFrançois Revol isync(); // synchronize context
27062caef87SFrançois Revol asm("mtsr 0,%0" : : "g"(vsidBase));
27162caef87SFrançois Revol asm("mtsr 1,%0" : : "g"(vsidBase + 1));
27262caef87SFrançois Revol asm("mtsr 2,%0" : : "g"(vsidBase + 2));
27362caef87SFrançois Revol asm("mtsr 3,%0" : : "g"(vsidBase + 3));
27462caef87SFrançois Revol asm("mtsr 4,%0" : : "g"(vsidBase + 4));
27562caef87SFrançois Revol asm("mtsr 5,%0" : : "g"(vsidBase + 5));
27662caef87SFrançois Revol asm("mtsr 6,%0" : : "g"(vsidBase + 6));
27762caef87SFrançois Revol asm("mtsr 7,%0" : : "g"(vsidBase + 7));
27862caef87SFrançois Revol isync(); // synchronize context
27962caef87SFrançois Revol }
28062caef87SFrançois Revol
28162caef87SFrançois Revol
28262caef87SFrançois Revol page_table_entry *
LookupPageTableEntry(addr_t virtualAddress)28362caef87SFrançois Revol PPCVMTranslationMapClassic::LookupPageTableEntry(addr_t virtualAddress)
28462caef87SFrançois Revol {
28562caef87SFrançois Revol // lookup the vsid based off the va
28662caef87SFrançois Revol uint32 virtualSegmentID = VADDR_TO_VSID(fVSIDBase, virtualAddress);
28762caef87SFrançois Revol
28862caef87SFrançois Revol // dprintf("vm_translation_map.lookup_page_table_entry: vsid %ld, va 0x%lx\n", virtualSegmentID, virtualAddress);
28962caef87SFrançois Revol
29062caef87SFrançois Revol PPCPagingMethodClassic* m = PPCPagingMethodClassic::Method();
29162caef87SFrançois Revol
29262caef87SFrançois Revol // Search for the page table entry using the primary hash value
29362caef87SFrançois Revol
29462caef87SFrançois Revol uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, virtualAddress);
29562caef87SFrançois Revol page_table_entry_group *group = &(m->PageTable())[hash & m->PageTableHashMask()];
29662caef87SFrançois Revol
29762caef87SFrançois Revol for (int i = 0; i < 8; i++) {
29862caef87SFrançois Revol page_table_entry *entry = &group->entry[i];
29962caef87SFrançois Revol
30062caef87SFrançois Revol if (entry->virtual_segment_id == virtualSegmentID
30162caef87SFrançois Revol && entry->secondary_hash == false
30262caef87SFrançois Revol && entry->abbr_page_index == ((virtualAddress >> 22) & 0x3f))
30362caef87SFrançois Revol return entry;
30462caef87SFrançois Revol }
30562caef87SFrançois Revol
30662caef87SFrançois Revol // didn't find it, try the secondary hash value
30762caef87SFrançois Revol
30862caef87SFrançois Revol hash = page_table_entry::SecondaryHash(hash);
30962caef87SFrançois Revol group = &(m->PageTable())[hash & m->PageTableHashMask()];
31062caef87SFrançois Revol
31162caef87SFrançois Revol for (int i = 0; i < 8; i++) {
31262caef87SFrançois Revol page_table_entry *entry = &group->entry[i];
31362caef87SFrançois Revol
31462caef87SFrançois Revol if (entry->virtual_segment_id == virtualSegmentID
31562caef87SFrançois Revol && entry->secondary_hash == true
31662caef87SFrançois Revol && entry->abbr_page_index == ((virtualAddress >> 22) & 0x3f))
31762caef87SFrançois Revol return entry;
31862caef87SFrançois Revol }
31962caef87SFrançois Revol
32062caef87SFrançois Revol return NULL;
32162caef87SFrançois Revol }
32262caef87SFrançois Revol
32362caef87SFrançois Revol
32462caef87SFrançois Revol bool
RemovePageTableEntry(addr_t virtualAddress)32562caef87SFrançois Revol PPCVMTranslationMapClassic::RemovePageTableEntry(addr_t virtualAddress)
32662caef87SFrançois Revol {
32762caef87SFrançois Revol page_table_entry *entry = LookupPageTableEntry(virtualAddress);
32862caef87SFrançois Revol if (entry == NULL)
32962caef87SFrançois Revol return false;
33062caef87SFrançois Revol
33162caef87SFrançois Revol entry->valid = 0;
33262caef87SFrançois Revol ppc_sync();
33362caef87SFrançois Revol tlbie(virtualAddress);
33462caef87SFrançois Revol eieio();
33562caef87SFrançois Revol tlbsync();
33662caef87SFrançois Revol ppc_sync();
33762caef87SFrançois Revol
33862caef87SFrançois Revol return true;
33962caef87SFrançois Revol }
34062caef87SFrançois Revol
34162caef87SFrançois Revol
34262caef87SFrançois Revol size_t
MaxPagesNeededToMap(addr_t start,addr_t end) const34362caef87SFrançois Revol PPCVMTranslationMapClassic::MaxPagesNeededToMap(addr_t start, addr_t end) const
34462caef87SFrançois Revol {
34562caef87SFrançois Revol return 0;
34662caef87SFrançois Revol }
34762caef87SFrançois Revol
34862caef87SFrançois Revol
34962caef87SFrançois Revol status_t
Map(addr_t virtualAddress,phys_addr_t physicalAddress,uint32 attributes,uint32 memoryType,vm_page_reservation * reservation)35062caef87SFrançois Revol PPCVMTranslationMapClassic::Map(addr_t virtualAddress,
35162caef87SFrançois Revol phys_addr_t physicalAddress, uint32 attributes,
35262caef87SFrançois Revol uint32 memoryType, vm_page_reservation* reservation)
35362caef87SFrançois Revol {
35462caef87SFrançois Revol TRACE("map_tmap: entry pa 0x%lx va 0x%lx\n", pa, va);
35562caef87SFrançois Revol
35662caef87SFrançois Revol // lookup the vsid based off the va
35762caef87SFrançois Revol uint32 virtualSegmentID = VADDR_TO_VSID(fVSIDBase, virtualAddress);
35862caef87SFrançois Revol uint32 protection = 0;
35962caef87SFrançois Revol
36062caef87SFrançois Revol // ToDo: check this
36162caef87SFrançois Revol // all kernel mappings are R/W to supervisor code
36262caef87SFrançois Revol if (attributes & (B_READ_AREA | B_WRITE_AREA))
36362caef87SFrançois Revol protection = (attributes & B_WRITE_AREA) ? PTE_READ_WRITE : PTE_READ_ONLY;
36462caef87SFrançois Revol
36562caef87SFrançois Revol //dprintf("vm_translation_map.map_tmap: vsid %d, pa 0x%lx, va 0x%lx\n", vsid, pa, va);
36662caef87SFrançois Revol
36762caef87SFrançois Revol PPCPagingMethodClassic* m = PPCPagingMethodClassic::Method();
36862caef87SFrançois Revol
36962caef87SFrançois Revol // Search for a free page table slot using the primary hash value
37062caef87SFrançois Revol uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, virtualAddress);
37162caef87SFrançois Revol page_table_entry_group *group = &(m->PageTable())[hash & m->PageTableHashMask()];
37262caef87SFrançois Revol
37362caef87SFrançois Revol for (int i = 0; i < 8; i++) {
37462caef87SFrançois Revol page_table_entry *entry = &group->entry[i];
37562caef87SFrançois Revol
37662caef87SFrançois Revol if (entry->valid)
37762caef87SFrançois Revol continue;
37862caef87SFrançois Revol
37962caef87SFrançois Revol m->FillPageTableEntry(entry, virtualSegmentID, virtualAddress,
38062caef87SFrançois Revol physicalAddress, protection, memoryType, false);
38162caef87SFrançois Revol fMapCount++;
38262caef87SFrançois Revol return B_OK;
38362caef87SFrançois Revol }
38462caef87SFrançois Revol
38562caef87SFrançois Revol // Didn't found one, try the secondary hash value
38662caef87SFrançois Revol
38762caef87SFrançois Revol hash = page_table_entry::SecondaryHash(hash);
38862caef87SFrançois Revol group = &(m->PageTable())[hash & m->PageTableHashMask()];
38962caef87SFrançois Revol
39062caef87SFrançois Revol for (int i = 0; i < 8; i++) {
39162caef87SFrançois Revol page_table_entry *entry = &group->entry[i];
39262caef87SFrançois Revol
39362caef87SFrançois Revol if (entry->valid)
39462caef87SFrançois Revol continue;
39562caef87SFrançois Revol
39662caef87SFrançois Revol m->FillPageTableEntry(entry, virtualSegmentID, virtualAddress,
39762caef87SFrançois Revol physicalAddress, protection, memoryType, false);
39862caef87SFrançois Revol fMapCount++;
39962caef87SFrançois Revol return B_OK;
40062caef87SFrançois Revol }
40162caef87SFrançois Revol
40262caef87SFrançois Revol panic("vm_translation_map.map_tmap: hash table full\n");
40362caef87SFrançois Revol return B_ERROR;
40462caef87SFrançois Revol
40562caef87SFrançois Revol #if 0//X86
40662caef87SFrançois Revol /*
40762caef87SFrançois Revol dprintf("pgdir at 0x%x\n", pgdir);
40862caef87SFrançois Revol dprintf("index is %d\n", va / B_PAGE_SIZE / 1024);
40962caef87SFrançois Revol dprintf("final at 0x%x\n", &pgdir[va / B_PAGE_SIZE / 1024]);
41062caef87SFrançois Revol dprintf("value is 0x%x\n", *(int *)&pgdir[va / B_PAGE_SIZE / 1024]);
41162caef87SFrançois Revol dprintf("present bit is %d\n", pgdir[va / B_PAGE_SIZE / 1024].present);
41262caef87SFrançois Revol dprintf("addr is %d\n", pgdir[va / B_PAGE_SIZE / 1024].addr);
41362caef87SFrançois Revol */
41462caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt;
41562caef87SFrançois Revol
41662caef87SFrançois Revol // check to see if a page table exists for this range
41762caef87SFrançois Revol uint32 index = VADDR_TO_PDENT(va);
41862caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
41962caef87SFrançois Revol phys_addr_t pgtable;
42062caef87SFrançois Revol vm_page *page;
42162caef87SFrançois Revol
42262caef87SFrançois Revol // we need to allocate a pgtable
42362caef87SFrançois Revol page = vm_page_allocate_page(reservation,
42462caef87SFrançois Revol PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
42562caef87SFrançois Revol
42662caef87SFrançois Revol DEBUG_PAGE_ACCESS_END(page);
42762caef87SFrançois Revol
42862caef87SFrançois Revol pgtable = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE;
42962caef87SFrançois Revol
43062caef87SFrançois Revol TRACE("map_tmap: asked for free page for pgtable. 0x%lx\n", pgtable);
43162caef87SFrançois Revol
43262caef87SFrançois Revol // put it in the pgdir
43362caef87SFrançois Revol PPCPagingMethodClassic::PutPageTableInPageDir(&pd[index], pgtable,
43462caef87SFrançois Revol attributes
43562caef87SFrançois Revol | ((attributes & B_USER_PROTECTION) != 0
43662caef87SFrançois Revol ? B_WRITE_AREA : B_KERNEL_WRITE_AREA));
43762caef87SFrançois Revol
43862caef87SFrançois Revol // update any other page directories, if it maps kernel space
43962caef87SFrançois Revol if (index >= FIRST_KERNEL_PGDIR_ENT
44062caef87SFrançois Revol && index < (FIRST_KERNEL_PGDIR_ENT + NUM_KERNEL_PGDIR_ENTS)) {
44162caef87SFrançois Revol PPCPagingStructuresClassic::UpdateAllPageDirs(index, pd[index]);
44262caef87SFrançois Revol }
44362caef87SFrançois Revol
44462caef87SFrançois Revol fMapCount++;
44562caef87SFrançois Revol }
44662caef87SFrançois Revol
44762caef87SFrançois Revol // now, fill in the pentry
44862caef87SFrançois Revol Thread* thread = thread_get_current_thread();
44962caef87SFrançois Revol ThreadCPUPinner pinner(thread);
45062caef87SFrançois Revol
45162caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
45262caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
45362caef87SFrançois Revol index = VADDR_TO_PTENT(va);
45462caef87SFrançois Revol
45562caef87SFrançois Revol ASSERT_PRINT((pt[index] & PPC_PTE_PRESENT) == 0,
45662caef87SFrançois Revol "virtual address: %#" B_PRIxADDR ", existing pte: %#" B_PRIx32, va,
45762caef87SFrançois Revol pt[index]);
45862caef87SFrançois Revol
45962caef87SFrançois Revol PPCPagingMethodClassic::PutPageTableEntryInTable(&pt[index], pa, attributes,
46062caef87SFrançois Revol memoryType, fIsKernelMap);
46162caef87SFrançois Revol
46262caef87SFrançois Revol pinner.Unlock();
46362caef87SFrançois Revol
46462caef87SFrançois Revol // Note: We don't need to invalidate the TLB for this address, as previously
46562caef87SFrançois Revol // the entry was not present and the TLB doesn't cache those entries.
46662caef87SFrançois Revol
46762caef87SFrançois Revol fMapCount++;
46862caef87SFrançois Revol
46962caef87SFrançois Revol return 0;
47062caef87SFrançois Revol #endif
47162caef87SFrançois Revol }
47262caef87SFrançois Revol
47362caef87SFrançois Revol
47462caef87SFrançois Revol status_t
Unmap(addr_t start,addr_t end)47562caef87SFrançois Revol PPCVMTranslationMapClassic::Unmap(addr_t start, addr_t end)
47662caef87SFrançois Revol {
47762caef87SFrançois Revol page_table_entry *entry;
47862caef87SFrançois Revol
47962caef87SFrançois Revol start = ROUNDDOWN(start, B_PAGE_SIZE);
48062caef87SFrançois Revol end = ROUNDUP(end, B_PAGE_SIZE);
48162caef87SFrançois Revol
48262caef87SFrançois Revol if (start >= end)
48362caef87SFrançois Revol return B_OK;
48462caef87SFrançois Revol
48562caef87SFrançois Revol TRACE("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end);
48662caef87SFrançois Revol
48762caef87SFrançois Revol // dprintf("vm_translation_map.unmap_tmap: start 0x%lx, end 0x%lx\n", start, end);
48862caef87SFrançois Revol
48962caef87SFrançois Revol while (start < end) {
49062caef87SFrançois Revol if (RemovePageTableEntry(start))
49162caef87SFrançois Revol fMapCount--;
49262caef87SFrançois Revol
49362caef87SFrançois Revol start += B_PAGE_SIZE;
49462caef87SFrançois Revol }
49562caef87SFrançois Revol
49662caef87SFrançois Revol return B_OK;
49762caef87SFrançois Revol
49862caef87SFrançois Revol #if 0//X86
49962caef87SFrançois Revol
50062caef87SFrançois Revol start = ROUNDDOWN(start, B_PAGE_SIZE);
50162caef87SFrançois Revol if (start >= end)
50262caef87SFrançois Revol return B_OK;
50362caef87SFrançois Revol
50462caef87SFrançois Revol TRACE("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end);
50562caef87SFrançois Revol
50662caef87SFrançois Revol page_directory_entry *pd = fPagingStructures->pgdir_virt;
50762caef87SFrançois Revol
50862caef87SFrançois Revol do {
50962caef87SFrançois Revol int index = VADDR_TO_PDENT(start);
51062caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
51162caef87SFrançois Revol // no page table here, move the start up to access the next page
51262caef87SFrançois Revol // table
51362caef87SFrançois Revol start = ROUNDUP(start + 1, kPageTableAlignment);
51462caef87SFrançois Revol continue;
51562caef87SFrançois Revol }
51662caef87SFrançois Revol
51762caef87SFrançois Revol Thread* thread = thread_get_current_thread();
51862caef87SFrançois Revol ThreadCPUPinner pinner(thread);
51962caef87SFrançois Revol
52062caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
52162caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
52262caef87SFrançois Revol
52362caef87SFrançois Revol for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end);
52462caef87SFrançois Revol index++, start += B_PAGE_SIZE) {
52562caef87SFrançois Revol if ((pt[index] & PPC_PTE_PRESENT) == 0) {
52662caef87SFrançois Revol // page mapping not valid
52762caef87SFrançois Revol continue;
52862caef87SFrançois Revol }
52962caef87SFrançois Revol
53062caef87SFrançois Revol TRACE("unmap_tmap: removing page 0x%lx\n", start);
53162caef87SFrançois Revol
53262caef87SFrançois Revol page_table_entry oldEntry
53362caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntryFlags(&pt[index],
53462caef87SFrançois Revol PPC_PTE_PRESENT);
53562caef87SFrançois Revol fMapCount--;
53662caef87SFrançois Revol
53762caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) {
53862caef87SFrançois Revol // Note, that we only need to invalidate the address, if the
53962caef87SFrançois Revol // accessed flags was set, since only then the entry could have
54062caef87SFrançois Revol // been in any TLB.
54162caef87SFrançois Revol InvalidatePage(start);
54262caef87SFrançois Revol }
54362caef87SFrançois Revol }
54462caef87SFrançois Revol } while (start != 0 && start < end);
54562caef87SFrançois Revol
54662caef87SFrançois Revol return B_OK;
54762caef87SFrançois Revol #endif
54862caef87SFrançois Revol }
54962caef87SFrançois Revol
55062caef87SFrançois Revol
55162caef87SFrançois Revol status_t
RemapAddressRange(addr_t * _virtualAddress,size_t size,bool unmap)55262caef87SFrançois Revol PPCVMTranslationMapClassic::RemapAddressRange(addr_t *_virtualAddress,
55362caef87SFrançois Revol size_t size, bool unmap)
55462caef87SFrançois Revol {
55562caef87SFrançois Revol addr_t virtualAddress = ROUNDDOWN(*_virtualAddress, B_PAGE_SIZE);
55662caef87SFrançois Revol size = ROUNDUP(*_virtualAddress + size - virtualAddress, B_PAGE_SIZE);
55762caef87SFrançois Revol
55862caef87SFrançois Revol VMAddressSpace *addressSpace = VMAddressSpace::Kernel();
55962caef87SFrançois Revol
56062caef87SFrançois Revol // reserve space in the address space
56162caef87SFrançois Revol void *newAddress = NULL;
56262caef87SFrançois Revol status_t error = vm_reserve_address_range(addressSpace->ID(), &newAddress,
56362caef87SFrançois Revol B_ANY_KERNEL_ADDRESS, size, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
56462caef87SFrançois Revol if (error != B_OK)
56562caef87SFrançois Revol return error;
56662caef87SFrançois Revol
56762caef87SFrançois Revol // get the area's first physical page
56862caef87SFrançois Revol page_table_entry *entry = LookupPageTableEntry(virtualAddress);
56962caef87SFrançois Revol if (!entry)
57062caef87SFrançois Revol return B_ERROR;
57162caef87SFrançois Revol phys_addr_t physicalBase = (phys_addr_t)entry->physical_page_number << 12;
57262caef87SFrançois Revol
57362caef87SFrançois Revol // map the pages
57462caef87SFrançois Revol error = ppc_map_address_range((addr_t)newAddress, physicalBase, size);
57562caef87SFrançois Revol if (error != B_OK)
57662caef87SFrançois Revol return error;
57762caef87SFrançois Revol
57862caef87SFrançois Revol *_virtualAddress = (addr_t)newAddress;
57962caef87SFrançois Revol
58062caef87SFrançois Revol // unmap the old pages
58162caef87SFrançois Revol if (unmap)
58262caef87SFrançois Revol ppc_unmap_address_range(virtualAddress, size);
58362caef87SFrançois Revol
58462caef87SFrançois Revol return B_OK;
58562caef87SFrançois Revol }
58662caef87SFrançois Revol
58762caef87SFrançois Revol
58862caef87SFrançois Revol status_t
DebugMarkRangePresent(addr_t start,addr_t end,bool markPresent)58962caef87SFrançois Revol PPCVMTranslationMapClassic::DebugMarkRangePresent(addr_t start, addr_t end,
59062caef87SFrançois Revol bool markPresent)
59162caef87SFrançois Revol {
59262caef87SFrançois Revol panic("%s: UNIMPLEMENTED", __FUNCTION__);
59362caef87SFrançois Revol return B_ERROR;
59462caef87SFrançois Revol #if 0//X86
59562caef87SFrançois Revol start = ROUNDDOWN(start, B_PAGE_SIZE);
59662caef87SFrançois Revol if (start >= end)
59762caef87SFrançois Revol return B_OK;
59862caef87SFrançois Revol
59962caef87SFrançois Revol page_directory_entry *pd = fPagingStructures->pgdir_virt;
60062caef87SFrançois Revol
60162caef87SFrançois Revol do {
60262caef87SFrançois Revol int index = VADDR_TO_PDENT(start);
60362caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
60462caef87SFrançois Revol // no page table here, move the start up to access the next page
60562caef87SFrançois Revol // table
60662caef87SFrançois Revol start = ROUNDUP(start + 1, kPageTableAlignment);
60762caef87SFrançois Revol continue;
60862caef87SFrançois Revol }
60962caef87SFrançois Revol
61062caef87SFrançois Revol Thread* thread = thread_get_current_thread();
61162caef87SFrançois Revol ThreadCPUPinner pinner(thread);
61262caef87SFrançois Revol
61362caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
61462caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
61562caef87SFrançois Revol
61662caef87SFrançois Revol for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end);
61762caef87SFrançois Revol index++, start += B_PAGE_SIZE) {
61862caef87SFrançois Revol if ((pt[index] & PPC_PTE_PRESENT) == 0) {
61962caef87SFrançois Revol if (!markPresent)
62062caef87SFrançois Revol continue;
62162caef87SFrançois Revol
62262caef87SFrançois Revol PPCPagingMethodClassic::SetPageTableEntryFlags(&pt[index],
62362caef87SFrançois Revol PPC_PTE_PRESENT);
62462caef87SFrançois Revol } else {
62562caef87SFrançois Revol if (markPresent)
62662caef87SFrançois Revol continue;
62762caef87SFrançois Revol
62862caef87SFrançois Revol page_table_entry oldEntry
62962caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntryFlags(&pt[index],
63062caef87SFrançois Revol PPC_PTE_PRESENT);
63162caef87SFrançois Revol
63262caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) {
63362caef87SFrançois Revol // Note, that we only need to invalidate the address, if the
63462caef87SFrançois Revol // accessed flags was set, since only then the entry could
63562caef87SFrançois Revol // have been in any TLB.
63662caef87SFrançois Revol InvalidatePage(start);
63762caef87SFrançois Revol }
63862caef87SFrançois Revol }
63962caef87SFrançois Revol }
64062caef87SFrançois Revol } while (start != 0 && start < end);
64162caef87SFrançois Revol
64262caef87SFrançois Revol return B_OK;
64362caef87SFrançois Revol #endif
64462caef87SFrançois Revol }
64562caef87SFrançois Revol
64662caef87SFrançois Revol
64762caef87SFrançois Revol /*! Caller must have locked the cache of the page to be unmapped.
64862caef87SFrançois Revol This object shouldn't be locked.
64962caef87SFrançois Revol */
65062caef87SFrançois Revol status_t
UnmapPage(VMArea * area,addr_t address,bool updatePageQueue)65162caef87SFrançois Revol PPCVMTranslationMapClassic::UnmapPage(VMArea* area, addr_t address,
65262caef87SFrançois Revol bool updatePageQueue)
65362caef87SFrançois Revol {
65462caef87SFrançois Revol ASSERT(address % B_PAGE_SIZE == 0);
65562caef87SFrançois Revol
65662caef87SFrançois Revol RecursiveLocker locker(fLock);
65762caef87SFrançois Revol
65862caef87SFrançois Revol if (area->cache_type == CACHE_TYPE_DEVICE) {
65962caef87SFrançois Revol if (!RemovePageTableEntry(address))
66062caef87SFrançois Revol return B_ENTRY_NOT_FOUND;
66162caef87SFrançois Revol
66262caef87SFrançois Revol fMapCount--;
66362caef87SFrançois Revol return B_OK;
66462caef87SFrançois Revol }
66562caef87SFrançois Revol
66662caef87SFrançois Revol page_table_entry* entry = LookupPageTableEntry(address);
66762caef87SFrançois Revol if (entry == NULL)
66862caef87SFrançois Revol return B_ENTRY_NOT_FOUND;
66962caef87SFrançois Revol
67062caef87SFrançois Revol page_num_t pageNumber = entry->physical_page_number;
67162caef87SFrançois Revol bool accessed = entry->referenced;
67262caef87SFrançois Revol bool modified = entry->changed;
67362caef87SFrançois Revol
67462caef87SFrançois Revol RemovePageTableEntry(address);
67562caef87SFrançois Revol
67662caef87SFrançois Revol fMapCount--;
67762caef87SFrançois Revol
67862caef87SFrançois Revol locker.Detach();
67962caef87SFrançois Revol // PageUnmapped() will unlock for us
68062caef87SFrançois Revol
68162caef87SFrançois Revol PageUnmapped(area, pageNumber, accessed, modified, updatePageQueue);
68262caef87SFrançois Revol
68362caef87SFrançois Revol return B_OK;
68462caef87SFrançois Revol
68562caef87SFrançois Revol #if 0//X86
68662caef87SFrançois Revol
68762caef87SFrançois Revol ASSERT(address % B_PAGE_SIZE == 0);
68862caef87SFrançois Revol
68962caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt;
69062caef87SFrançois Revol
69162caef87SFrançois Revol TRACE("PPCVMTranslationMapClassic::UnmapPage(%#" B_PRIxADDR ")\n", address);
69262caef87SFrançois Revol
69362caef87SFrançois Revol RecursiveLocker locker(fLock);
69462caef87SFrançois Revol
69562caef87SFrançois Revol int index = VADDR_TO_PDENT(address);
69662caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0)
69762caef87SFrançois Revol return B_ENTRY_NOT_FOUND;
69862caef87SFrançois Revol
69962caef87SFrançois Revol ThreadCPUPinner pinner(thread_get_current_thread());
70062caef87SFrançois Revol
70162caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
70262caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
70362caef87SFrançois Revol
70462caef87SFrançois Revol index = VADDR_TO_PTENT(address);
70562caef87SFrançois Revol page_table_entry oldEntry = PPCPagingMethodClassic::ClearPageTableEntry(
70662caef87SFrançois Revol &pt[index]);
70762caef87SFrançois Revol
70862caef87SFrançois Revol pinner.Unlock();
70962caef87SFrançois Revol
71062caef87SFrançois Revol if ((oldEntry & PPC_PTE_PRESENT) == 0) {
71162caef87SFrançois Revol // page mapping not valid
71262caef87SFrançois Revol return B_ENTRY_NOT_FOUND;
71362caef87SFrançois Revol }
71462caef87SFrançois Revol
71562caef87SFrançois Revol fMapCount--;
71662caef87SFrançois Revol
71762caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) {
71862caef87SFrançois Revol // Note, that we only need to invalidate the address, if the
71962caef87SFrançois Revol // accessed flags was set, since only then the entry could have been
72062caef87SFrançois Revol // in any TLB.
72162caef87SFrançois Revol InvalidatePage(address);
72262caef87SFrançois Revol Flush();
72362caef87SFrançois Revol
72462caef87SFrançois Revol // NOTE: Between clearing the page table entry and Flush() other
72562caef87SFrançois Revol // processors (actually even this processor with another thread of the
72662caef87SFrançois Revol // same team) could still access the page in question via their cached
72762caef87SFrançois Revol // entry. We can obviously lose a modified flag in this case, with the
72862caef87SFrançois Revol // effect that the page looks unmodified (and might thus be recycled),
72962caef87SFrançois Revol // but is actually modified.
73062caef87SFrançois Revol // In most cases this is harmless, but for vm_remove_all_page_mappings()
73162caef87SFrançois Revol // this is actually a problem.
73262caef87SFrançois Revol // Interestingly FreeBSD seems to ignore this problem as well
73362caef87SFrançois Revol // (cf. pmap_remove_all()), unless I've missed something.
73462caef87SFrançois Revol }
73562caef87SFrançois Revol
73662caef87SFrançois Revol locker.Detach();
73762caef87SFrançois Revol // PageUnmapped() will unlock for us
73862caef87SFrançois Revol
73962caef87SFrançois Revol PageUnmapped(area, (oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
74062caef87SFrançois Revol (oldEntry & PPC_PTE_ACCESSED) != 0, (oldEntry & PPC_PTE_DIRTY) != 0,
74162caef87SFrançois Revol updatePageQueue);
74262caef87SFrançois Revol
74362caef87SFrançois Revol return B_OK;
74462caef87SFrançois Revol #endif
74562caef87SFrançois Revol }
74662caef87SFrançois Revol
74762caef87SFrançois Revol
74862caef87SFrançois Revol void
UnmapPages(VMArea * area,addr_t base,size_t size,bool updatePageQueue)74962caef87SFrançois Revol PPCVMTranslationMapClassic::UnmapPages(VMArea* area, addr_t base, size_t size,
75062caef87SFrançois Revol bool updatePageQueue)
75162caef87SFrançois Revol {
75262caef87SFrançois Revol panic("%s: UNIMPLEMENTED", __FUNCTION__);
75362caef87SFrançois Revol #if 0//X86
75462caef87SFrançois Revol if (size == 0)
75562caef87SFrançois Revol return;
75662caef87SFrançois Revol
75762caef87SFrançois Revol addr_t start = base;
75862caef87SFrançois Revol addr_t end = base + size - 1;
75962caef87SFrançois Revol
76062caef87SFrançois Revol TRACE("PPCVMTranslationMapClassic::UnmapPages(%p, %#" B_PRIxADDR ", %#"
76162caef87SFrançois Revol B_PRIxADDR ")\n", area, start, end);
76262caef87SFrançois Revol
76362caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt;
76462caef87SFrançois Revol
76562caef87SFrançois Revol VMAreaMappings queue;
76662caef87SFrançois Revol
76762caef87SFrançois Revol RecursiveLocker locker(fLock);
76862caef87SFrançois Revol
76962caef87SFrançois Revol do {
77062caef87SFrançois Revol int index = VADDR_TO_PDENT(start);
77162caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
77262caef87SFrançois Revol // no page table here, move the start up to access the next page
77362caef87SFrançois Revol // table
77462caef87SFrançois Revol start = ROUNDUP(start + 1, kPageTableAlignment);
77562caef87SFrançois Revol continue;
77662caef87SFrançois Revol }
77762caef87SFrançois Revol
77862caef87SFrançois Revol Thread* thread = thread_get_current_thread();
77962caef87SFrançois Revol ThreadCPUPinner pinner(thread);
78062caef87SFrançois Revol
78162caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
78262caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
78362caef87SFrançois Revol
78462caef87SFrançois Revol for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end);
78562caef87SFrançois Revol index++, start += B_PAGE_SIZE) {
78662caef87SFrançois Revol page_table_entry oldEntry
78762caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntry(&pt[index]);
78862caef87SFrançois Revol if ((oldEntry & PPC_PTE_PRESENT) == 0)
78962caef87SFrançois Revol continue;
79062caef87SFrançois Revol
79162caef87SFrançois Revol fMapCount--;
79262caef87SFrançois Revol
79362caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) {
79462caef87SFrançois Revol // Note, that we only need to invalidate the address, if the
79562caef87SFrançois Revol // accessed flags was set, since only then the entry could have
79662caef87SFrançois Revol // been in any TLB.
79762caef87SFrançois Revol InvalidatePage(start);
79862caef87SFrançois Revol }
79962caef87SFrançois Revol
80062caef87SFrançois Revol if (area->cache_type != CACHE_TYPE_DEVICE) {
80162caef87SFrançois Revol // get the page
80262caef87SFrançois Revol vm_page* page = vm_lookup_page(
80362caef87SFrançois Revol (oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE);
80462caef87SFrançois Revol ASSERT(page != NULL);
80562caef87SFrançois Revol
80662caef87SFrançois Revol DEBUG_PAGE_ACCESS_START(page);
80762caef87SFrançois Revol
80862caef87SFrançois Revol // transfer the accessed/dirty flags to the page
80962caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0)
81062caef87SFrançois Revol page->accessed = true;
81162caef87SFrançois Revol if ((oldEntry & PPC_PTE_DIRTY) != 0)
81262caef87SFrançois Revol page->modified = true;
81362caef87SFrançois Revol
81462caef87SFrançois Revol // remove the mapping object/decrement the wired_count of the
81562caef87SFrançois Revol // page
81662caef87SFrançois Revol if (area->wiring == B_NO_LOCK) {
81762caef87SFrançois Revol vm_page_mapping* mapping = NULL;
81862caef87SFrançois Revol vm_page_mappings::Iterator iterator
81962caef87SFrançois Revol = page->mappings.GetIterator();
82062caef87SFrançois Revol while ((mapping = iterator.Next()) != NULL) {
82162caef87SFrançois Revol if (mapping->area == area)
82262caef87SFrançois Revol break;
82362caef87SFrançois Revol }
82462caef87SFrançois Revol
82562caef87SFrançois Revol ASSERT(mapping != NULL);
82662caef87SFrançois Revol
82762caef87SFrançois Revol area->mappings.Remove(mapping);
82862caef87SFrançois Revol page->mappings.Remove(mapping);
82962caef87SFrançois Revol queue.Add(mapping);
83062caef87SFrançois Revol } else
83162caef87SFrançois Revol page->DecrementWiredCount();
83262caef87SFrançois Revol
83362caef87SFrançois Revol if (!page->IsMapped()) {
83462caef87SFrançois Revol atomic_add(&gMappedPagesCount, -1);
83562caef87SFrançois Revol
83662caef87SFrançois Revol if (updatePageQueue) {
83762caef87SFrançois Revol if (page->Cache()->temporary)
83862caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_INACTIVE);
83962caef87SFrançois Revol else if (page->modified)
84062caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_MODIFIED);
84162caef87SFrançois Revol else
84262caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_CACHED);
84362caef87SFrançois Revol }
84462caef87SFrançois Revol }
84562caef87SFrançois Revol
84662caef87SFrançois Revol DEBUG_PAGE_ACCESS_END(page);
84762caef87SFrançois Revol }
84862caef87SFrançois Revol }
84962caef87SFrançois Revol
85062caef87SFrançois Revol Flush();
85162caef87SFrançois Revol // flush explicitly, since we directly use the lock
85262caef87SFrançois Revol } while (start != 0 && start < end);
85362caef87SFrançois Revol
85462caef87SFrançois Revol // TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not
85562caef87SFrançois Revol // really critical here, as in all cases this method is used, the unmapped
85662caef87SFrançois Revol // area range is unmapped for good (resized/cut) and the pages will likely
85762caef87SFrançois Revol // be freed.
85862caef87SFrançois Revol
85962caef87SFrançois Revol locker.Unlock();
86062caef87SFrançois Revol
86162caef87SFrançois Revol // free removed mappings
86262caef87SFrançois Revol bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
86362caef87SFrançois Revol uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY
86462caef87SFrançois Revol | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0);
86562caef87SFrançois Revol while (vm_page_mapping* mapping = queue.RemoveHead())
866*08c53ca9SAugustin Cavalier vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
86762caef87SFrançois Revol #endif
86862caef87SFrançois Revol }
86962caef87SFrançois Revol
87062caef87SFrançois Revol
87162caef87SFrançois Revol void
UnmapArea(VMArea * area,bool deletingAddressSpace,bool ignoreTopCachePageFlags)87262caef87SFrançois Revol PPCVMTranslationMapClassic::UnmapArea(VMArea* area, bool deletingAddressSpace,
87362caef87SFrançois Revol bool ignoreTopCachePageFlags)
87462caef87SFrançois Revol {
87562caef87SFrançois Revol panic("%s: UNIMPLEMENTED", __FUNCTION__);
87662caef87SFrançois Revol #if 0//X86
87762caef87SFrançois Revol if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
87862caef87SFrançois Revol PPCVMTranslationMapClassic::UnmapPages(area, area->Base(), area->Size(),
87962caef87SFrançois Revol true);
88062caef87SFrançois Revol return;
88162caef87SFrançois Revol }
88262caef87SFrançois Revol
88362caef87SFrançois Revol bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags;
88462caef87SFrançois Revol
88562caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt;
88662caef87SFrançois Revol
88762caef87SFrançois Revol RecursiveLocker locker(fLock);
88862caef87SFrançois Revol
88962caef87SFrançois Revol VMAreaMappings mappings;
89062caef87SFrançois Revol mappings.MoveFrom(&area->mappings);
89162caef87SFrançois Revol
89262caef87SFrançois Revol for (VMAreaMappings::Iterator it = mappings.GetIterator();
89362caef87SFrançois Revol vm_page_mapping* mapping = it.Next();) {
89462caef87SFrançois Revol vm_page* page = mapping->page;
89562caef87SFrançois Revol page->mappings.Remove(mapping);
89662caef87SFrançois Revol
89762caef87SFrançois Revol VMCache* cache = page->Cache();
89862caef87SFrançois Revol
89962caef87SFrançois Revol bool pageFullyUnmapped = false;
90062caef87SFrançois Revol if (!page->IsMapped()) {
90162caef87SFrançois Revol atomic_add(&gMappedPagesCount, -1);
90262caef87SFrançois Revol pageFullyUnmapped = true;
90362caef87SFrançois Revol }
90462caef87SFrançois Revol
90562caef87SFrançois Revol if (unmapPages || cache != area->cache) {
90662caef87SFrançois Revol addr_t address = area->Base()
90762caef87SFrançois Revol + ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset);
90862caef87SFrançois Revol
90962caef87SFrançois Revol int index = VADDR_TO_PDENT(address);
91062caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
91162caef87SFrançois Revol panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
91262caef87SFrançois Revol "has no page dir entry", page, area, address);
91362caef87SFrançois Revol continue;
91462caef87SFrançois Revol }
91562caef87SFrançois Revol
91662caef87SFrançois Revol ThreadCPUPinner pinner(thread_get_current_thread());
91762caef87SFrançois Revol
91862caef87SFrançois Revol page_table_entry* pt
91962caef87SFrançois Revol = (page_table_entry*)fPageMapper->GetPageTableAt(
92062caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
92162caef87SFrançois Revol page_table_entry oldEntry
92262caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntry(
92362caef87SFrançois Revol &pt[VADDR_TO_PTENT(address)]);
92462caef87SFrançois Revol
92562caef87SFrançois Revol pinner.Unlock();
92662caef87SFrançois Revol
92762caef87SFrançois Revol if ((oldEntry & PPC_PTE_PRESENT) == 0) {
92862caef87SFrançois Revol panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
92962caef87SFrançois Revol "has no page table entry", page, area, address);
93062caef87SFrançois Revol continue;
93162caef87SFrançois Revol }
93262caef87SFrançois Revol
93362caef87SFrançois Revol // transfer the accessed/dirty flags to the page and invalidate
93462caef87SFrançois Revol // the mapping, if necessary
93562caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) {
93662caef87SFrançois Revol page->accessed = true;
93762caef87SFrançois Revol
93862caef87SFrançois Revol if (!deletingAddressSpace)
93962caef87SFrançois Revol InvalidatePage(address);
94062caef87SFrançois Revol }
94162caef87SFrançois Revol
94262caef87SFrançois Revol if ((oldEntry & PPC_PTE_DIRTY) != 0)
94362caef87SFrançois Revol page->modified = true;
94462caef87SFrançois Revol
94562caef87SFrançois Revol if (pageFullyUnmapped) {
94662caef87SFrançois Revol DEBUG_PAGE_ACCESS_START(page);
94762caef87SFrançois Revol
94862caef87SFrançois Revol if (cache->temporary)
94962caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_INACTIVE);
95062caef87SFrançois Revol else if (page->modified)
95162caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_MODIFIED);
95262caef87SFrançois Revol else
95362caef87SFrançois Revol vm_page_set_state(page, PAGE_STATE_CACHED);
95462caef87SFrançois Revol
95562caef87SFrançois Revol DEBUG_PAGE_ACCESS_END(page);
95662caef87SFrançois Revol }
95762caef87SFrançois Revol }
95862caef87SFrançois Revol
95962caef87SFrançois Revol fMapCount--;
96062caef87SFrançois Revol }
96162caef87SFrançois Revol
96262caef87SFrançois Revol Flush();
96362caef87SFrançois Revol // flush explicitely, since we directly use the lock
96462caef87SFrançois Revol
96562caef87SFrançois Revol locker.Unlock();
96662caef87SFrançois Revol
96762caef87SFrançois Revol bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
96862caef87SFrançois Revol uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY
96962caef87SFrançois Revol | (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0);
97062caef87SFrançois Revol while (vm_page_mapping* mapping = mappings.RemoveHead())
971*08c53ca9SAugustin Cavalier vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
97262caef87SFrançois Revol #endif
97362caef87SFrançois Revol }
97462caef87SFrançois Revol
97562caef87SFrançois Revol
97662caef87SFrançois Revol status_t
Query(addr_t va,phys_addr_t * _outPhysical,uint32 * _outFlags)97762caef87SFrançois Revol PPCVMTranslationMapClassic::Query(addr_t va, phys_addr_t *_outPhysical,
97862caef87SFrançois Revol uint32 *_outFlags)
97962caef87SFrançois Revol {
98062caef87SFrançois Revol page_table_entry *entry;
98162caef87SFrançois Revol
98262caef87SFrançois Revol // default the flags to not present
98362caef87SFrançois Revol *_outFlags = 0;
98462caef87SFrançois Revol *_outPhysical = 0;
98562caef87SFrançois Revol
98662caef87SFrançois Revol entry = LookupPageTableEntry(va);
98762caef87SFrançois Revol if (entry == NULL)
98862caef87SFrançois Revol return B_NO_ERROR;
98962caef87SFrançois Revol
99062caef87SFrançois Revol // ToDo: check this!
99162caef87SFrançois Revol if (IS_KERNEL_ADDRESS(va))
99262caef87SFrançois Revol *_outFlags |= B_KERNEL_READ_AREA | (entry->page_protection == PTE_READ_ONLY ? 0 : B_KERNEL_WRITE_AREA);
99362caef87SFrançois Revol else
99462caef87SFrançois Revol *_outFlags |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | (entry->page_protection == PTE_READ_ONLY ? 0 : B_WRITE_AREA);
99562caef87SFrançois Revol
99662caef87SFrançois Revol *_outFlags |= entry->changed ? PAGE_MODIFIED : 0;
99762caef87SFrançois Revol *_outFlags |= entry->referenced ? PAGE_ACCESSED : 0;
99862caef87SFrançois Revol *_outFlags |= entry->valid ? PAGE_PRESENT : 0;
99962caef87SFrançois Revol
100062caef87SFrançois Revol *_outPhysical = entry->physical_page_number * B_PAGE_SIZE;
100162caef87SFrançois Revol
100262caef87SFrançois Revol return B_OK;
100362caef87SFrançois Revol
100462caef87SFrançois Revol #if 0//X86
100562caef87SFrançois Revol // default the flags to not present
100662caef87SFrançois Revol *_flags = 0;
100762caef87SFrançois Revol *_physical = 0;
100862caef87SFrançois Revol
100962caef87SFrançois Revol int index = VADDR_TO_PDENT(va);
101062caef87SFrançois Revol page_directory_entry *pd = fPagingStructures->pgdir_virt;
101162caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
101262caef87SFrançois Revol // no pagetable here
101362caef87SFrançois Revol return B_OK;
101462caef87SFrançois Revol }
101562caef87SFrançois Revol
101662caef87SFrançois Revol Thread* thread = thread_get_current_thread();
101762caef87SFrançois Revol ThreadCPUPinner pinner(thread);
101862caef87SFrançois Revol
101962caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
102062caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
102162caef87SFrançois Revol page_table_entry entry = pt[VADDR_TO_PTENT(va)];
102262caef87SFrançois Revol
102362caef87SFrançois Revol *_physical = entry & PPC_PDE_ADDRESS_MASK;
102462caef87SFrançois Revol
102562caef87SFrançois Revol // read in the page state flags
102662caef87SFrançois Revol if ((entry & PPC_PTE_USER) != 0) {
102762caef87SFrançois Revol *_flags |= ((entry & PPC_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0)
102862caef87SFrançois Revol | B_READ_AREA;
102962caef87SFrançois Revol }
103062caef87SFrançois Revol
103162caef87SFrançois Revol *_flags |= ((entry & PPC_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0)
103262caef87SFrançois Revol | B_KERNEL_READ_AREA
103362caef87SFrançois Revol | ((entry & PPC_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
103462caef87SFrançois Revol | ((entry & PPC_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
103562caef87SFrançois Revol | ((entry & PPC_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
103662caef87SFrançois Revol
103762caef87SFrançois Revol pinner.Unlock();
103862caef87SFrançois Revol
103962caef87SFrançois Revol TRACE("query_tmap: returning pa 0x%lx for va 0x%lx\n", *_physical, va);
104062caef87SFrançois Revol
104162caef87SFrançois Revol return B_OK;
104262caef87SFrançois Revol #endif
104362caef87SFrançois Revol }
104462caef87SFrançois Revol
104562caef87SFrançois Revol
104662caef87SFrançois Revol status_t
QueryInterrupt(addr_t virtualAddress,phys_addr_t * _physicalAddress,uint32 * _flags)104762caef87SFrançois Revol PPCVMTranslationMapClassic::QueryInterrupt(addr_t virtualAddress,
104862caef87SFrançois Revol phys_addr_t *_physicalAddress, uint32 *_flags)
104962caef87SFrançois Revol {
105062caef87SFrançois Revol return PPCVMTranslationMapClassic::Query(virtualAddress, _physicalAddress, _flags);
105162caef87SFrançois Revol
105262caef87SFrançois Revol #if 0//X86
105362caef87SFrançois Revol *_flags = 0;
105462caef87SFrançois Revol *_physical = 0;
105562caef87SFrançois Revol
105662caef87SFrançois Revol int index = VADDR_TO_PDENT(va);
105762caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt;
105862caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
105962caef87SFrançois Revol // no pagetable here
106062caef87SFrançois Revol return B_OK;
106162caef87SFrançois Revol }
106262caef87SFrançois Revol
106362caef87SFrançois Revol // map page table entry
106462caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)PPCPagingMethodClassic::Method()
106562caef87SFrançois Revol ->PhysicalPageMapper()->InterruptGetPageTableAt(
106662caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
106762caef87SFrançois Revol page_table_entry entry = pt[VADDR_TO_PTENT(va)];
106862caef87SFrançois Revol
106962caef87SFrançois Revol *_physical = entry & PPC_PDE_ADDRESS_MASK;
107062caef87SFrançois Revol
107162caef87SFrançois Revol // read in the page state flags
107262caef87SFrançois Revol if ((entry & PPC_PTE_USER) != 0) {
107362caef87SFrançois Revol *_flags |= ((entry & PPC_PTE_WRITABLE) != 0 ? B_WRITE_AREA : 0)
107462caef87SFrançois Revol | B_READ_AREA;
107562caef87SFrançois Revol }
107662caef87SFrançois Revol
107762caef87SFrançois Revol *_flags |= ((entry & PPC_PTE_WRITABLE) != 0 ? B_KERNEL_WRITE_AREA : 0)
107862caef87SFrançois Revol | B_KERNEL_READ_AREA
107962caef87SFrançois Revol | ((entry & PPC_PTE_DIRTY) != 0 ? PAGE_MODIFIED : 0)
108062caef87SFrançois Revol | ((entry & PPC_PTE_ACCESSED) != 0 ? PAGE_ACCESSED : 0)
108162caef87SFrançois Revol | ((entry & PPC_PTE_PRESENT) != 0 ? PAGE_PRESENT : 0);
108262caef87SFrançois Revol
108362caef87SFrançois Revol return B_OK;
108462caef87SFrançois Revol #endif
108562caef87SFrançois Revol }
108662caef87SFrançois Revol
108762caef87SFrançois Revol
108862caef87SFrançois Revol status_t
Protect(addr_t start,addr_t end,uint32 attributes,uint32 memoryType)108962caef87SFrançois Revol PPCVMTranslationMapClassic::Protect(addr_t start, addr_t end, uint32 attributes,
109062caef87SFrançois Revol uint32 memoryType)
109162caef87SFrançois Revol {
109262caef87SFrançois Revol // XXX finish
109362caef87SFrançois Revol return B_ERROR;
109462caef87SFrançois Revol #if 0//X86
109562caef87SFrançois Revol start = ROUNDDOWN(start, B_PAGE_SIZE);
109662caef87SFrançois Revol if (start >= end)
109762caef87SFrançois Revol return B_OK;
109862caef87SFrançois Revol
109962caef87SFrançois Revol TRACE("protect_tmap: pages 0x%lx to 0x%lx, attributes %lx\n", start, end,
110062caef87SFrançois Revol attributes);
110162caef87SFrançois Revol
110262caef87SFrançois Revol // compute protection flags
110362caef87SFrançois Revol uint32 newProtectionFlags = 0;
110462caef87SFrançois Revol if ((attributes & B_USER_PROTECTION) != 0) {
110562caef87SFrançois Revol newProtectionFlags = PPC_PTE_USER;
110662caef87SFrançois Revol if ((attributes & B_WRITE_AREA) != 0)
110762caef87SFrançois Revol newProtectionFlags |= PPC_PTE_WRITABLE;
110862caef87SFrançois Revol } else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
110962caef87SFrançois Revol newProtectionFlags = PPC_PTE_WRITABLE;
111062caef87SFrançois Revol
111162caef87SFrançois Revol page_directory_entry *pd = fPagingStructures->pgdir_virt;
111262caef87SFrançois Revol
111362caef87SFrançois Revol do {
111462caef87SFrançois Revol int index = VADDR_TO_PDENT(start);
111562caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
111662caef87SFrançois Revol // no page table here, move the start up to access the next page
111762caef87SFrançois Revol // table
111862caef87SFrançois Revol start = ROUNDUP(start + 1, kPageTableAlignment);
111962caef87SFrançois Revol continue;
112062caef87SFrançois Revol }
112162caef87SFrançois Revol
112262caef87SFrançois Revol Thread* thread = thread_get_current_thread();
112362caef87SFrançois Revol ThreadCPUPinner pinner(thread);
112462caef87SFrançois Revol
112562caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
112662caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
112762caef87SFrançois Revol
112862caef87SFrançois Revol for (index = VADDR_TO_PTENT(start); index < 1024 && start < end;
112962caef87SFrançois Revol index++, start += B_PAGE_SIZE) {
113062caef87SFrançois Revol page_table_entry entry = pt[index];
113162caef87SFrançois Revol if ((entry & PPC_PTE_PRESENT) == 0) {
113262caef87SFrançois Revol // page mapping not valid
113362caef87SFrançois Revol continue;
113462caef87SFrançois Revol }
113562caef87SFrançois Revol
113662caef87SFrançois Revol TRACE("protect_tmap: protect page 0x%lx\n", start);
113762caef87SFrançois Revol
113862caef87SFrançois Revol // set the new protection flags -- we want to do that atomically,
113962caef87SFrançois Revol // without changing the accessed or dirty flag
114062caef87SFrançois Revol page_table_entry oldEntry;
114162caef87SFrançois Revol while (true) {
114262caef87SFrançois Revol oldEntry = PPCPagingMethodClassic::TestAndSetPageTableEntry(
114362caef87SFrançois Revol &pt[index],
114462caef87SFrançois Revol (entry & ~(PPC_PTE_PROTECTION_MASK
114562caef87SFrançois Revol | PPC_PTE_MEMORY_TYPE_MASK))
114662caef87SFrançois Revol | newProtectionFlags
114762caef87SFrançois Revol | PPCPagingMethodClassic::MemoryTypeToPageTableEntryFlags(
114862caef87SFrançois Revol memoryType),
114962caef87SFrançois Revol entry);
115062caef87SFrançois Revol if (oldEntry == entry)
115162caef87SFrançois Revol break;
115262caef87SFrançois Revol entry = oldEntry;
115362caef87SFrançois Revol }
115462caef87SFrançois Revol
115562caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) {
115662caef87SFrançois Revol // Note, that we only need to invalidate the address, if the
115762caef87SFrançois Revol // accessed flag was set, since only then the entry could have
115862caef87SFrançois Revol // been in any TLB.
115962caef87SFrançois Revol InvalidatePage(start);
116062caef87SFrançois Revol }
116162caef87SFrançois Revol }
116262caef87SFrançois Revol } while (start != 0 && start < end);
116362caef87SFrançois Revol
116462caef87SFrançois Revol return B_OK;
116562caef87SFrançois Revol #endif
116662caef87SFrançois Revol }
116762caef87SFrançois Revol
116862caef87SFrançois Revol
116962caef87SFrançois Revol status_t
ClearFlags(addr_t virtualAddress,uint32 flags)117062caef87SFrançois Revol PPCVMTranslationMapClassic::ClearFlags(addr_t virtualAddress, uint32 flags)
117162caef87SFrançois Revol {
117262caef87SFrançois Revol page_table_entry *entry = LookupPageTableEntry(virtualAddress);
117362caef87SFrançois Revol if (entry == NULL)
117462caef87SFrançois Revol return B_NO_ERROR;
117562caef87SFrançois Revol
117662caef87SFrançois Revol bool modified = false;
117762caef87SFrançois Revol
117862caef87SFrançois Revol // clear the bits
117962caef87SFrançois Revol if (flags & PAGE_MODIFIED && entry->changed) {
118062caef87SFrançois Revol entry->changed = false;
118162caef87SFrançois Revol modified = true;
118262caef87SFrançois Revol }
118362caef87SFrançois Revol if (flags & PAGE_ACCESSED && entry->referenced) {
118462caef87SFrançois Revol entry->referenced = false;
118562caef87SFrançois Revol modified = true;
118662caef87SFrançois Revol }
118762caef87SFrançois Revol
118862caef87SFrançois Revol // synchronize
118962caef87SFrançois Revol if (modified) {
119062caef87SFrançois Revol tlbie(virtualAddress);
119162caef87SFrançois Revol eieio();
119262caef87SFrançois Revol tlbsync();
119362caef87SFrançois Revol ppc_sync();
119462caef87SFrançois Revol }
119562caef87SFrançois Revol
119662caef87SFrançois Revol return B_OK;
119762caef87SFrançois Revol
119862caef87SFrançois Revol #if 0//X86
119962caef87SFrançois Revol int index = VADDR_TO_PDENT(va);
120062caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt;
120162caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0) {
120262caef87SFrançois Revol // no pagetable here
120362caef87SFrançois Revol return B_OK;
120462caef87SFrançois Revol }
120562caef87SFrançois Revol
120662caef87SFrançois Revol uint32 flagsToClear = ((flags & PAGE_MODIFIED) ? PPC_PTE_DIRTY : 0)
120762caef87SFrançois Revol | ((flags & PAGE_ACCESSED) ? PPC_PTE_ACCESSED : 0);
120862caef87SFrançois Revol
120962caef87SFrançois Revol Thread* thread = thread_get_current_thread();
121062caef87SFrançois Revol ThreadCPUPinner pinner(thread);
121162caef87SFrançois Revol
121262caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
121362caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
121462caef87SFrançois Revol index = VADDR_TO_PTENT(va);
121562caef87SFrançois Revol
121662caef87SFrançois Revol // clear out the flags we've been requested to clear
121762caef87SFrançois Revol page_table_entry oldEntry
121862caef87SFrançois Revol = PPCPagingMethodClassic::ClearPageTableEntryFlags(&pt[index],
121962caef87SFrançois Revol flagsToClear);
122062caef87SFrançois Revol
122162caef87SFrançois Revol pinner.Unlock();
122262caef87SFrançois Revol
122362caef87SFrançois Revol if ((oldEntry & flagsToClear) != 0)
122462caef87SFrançois Revol InvalidatePage(va);
122562caef87SFrançois Revol
122662caef87SFrançois Revol return B_OK;
122762caef87SFrançois Revol #endif
122862caef87SFrançois Revol }
122962caef87SFrançois Revol
123062caef87SFrançois Revol
123162caef87SFrançois Revol bool
ClearAccessedAndModified(VMArea * area,addr_t address,bool unmapIfUnaccessed,bool & _modified)123262caef87SFrançois Revol PPCVMTranslationMapClassic::ClearAccessedAndModified(VMArea* area,
123362caef87SFrançois Revol addr_t address, bool unmapIfUnaccessed, bool& _modified)
123462caef87SFrançois Revol {
123562caef87SFrançois Revol ASSERT(address % B_PAGE_SIZE == 0);
123662caef87SFrançois Revol
123762caef87SFrançois Revol // TODO: Implement for real! ATM this is just an approximation using
123862caef87SFrançois Revol // Query(), ClearFlags(), and UnmapPage(). See below!
123962caef87SFrançois Revol
124062caef87SFrançois Revol RecursiveLocker locker(fLock);
124162caef87SFrançois Revol
124262caef87SFrançois Revol uint32 flags;
124362caef87SFrançois Revol phys_addr_t physicalAddress;
124462caef87SFrançois Revol if (Query(address, &physicalAddress, &flags) != B_OK
124562caef87SFrançois Revol || (flags & PAGE_PRESENT) == 0) {
124662caef87SFrançois Revol return false;
124762caef87SFrançois Revol }
124862caef87SFrançois Revol
124962caef87SFrançois Revol _modified = (flags & PAGE_MODIFIED) != 0;
125062caef87SFrançois Revol
125162caef87SFrançois Revol if ((flags & (PAGE_ACCESSED | PAGE_MODIFIED)) != 0)
125262caef87SFrançois Revol ClearFlags(address, flags & (PAGE_ACCESSED | PAGE_MODIFIED));
125362caef87SFrançois Revol
125462caef87SFrançois Revol if ((flags & PAGE_ACCESSED) != 0)
125562caef87SFrançois Revol return true;
125662caef87SFrançois Revol
125762caef87SFrançois Revol if (!unmapIfUnaccessed)
125862caef87SFrançois Revol return false;
125962caef87SFrançois Revol
126062caef87SFrançois Revol locker.Unlock();
126162caef87SFrançois Revol
126262caef87SFrançois Revol UnmapPage(area, address, false);
126362caef87SFrançois Revol // TODO: Obvious race condition: Between querying and unmapping the
126462caef87SFrançois Revol // page could have been accessed. We try to compensate by considering
126562caef87SFrançois Revol // vm_page::{accessed,modified} (which would have been updated by
126662caef87SFrançois Revol // UnmapPage()) below, but that doesn't quite match the required
126762caef87SFrançois Revol // semantics of the method.
126862caef87SFrançois Revol
126962caef87SFrançois Revol vm_page* page = vm_lookup_page(physicalAddress / B_PAGE_SIZE);
127062caef87SFrançois Revol if (page == NULL)
127162caef87SFrançois Revol return false;
127262caef87SFrançois Revol
127362caef87SFrançois Revol _modified |= page->modified;
127462caef87SFrançois Revol
127562caef87SFrançois Revol return page->accessed;
127662caef87SFrançois Revol
127762caef87SFrançois Revol #if 0//X86
127862caef87SFrançois Revol page_directory_entry* pd = fPagingStructures->pgdir_virt;
127962caef87SFrançois Revol
128062caef87SFrançois Revol TRACE("PPCVMTranslationMapClassic::ClearAccessedAndModified(%#" B_PRIxADDR
128162caef87SFrançois Revol ")\n", address);
128262caef87SFrançois Revol
128362caef87SFrançois Revol RecursiveLocker locker(fLock);
128462caef87SFrançois Revol
128562caef87SFrançois Revol int index = VADDR_TO_PDENT(address);
128662caef87SFrançois Revol if ((pd[index] & PPC_PDE_PRESENT) == 0)
128762caef87SFrançois Revol return false;
128862caef87SFrançois Revol
128962caef87SFrançois Revol ThreadCPUPinner pinner(thread_get_current_thread());
129062caef87SFrançois Revol
129162caef87SFrançois Revol page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
129262caef87SFrançois Revol pd[index] & PPC_PDE_ADDRESS_MASK);
129362caef87SFrançois Revol
129462caef87SFrançois Revol index = VADDR_TO_PTENT(address);
129562caef87SFrançois Revol
129662caef87SFrançois Revol // perform the deed
129762caef87SFrançois Revol page_table_entry oldEntry;
129862caef87SFrançois Revol
129962caef87SFrançois Revol if (unmapIfUnaccessed) {
130062caef87SFrançois Revol while (true) {
130162caef87SFrançois Revol oldEntry = pt[index];
130262caef87SFrançois Revol if ((oldEntry & PPC_PTE_PRESENT) == 0) {
130362caef87SFrançois Revol // page mapping not valid
130462caef87SFrançois Revol return false;
130562caef87SFrançois Revol }
130662caef87SFrançois Revol
130762caef87SFrançois Revol if (oldEntry & PPC_PTE_ACCESSED) {
130862caef87SFrançois Revol // page was accessed -- just clear the flags
130962caef87SFrançois Revol oldEntry = PPCPagingMethodClassic::ClearPageTableEntryFlags(
131062caef87SFrançois Revol &pt[index], PPC_PTE_ACCESSED | PPC_PTE_DIRTY);
131162caef87SFrançois Revol break;
131262caef87SFrançois Revol }
131362caef87SFrançois Revol
131462caef87SFrançois Revol // page hasn't been accessed -- unmap it
131562caef87SFrançois Revol if (PPCPagingMethodClassic::TestAndSetPageTableEntry(&pt[index], 0,
131662caef87SFrançois Revol oldEntry) == oldEntry) {
131762caef87SFrançois Revol break;
131862caef87SFrançois Revol }
131962caef87SFrançois Revol
132062caef87SFrançois Revol // something changed -- check again
132162caef87SFrançois Revol }
132262caef87SFrançois Revol } else {
132362caef87SFrançois Revol oldEntry = PPCPagingMethodClassic::ClearPageTableEntryFlags(&pt[index],
132462caef87SFrançois Revol PPC_PTE_ACCESSED | PPC_PTE_DIRTY);
132562caef87SFrançois Revol }
132662caef87SFrançois Revol
132762caef87SFrançois Revol pinner.Unlock();
132862caef87SFrançois Revol
132962caef87SFrançois Revol _modified = (oldEntry & PPC_PTE_DIRTY) != 0;
133062caef87SFrançois Revol
133162caef87SFrançois Revol if ((oldEntry & PPC_PTE_ACCESSED) != 0) {
133262caef87SFrançois Revol // Note, that we only need to invalidate the address, if the
133362caef87SFrançois Revol // accessed flags was set, since only then the entry could have been
133462caef87SFrançois Revol // in any TLB.
133562caef87SFrançois Revol InvalidatePage(address);
133662caef87SFrançois Revol
133762caef87SFrançois Revol Flush();
133862caef87SFrançois Revol
133962caef87SFrançois Revol return true;
134062caef87SFrançois Revol }
134162caef87SFrançois Revol
134262caef87SFrançois Revol if (!unmapIfUnaccessed)
134362caef87SFrançois Revol return false;
134462caef87SFrançois Revol
134562caef87SFrançois Revol // We have unmapped the address. Do the "high level" stuff.
134662caef87SFrançois Revol
134762caef87SFrançois Revol fMapCount--;
134862caef87SFrançois Revol
134962caef87SFrançois Revol locker.Detach();
135062caef87SFrançois Revol // UnaccessedPageUnmapped() will unlock for us
135162caef87SFrançois Revol
135262caef87SFrançois Revol UnaccessedPageUnmapped(area,
135362caef87SFrançois Revol (oldEntry & PPC_PTE_ADDRESS_MASK) / B_PAGE_SIZE);
135462caef87SFrançois Revol
135562caef87SFrançois Revol return false;
135662caef87SFrançois Revol #endif
135762caef87SFrançois Revol }
135862caef87SFrançois Revol
135962caef87SFrançois Revol
136062caef87SFrançois Revol PPCPagingStructures*
PagingStructures() const136162caef87SFrançois Revol PPCVMTranslationMapClassic::PagingStructures() const
136262caef87SFrançois Revol {
136362caef87SFrançois Revol return fPagingStructures;
136462caef87SFrançois Revol }
1365