xref: /haiku/src/system/kernel/arch/ppc/paging/460/PPCPagingMethod460.cpp (revision d66182742ff26552a05d04cf3c5d5c47a7b622ca)
1*d6618274SFrançois Revol /*
2*d6618274SFrançois Revol  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3*d6618274SFrançois Revol  * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
4*d6618274SFrançois Revol  * Distributed under the terms of the MIT License.
5*d6618274SFrançois Revol  *
6*d6618274SFrançois Revol  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
7*d6618274SFrançois Revol  * Distributed under the terms of the NewOS License.
8*d6618274SFrançois Revol  */
9*d6618274SFrançois Revol 
10*d6618274SFrançois Revol 
11*d6618274SFrançois Revol #include "paging/460/PPCPagingMethod460.h"
12*d6618274SFrançois Revol 
13*d6618274SFrançois Revol #include <stdlib.h>
14*d6618274SFrançois Revol #include <string.h>
15*d6618274SFrançois Revol 
16*d6618274SFrançois Revol #include <AutoDeleter.h>
17*d6618274SFrançois Revol 
18*d6618274SFrançois Revol #include <arch/cpu.h>
19*d6618274SFrançois Revol #include <arch_mmu.h>
20*d6618274SFrançois Revol #include <arch_system_info.h>
21*d6618274SFrançois Revol #include <boot/kernel_args.h>
22*d6618274SFrançois Revol #include <int.h>
23*d6618274SFrançois Revol #include <thread.h>
24*d6618274SFrançois Revol #include <vm/vm.h>
25*d6618274SFrançois Revol #include <vm/VMAddressSpace.h>
26*d6618274SFrançois Revol 
27*d6618274SFrançois Revol #include "paging/460/PPCPagingStructures460.h"
28*d6618274SFrançois Revol #include "paging/460/PPCVMTranslationMap460.h"
29*d6618274SFrançois Revol #include "generic_vm_physical_page_mapper.h"
30*d6618274SFrançois Revol #include "generic_vm_physical_page_ops.h"
31*d6618274SFrançois Revol #include "GenericVMPhysicalPageMapper.h"
32*d6618274SFrançois Revol 
33*d6618274SFrançois Revol 
34*d6618274SFrançois Revol //#define TRACE_PPC_PAGING_METHOD_460
35*d6618274SFrançois Revol #ifdef TRACE_PPC_PAGING_METHOD_460
36*d6618274SFrançois Revol #	define TRACE(x...) dprintf(x)
37*d6618274SFrançois Revol #else
38*d6618274SFrançois Revol #	define TRACE(x...) ;
39*d6618274SFrançois Revol #endif
40*d6618274SFrançois Revol 
41*d6618274SFrançois Revol // 64 MB of iospace
42*d6618274SFrançois Revol #define IOSPACE_SIZE (64*1024*1024)
43*d6618274SFrançois Revol // We only have small (4 KB) pages. The only reason for choosing greater chunk
44*d6618274SFrançois Revol // size is to keep the waste of memory limited, since the generic page mapper
45*d6618274SFrançois Revol // allocates structures per physical/virtual chunk.
46*d6618274SFrançois Revol // TODO: Implement a page mapper more suitable for small pages!
47*d6618274SFrançois Revol #define IOSPACE_CHUNK_SIZE (16 * B_PAGE_SIZE)
48*d6618274SFrançois Revol 
49*d6618274SFrançois Revol static addr_t sIOSpaceBase;
50*d6618274SFrançois Revol 
51*d6618274SFrançois Revol 
52*d6618274SFrançois Revol static status_t
53*d6618274SFrançois Revol map_iospace_chunk(addr_t va, phys_addr_t pa, uint32 flags)
54*d6618274SFrançois Revol {
55*d6618274SFrançois Revol 	pa &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
56*d6618274SFrançois Revol 	va &= ~(B_PAGE_SIZE - 1); // make sure it's page aligned
57*d6618274SFrançois Revol 	if (va < sIOSpaceBase || va >= (sIOSpaceBase + IOSPACE_SIZE))
58*d6618274SFrançois Revol 		panic("map_iospace_chunk: passed invalid va 0x%lx\n", va);
59*d6618274SFrançois Revol 
60*d6618274SFrançois Revol 	// map the pages
61*d6618274SFrançois Revol 	return ppc_map_address_range(va, pa, IOSPACE_CHUNK_SIZE);
62*d6618274SFrançois Revol }
63*d6618274SFrançois Revol 
64*d6618274SFrançois Revol 
65*d6618274SFrançois Revol // #pragma mark - PPCPagingMethod460
66*d6618274SFrançois Revol 
67*d6618274SFrançois Revol 
68*d6618274SFrançois Revol PPCPagingMethod460::PPCPagingMethod460()
69*d6618274SFrançois Revol /*
70*d6618274SFrançois Revol 	:
71*d6618274SFrançois Revol 	fPageHole(NULL),
72*d6618274SFrançois Revol 	fPageHolePageDir(NULL),
73*d6618274SFrançois Revol 	fKernelPhysicalPageDirectory(0),
74*d6618274SFrançois Revol 	fKernelVirtualPageDirectory(NULL),
75*d6618274SFrançois Revol 	fPhysicalPageMapper(NULL),
76*d6618274SFrançois Revol 	fKernelPhysicalPageMapper(NULL)
77*d6618274SFrançois Revol */
78*d6618274SFrançois Revol {
79*d6618274SFrançois Revol }
80*d6618274SFrançois Revol 
81*d6618274SFrançois Revol 
82*d6618274SFrançois Revol PPCPagingMethod460::~PPCPagingMethod460()
83*d6618274SFrançois Revol {
84*d6618274SFrançois Revol }
85*d6618274SFrançois Revol 
86*d6618274SFrançois Revol 
87*d6618274SFrançois Revol status_t
88*d6618274SFrançois Revol PPCPagingMethod460::Init(kernel_args* args,
89*d6618274SFrançois Revol 	VMPhysicalPageMapper** _physicalPageMapper)
90*d6618274SFrançois Revol {
91*d6618274SFrançois Revol 	TRACE("PPCPagingMethod460::Init(): entry\n");
92*d6618274SFrançois Revol 
93*d6618274SFrançois Revol 	fPageTable = (page_table_entry_group *)args->arch_args.page_table.start;
94*d6618274SFrançois Revol 	fPageTableSize = args->arch_args.page_table.size;
95*d6618274SFrançois Revol 	fPageTableHashMask = fPageTableSize / sizeof(page_table_entry_group) - 1;
96*d6618274SFrançois Revol 
97*d6618274SFrançois Revol 	// init physical page mapper
98*d6618274SFrançois Revol 	status_t error = generic_vm_physical_page_mapper_init(args,
99*d6618274SFrançois Revol 		map_iospace_chunk, &sIOSpaceBase, IOSPACE_SIZE, IOSPACE_CHUNK_SIZE);
100*d6618274SFrançois Revol 	if (error != B_OK)
101*d6618274SFrançois Revol 		return error;
102*d6618274SFrançois Revol 
103*d6618274SFrançois Revol 	new(&fPhysicalPageMapper) GenericVMPhysicalPageMapper;
104*d6618274SFrançois Revol 
105*d6618274SFrançois Revol 	*_physicalPageMapper = &fPhysicalPageMapper;
106*d6618274SFrançois Revol 	return B_OK;
107*d6618274SFrançois Revol 
108*d6618274SFrançois Revol #if 0//X86
109*d6618274SFrançois Revol 	fKernelPhysicalPageDirectory = args->arch_args.phys_pgdir;
110*d6618274SFrançois Revol 	fKernelVirtualPageDirectory = (page_directory_entry*)(addr_t)
111*d6618274SFrançois Revol 		args->arch_args.vir_pgdir;
112*d6618274SFrançois Revol 
113*d6618274SFrançois Revol #ifdef TRACE_PPC_PAGING_METHOD_460
114*d6618274SFrançois Revol 	TRACE("page hole: %p, page dir: %p\n", fPageHole, fPageHolePageDir);
115*d6618274SFrançois Revol 	TRACE("page dir: %p (physical: %#" B_PRIx32 ")\n",
116*d6618274SFrançois Revol 		fKernelVirtualPageDirectory, fKernelPhysicalPageDirectory);
117*d6618274SFrançois Revol #endif
118*d6618274SFrançois Revol 
119*d6618274SFrançois Revol 	PPCPagingStructures460::StaticInit();
120*d6618274SFrançois Revol 
121*d6618274SFrançois Revol 	// create the initial pool for the physical page mapper
122*d6618274SFrançois Revol 	PhysicalPageSlotPool* pool
123*d6618274SFrançois Revol 		= new(&PhysicalPageSlotPool::sInitialPhysicalPagePool)
124*d6618274SFrançois Revol 			PhysicalPageSlotPool;
125*d6618274SFrançois Revol 	status_t error = pool->InitInitial(args);
126*d6618274SFrançois Revol 	if (error != B_OK) {
127*d6618274SFrançois Revol 		panic("PPCPagingMethod460::Init(): Failed to create initial pool "
128*d6618274SFrançois Revol 			"for physical page mapper!");
129*d6618274SFrançois Revol 		return error;
130*d6618274SFrançois Revol 	}
131*d6618274SFrançois Revol 
132*d6618274SFrançois Revol 	// create physical page mapper
133*d6618274SFrançois Revol 	large_memory_physical_page_ops_init(args, pool, fPhysicalPageMapper,
134*d6618274SFrançois Revol 		fKernelPhysicalPageMapper);
135*d6618274SFrançois Revol 		// TODO: Select the best page mapper!
136*d6618274SFrançois Revol 
137*d6618274SFrançois Revol 	// enable global page feature if available
138*d6618274SFrançois Revol 	if (x86_check_feature(IA32_FEATURE_PGE, FEATURE_COMMON)) {
139*d6618274SFrançois Revol 		// this prevents kernel pages from being flushed from TLB on
140*d6618274SFrançois Revol 		// context-switch
141*d6618274SFrançois Revol 		x86_write_cr4(x86_read_cr4() | IA32_CR4_GLOBAL_PAGES);
142*d6618274SFrançois Revol 	}
143*d6618274SFrançois Revol 
144*d6618274SFrançois Revol 	TRACE("PPCPagingMethod460::Init(): done\n");
145*d6618274SFrançois Revol 
146*d6618274SFrançois Revol 	*_physicalPageMapper = fPhysicalPageMapper;
147*d6618274SFrançois Revol 	return B_OK;
148*d6618274SFrançois Revol #endif
149*d6618274SFrançois Revol }
150*d6618274SFrançois Revol 
151*d6618274SFrançois Revol 
152*d6618274SFrançois Revol status_t
153*d6618274SFrançois Revol PPCPagingMethod460::InitPostArea(kernel_args* args)
154*d6618274SFrançois Revol {
155*d6618274SFrançois Revol 
156*d6618274SFrançois Revol 	// If the page table doesn't lie within the kernel address space, we
157*d6618274SFrançois Revol 	// remap it.
158*d6618274SFrançois Revol 	if (!IS_KERNEL_ADDRESS(fPageTable)) {
159*d6618274SFrançois Revol 		addr_t newAddress = (addr_t)fPageTable;
160*d6618274SFrançois Revol 		status_t error = ppc_remap_address_range(&newAddress, fPageTableSize,
161*d6618274SFrançois Revol 			false);
162*d6618274SFrançois Revol 		if (error != B_OK) {
163*d6618274SFrançois Revol 			panic("arch_vm_translation_map_init_post_area(): Failed to remap "
164*d6618274SFrançois Revol 				"the page table!");
165*d6618274SFrançois Revol 			return error;
166*d6618274SFrançois Revol 		}
167*d6618274SFrançois Revol 
168*d6618274SFrançois Revol 		// set the new page table address
169*d6618274SFrançois Revol 		addr_t oldVirtualBase = (addr_t)(fPageTable);
170*d6618274SFrançois Revol 		fPageTable = (page_table_entry_group*)newAddress;
171*d6618274SFrançois Revol 
172*d6618274SFrançois Revol 		// unmap the old pages
173*d6618274SFrançois Revol 		ppc_unmap_address_range(oldVirtualBase, fPageTableSize);
174*d6618274SFrançois Revol 
175*d6618274SFrançois Revol // TODO: We should probably map the page table via BAT. It is relatively large,
176*d6618274SFrançois Revol // and due to being a hash table the access patterns might look sporadic, which
177*d6618274SFrançois Revol // certainly isn't to the liking of the TLB.
178*d6618274SFrançois Revol 	}
179*d6618274SFrançois Revol 
180*d6618274SFrançois Revol 	// create an area to cover the page table
181*d6618274SFrançois Revol 	fPageTableArea = create_area("page_table", (void **)&fPageTable, B_EXACT_ADDRESS,
182*d6618274SFrançois Revol 		fPageTableSize, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
183*d6618274SFrançois Revol 
184*d6618274SFrançois Revol 	// init physical page mapper
185*d6618274SFrançois Revol 	status_t error = generic_vm_physical_page_mapper_init_post_area(args);
186*d6618274SFrançois Revol 	if (error != B_OK)
187*d6618274SFrançois Revol 		return error;
188*d6618274SFrançois Revol 
189*d6618274SFrançois Revol 	return B_OK;
190*d6618274SFrançois Revol 
191*d6618274SFrançois Revol #if 0//X86
192*d6618274SFrançois Revol 	// now that the vm is initialized, create an area that represents
193*d6618274SFrançois Revol 	// the page hole
194*d6618274SFrançois Revol 	void *temp;
195*d6618274SFrançois Revol 	status_t error;
196*d6618274SFrançois Revol 	area_id area;
197*d6618274SFrançois Revol 
198*d6618274SFrançois Revol 	// unmap the page hole hack we were using before
199*d6618274SFrançois Revol 	fKernelVirtualPageDirectory[1023] = 0;
200*d6618274SFrançois Revol 	fPageHolePageDir = NULL;
201*d6618274SFrançois Revol 	fPageHole = NULL;
202*d6618274SFrançois Revol 
203*d6618274SFrançois Revol 	temp = (void*)fKernelVirtualPageDirectory;
204*d6618274SFrançois Revol 	area = create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, B_PAGE_SIZE,
205*d6618274SFrançois Revol 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
206*d6618274SFrançois Revol 	if (area < B_OK)
207*d6618274SFrançois Revol 		return area;
208*d6618274SFrançois Revol 
209*d6618274SFrançois Revol 	error = PhysicalPageSlotPool::sInitialPhysicalPagePool
210*d6618274SFrançois Revol 		.InitInitialPostArea(args);
211*d6618274SFrançois Revol 	if (error != B_OK)
212*d6618274SFrançois Revol 		return error;
213*d6618274SFrançois Revol 
214*d6618274SFrançois Revol 	return B_OK;
215*d6618274SFrançois Revol #endif//X86
216*d6618274SFrançois Revol }
217*d6618274SFrançois Revol 
218*d6618274SFrançois Revol 
219*d6618274SFrançois Revol status_t
220*d6618274SFrançois Revol PPCPagingMethod460::CreateTranslationMap(bool kernel, VMTranslationMap** _map)
221*d6618274SFrançois Revol {
222*d6618274SFrançois Revol 	PPCVMTranslationMap460* map = new(std::nothrow) PPCVMTranslationMap460;
223*d6618274SFrançois Revol 	if (map == NULL)
224*d6618274SFrançois Revol 		return B_NO_MEMORY;
225*d6618274SFrançois Revol 
226*d6618274SFrançois Revol 	status_t error = map->Init(kernel);
227*d6618274SFrançois Revol 	if (error != B_OK) {
228*d6618274SFrançois Revol 		delete map;
229*d6618274SFrançois Revol 		return error;
230*d6618274SFrançois Revol 	}
231*d6618274SFrançois Revol 
232*d6618274SFrançois Revol 	*_map = map;
233*d6618274SFrançois Revol 	return B_OK;
234*d6618274SFrançois Revol }
235*d6618274SFrançois Revol 
236*d6618274SFrançois Revol 
237*d6618274SFrançois Revol status_t
238*d6618274SFrançois Revol PPCPagingMethod460::MapEarly(kernel_args* args, addr_t virtualAddress,
239*d6618274SFrançois Revol 	phys_addr_t physicalAddress, uint8 attributes,
240*d6618274SFrançois Revol 	page_num_t (*get_free_page)(kernel_args*))
241*d6618274SFrançois Revol {
242*d6618274SFrançois Revol 	uint32 virtualSegmentID = get_sr((void *)virtualAddress) & 0xffffff;
243*d6618274SFrançois Revol 
244*d6618274SFrançois Revol 	uint32 hash = page_table_entry::PrimaryHash(virtualSegmentID, (uint32)virtualAddress);
245*d6618274SFrançois Revol 	page_table_entry_group *group = &fPageTable[hash & fPageTableHashMask];
246*d6618274SFrançois Revol 
247*d6618274SFrançois Revol 	for (int32 i = 0; i < 8; i++) {
248*d6618274SFrançois Revol 		// 8 entries in a group
249*d6618274SFrançois Revol 		if (group->entry[i].valid)
250*d6618274SFrançois Revol 			continue;
251*d6618274SFrançois Revol 
252*d6618274SFrançois Revol 		FillPageTableEntry(&group->entry[i], virtualSegmentID,
253*d6618274SFrançois Revol 			virtualAddress, physicalAddress, PTE_READ_WRITE, 0, false);
254*d6618274SFrançois Revol 		return B_OK;
255*d6618274SFrançois Revol 	}
256*d6618274SFrançois Revol 
257*d6618274SFrançois Revol 	hash = page_table_entry::SecondaryHash(hash);
258*d6618274SFrançois Revol 	group = &fPageTable[hash & fPageTableHashMask];
259*d6618274SFrançois Revol 
260*d6618274SFrançois Revol 	for (int32 i = 0; i < 8; i++) {
261*d6618274SFrançois Revol 		if (group->entry[i].valid)
262*d6618274SFrançois Revol 			continue;
263*d6618274SFrançois Revol 
264*d6618274SFrançois Revol 		FillPageTableEntry(&group->entry[i], virtualSegmentID,
265*d6618274SFrançois Revol 			virtualAddress, physicalAddress, PTE_READ_WRITE, 0, true);
266*d6618274SFrançois Revol 		return B_OK;
267*d6618274SFrançois Revol 	}
268*d6618274SFrançois Revol 
269*d6618274SFrançois Revol 	return B_ERROR;
270*d6618274SFrançois Revol }
271*d6618274SFrançois Revol 
272*d6618274SFrançois Revol 
273*d6618274SFrançois Revol bool
274*d6618274SFrançois Revol PPCPagingMethod460::IsKernelPageAccessible(addr_t virtualAddress,
275*d6618274SFrançois Revol 	uint32 protection)
276*d6618274SFrançois Revol {
277*d6618274SFrançois Revol 	// TODO:factor out to baseclass
278*d6618274SFrançois Revol 	VMAddressSpace *addressSpace = VMAddressSpace::Kernel();
279*d6618274SFrançois Revol 
280*d6618274SFrançois Revol //XXX:
281*d6618274SFrançois Revol //	PPCVMTranslationMap* map = static_cast<PPCVMTranslationMap*>(
282*d6618274SFrançois Revol //		addressSpace->TranslationMap());
283*d6618274SFrançois Revol //	VMTranslationMap* map = addressSpace->TranslationMap();
284*d6618274SFrançois Revol 	PPCVMTranslationMap460* map = static_cast<PPCVMTranslationMap460*>(
285*d6618274SFrançois Revol 		addressSpace->TranslationMap());
286*d6618274SFrançois Revol 
287*d6618274SFrançois Revol 	phys_addr_t physicalAddress;
288*d6618274SFrançois Revol 	uint32 flags;
289*d6618274SFrançois Revol 	if (map->Query(virtualAddress, &physicalAddress, &flags) != B_OK)
290*d6618274SFrançois Revol 		return false;
291*d6618274SFrançois Revol 
292*d6618274SFrançois Revol 	if ((flags & PAGE_PRESENT) == 0)
293*d6618274SFrançois Revol 		return false;
294*d6618274SFrançois Revol 
295*d6618274SFrançois Revol 	// present means kernel-readable, so check for writable
296*d6618274SFrançois Revol 	return (protection & B_KERNEL_WRITE_AREA) == 0
297*d6618274SFrançois Revol 		|| (flags & B_KERNEL_WRITE_AREA) != 0;
298*d6618274SFrançois Revol }
299*d6618274SFrançois Revol 
300*d6618274SFrançois Revol 
301*d6618274SFrançois Revol void
302*d6618274SFrançois Revol PPCPagingMethod460::FillPageTableEntry(page_table_entry *entry,
303*d6618274SFrançois Revol 	uint32 virtualSegmentID, addr_t virtualAddress, phys_addr_t physicalAddress,
304*d6618274SFrançois Revol 	uint8 protection, uint32 memoryType, bool secondaryHash)
305*d6618274SFrançois Revol {
306*d6618274SFrançois Revol 	// lower 32 bit - set at once
307*d6618274SFrançois Revol 	entry->physical_page_number = physicalAddress / B_PAGE_SIZE;
308*d6618274SFrançois Revol 	entry->_reserved0 = 0;
309*d6618274SFrançois Revol 	entry->referenced = false;
310*d6618274SFrançois Revol 	entry->changed = false;
311*d6618274SFrançois Revol 	entry->write_through = (memoryType == B_MTR_UC) || (memoryType == B_MTR_WT);
312*d6618274SFrançois Revol 	entry->caching_inhibited = (memoryType == B_MTR_UC);
313*d6618274SFrançois Revol 	entry->memory_coherent = false;
314*d6618274SFrançois Revol 	entry->guarded = false;
315*d6618274SFrançois Revol 	entry->_reserved1 = 0;
316*d6618274SFrançois Revol 	entry->page_protection = protection & 0x3;
317*d6618274SFrançois Revol 	eieio();
318*d6618274SFrançois Revol 		// we need to make sure that the lower 32 bit were
319*d6618274SFrançois Revol 		// already written when the entry becomes valid
320*d6618274SFrançois Revol 
321*d6618274SFrançois Revol 	// upper 32 bit
322*d6618274SFrançois Revol 	entry->virtual_segment_id = virtualSegmentID;
323*d6618274SFrançois Revol 	entry->secondary_hash = secondaryHash;
324*d6618274SFrançois Revol 	entry->abbr_page_index = (virtualAddress >> 22) & 0x3f;
325*d6618274SFrançois Revol 	entry->valid = true;
326*d6618274SFrançois Revol 
327*d6618274SFrançois Revol 	ppc_sync();
328*d6618274SFrançois Revol }
329*d6618274SFrançois Revol 
330*d6618274SFrançois Revol 
331*d6618274SFrançois Revol #if 0//X86
332*d6618274SFrançois Revol /*static*/ void
333*d6618274SFrançois Revol PPCPagingMethod460::PutPageTableInPageDir(page_directory_entry* entry,
334*d6618274SFrançois Revol 	phys_addr_t pgtablePhysical, uint32 attributes)
335*d6618274SFrançois Revol {
336*d6618274SFrançois Revol 	*entry = (pgtablePhysical & PPC_PDE_ADDRESS_MASK)
337*d6618274SFrançois Revol 		| PPC_PDE_PRESENT
338*d6618274SFrançois Revol 		| PPC_PDE_WRITABLE
339*d6618274SFrançois Revol 		| PPC_PDE_USER;
340*d6618274SFrançois Revol 		// TODO: we ignore the attributes of the page table - for compatibility
341*d6618274SFrançois Revol 		// with BeOS we allow having user accessible areas in the kernel address
342*d6618274SFrançois Revol 		// space. This is currently being used by some drivers, mainly for the
343*d6618274SFrançois Revol 		// frame buffer. Our current real time data implementation makes use of
344*d6618274SFrançois Revol 		// this fact, too.
345*d6618274SFrançois Revol 		// We might want to get rid of this possibility one day, especially if
346*d6618274SFrançois Revol 		// we intend to port it to a platform that does not support this.
347*d6618274SFrançois Revol }
348*d6618274SFrançois Revol 
349*d6618274SFrançois Revol 
350*d6618274SFrançois Revol /*static*/ void
351*d6618274SFrançois Revol PPCPagingMethod460::PutPageTableEntryInTable(page_table_entry* entry,
352*d6618274SFrançois Revol 	phys_addr_t physicalAddress, uint32 attributes, uint32 memoryType,
353*d6618274SFrançois Revol 	bool globalPage)
354*d6618274SFrançois Revol {
355*d6618274SFrançois Revol 	page_table_entry page = (physicalAddress & PPC_PTE_ADDRESS_MASK)
356*d6618274SFrançois Revol 		| PPC_PTE_PRESENT | (globalPage ? PPC_PTE_GLOBAL : 0)
357*d6618274SFrançois Revol 		| MemoryTypeToPageTableEntryFlags(memoryType);
358*d6618274SFrançois Revol 
359*d6618274SFrançois Revol 	// if the page is user accessible, it's automatically
360*d6618274SFrançois Revol 	// accessible in kernel space, too (but with the same
361*d6618274SFrançois Revol 	// protection)
362*d6618274SFrançois Revol 	if ((attributes & B_USER_PROTECTION) != 0) {
363*d6618274SFrançois Revol 		page |= PPC_PTE_USER;
364*d6618274SFrançois Revol 		if ((attributes & B_WRITE_AREA) != 0)
365*d6618274SFrançois Revol 			page |= PPC_PTE_WRITABLE;
366*d6618274SFrançois Revol 	} else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
367*d6618274SFrançois Revol 		page |= PPC_PTE_WRITABLE;
368*d6618274SFrançois Revol 
369*d6618274SFrançois Revol 	// put it in the page table
370*d6618274SFrançois Revol 	*(volatile page_table_entry*)entry = page;
371*d6618274SFrançois Revol }
372*d6618274SFrançois Revol 
373*d6618274SFrançois Revol 
374*d6618274SFrançois Revol /*static*/ void
375*d6618274SFrançois Revol PPCPagingMethod460::_EarlyPreparePageTables(page_table_entry* pageTables,
376*d6618274SFrançois Revol 	addr_t address, size_t size)
377*d6618274SFrançois Revol {
378*d6618274SFrançois Revol 	memset(pageTables, 0, B_PAGE_SIZE * (size / (B_PAGE_SIZE * 1024)));
379*d6618274SFrançois Revol 
380*d6618274SFrançois Revol 	// put the array of pgtables directly into the kernel pagedir
381*d6618274SFrançois Revol 	// these will be wired and kept mapped into virtual space to be easy to get
382*d6618274SFrançois Revol 	// to
383*d6618274SFrançois Revol 	{
384*d6618274SFrançois Revol 		addr_t virtualTable = (addr_t)pageTables;
385*d6618274SFrançois Revol 
386*d6618274SFrançois Revol 		page_directory_entry* pageHolePageDir
387*d6618274SFrançois Revol 			= PPCPagingMethod460::Method()->PageHolePageDir();
388*d6618274SFrançois Revol 
389*d6618274SFrançois Revol 		for (size_t i = 0; i < (size / (B_PAGE_SIZE * 1024));
390*d6618274SFrançois Revol 				i++, virtualTable += B_PAGE_SIZE) {
391*d6618274SFrançois Revol 			phys_addr_t physicalTable = 0;
392*d6618274SFrançois Revol 			_EarlyQuery(virtualTable, &physicalTable);
393*d6618274SFrançois Revol 			page_directory_entry* entry = &pageHolePageDir[
394*d6618274SFrançois Revol 				(address / (B_PAGE_SIZE * 1024)) + i];
395*d6618274SFrançois Revol 			PutPageTableInPageDir(entry, physicalTable,
396*d6618274SFrançois Revol 				B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
397*d6618274SFrançois Revol 		}
398*d6618274SFrançois Revol 	}
399*d6618274SFrançois Revol }
400*d6618274SFrançois Revol 
401*d6618274SFrançois Revol 
402*d6618274SFrançois Revol //! TODO: currently assumes this translation map is active
403*d6618274SFrançois Revol /*static*/ status_t
404*d6618274SFrançois Revol PPCPagingMethod460::_EarlyQuery(addr_t virtualAddress,
405*d6618274SFrançois Revol 	phys_addr_t *_physicalAddress)
406*d6618274SFrançois Revol {
407*d6618274SFrançois Revol 	PPCPagingMethod460* method = PPCPagingMethod460::Method();
408*d6618274SFrançois Revol 	int index = VADDR_TO_PDENT(virtualAddress);
409*d6618274SFrançois Revol 	if ((method->PageHolePageDir()[index] & PPC_PDE_PRESENT) == 0) {
410*d6618274SFrançois Revol 		// no pagetable here
411*d6618274SFrançois Revol 		return B_ERROR;
412*d6618274SFrançois Revol 	}
413*d6618274SFrançois Revol 
414*d6618274SFrançois Revol 	page_table_entry* entry = method->PageHole() + virtualAddress / B_PAGE_SIZE;
415*d6618274SFrançois Revol 	if ((*entry & PPC_PTE_PRESENT) == 0) {
416*d6618274SFrançois Revol 		// page mapping not valid
417*d6618274SFrançois Revol 		return B_ERROR;
418*d6618274SFrançois Revol 	}
419*d6618274SFrançois Revol 
420*d6618274SFrançois Revol 	*_physicalAddress = *entry & PPC_PTE_ADDRESS_MASK;
421*d6618274SFrançois Revol 	return B_OK;
422*d6618274SFrançois Revol }
423*d6618274SFrançois Revol #endif
424