xref: /haiku/src/system/kernel/arch/ppc/paging/classic/PPCVMTranslationMapClassic.cpp (revision 08c53ca964ec548bad28c7e368eac3fc0613f0c2)
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