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