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