xref: /haiku/src/system/kernel/arch/arm/paging/32bit/ARMPagingMethod32Bit.cpp (revision c917cd62618c2bfd683dba8bf34f96fb7bd37203)
1*c917cd62SIthamar R. Adema /*
2*c917cd62SIthamar R. Adema  * Copyirght 2010, Ithamar R. Adema, ithamar.adema@team-embedded.nl
3*c917cd62SIthamar R. Adema  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
4*c917cd62SIthamar R. Adema  * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
5*c917cd62SIthamar R. Adema  * Distributed under the terms of the MIT License.
6*c917cd62SIthamar R. Adema  *
7*c917cd62SIthamar R. Adema  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
8*c917cd62SIthamar R. Adema  * Distributed under the terms of the NewOS License.
9*c917cd62SIthamar R. Adema  */
10*c917cd62SIthamar R. Adema 
11*c917cd62SIthamar R. Adema 
12*c917cd62SIthamar R. Adema #include "paging/32bit/ARMPagingMethod32Bit.h"
13*c917cd62SIthamar R. Adema 
14*c917cd62SIthamar R. Adema #include <stdlib.h>
15*c917cd62SIthamar R. Adema #include <string.h>
16*c917cd62SIthamar R. Adema 
17*c917cd62SIthamar R. Adema #include <AutoDeleter.h>
18*c917cd62SIthamar R. Adema 
19*c917cd62SIthamar R. Adema #include <arch_system_info.h>
20*c917cd62SIthamar R. Adema #include <boot/kernel_args.h>
21*c917cd62SIthamar R. Adema #include <int.h>
22*c917cd62SIthamar R. Adema #include <thread.h>
23*c917cd62SIthamar R. Adema #include <vm/vm.h>
24*c917cd62SIthamar R. Adema #include <vm/VMAddressSpace.h>
25*c917cd62SIthamar R. Adema #include <arm_mmu.h>
26*c917cd62SIthamar R. Adema 
27*c917cd62SIthamar R. Adema #include "paging/32bit/ARMPagingStructures32Bit.h"
28*c917cd62SIthamar R. Adema #include "paging/32bit/ARMVMTranslationMap32Bit.h"
29*c917cd62SIthamar R. Adema #include "paging/arm_physical_page_mapper.h"
30*c917cd62SIthamar R. Adema #include "paging/arm_physical_page_mapper_large_memory.h"
31*c917cd62SIthamar R. Adema 
32*c917cd62SIthamar R. Adema 
33*c917cd62SIthamar R. Adema #define TRACE_ARM_PAGING_METHOD_32_BIT
34*c917cd62SIthamar R. Adema #ifdef TRACE_ARM_PAGING_METHOD_32_BIT
35*c917cd62SIthamar R. Adema #	define TRACE(x...) dprintf(x)
36*c917cd62SIthamar R. Adema #else
37*c917cd62SIthamar R. Adema #	define TRACE(x...) ;
38*c917cd62SIthamar R. Adema #endif
39*c917cd62SIthamar R. Adema 
40*c917cd62SIthamar R. Adema 
41*c917cd62SIthamar R. Adema using ARMLargePhysicalPageMapper::PhysicalPageSlot;
42*c917cd62SIthamar R. Adema 
43*c917cd62SIthamar R. Adema 
44*c917cd62SIthamar R. Adema // #pragma mark - ARMPagingMethod32Bit::PhysicalPageSlotPool
45*c917cd62SIthamar R. Adema 
46*c917cd62SIthamar R. Adema 
47*c917cd62SIthamar R. Adema struct ARMPagingMethod32Bit::PhysicalPageSlotPool
48*c917cd62SIthamar R. Adema 	: ARMLargePhysicalPageMapper::PhysicalPageSlotPool {
49*c917cd62SIthamar R. Adema public:
50*c917cd62SIthamar R. Adema 	virtual						~PhysicalPageSlotPool();
51*c917cd62SIthamar R. Adema 
52*c917cd62SIthamar R. Adema 			status_t			InitInitial(kernel_args* args);
53*c917cd62SIthamar R. Adema 			status_t			InitInitialPostArea(kernel_args* args);
54*c917cd62SIthamar R. Adema 
55*c917cd62SIthamar R. Adema 			void				Init(area_id dataArea, void* data,
56*c917cd62SIthamar R. Adema 									area_id virtualArea, addr_t virtualBase);
57*c917cd62SIthamar R. Adema 
58*c917cd62SIthamar R. Adema 	virtual	status_t			AllocatePool(
59*c917cd62SIthamar R. Adema 									ARMLargePhysicalPageMapper
60*c917cd62SIthamar R. Adema 										::PhysicalPageSlotPool*& _pool);
61*c917cd62SIthamar R. Adema 	virtual	void				Map(phys_addr_t physicalAddress,
62*c917cd62SIthamar R. Adema 									addr_t virtualAddress);
63*c917cd62SIthamar R. Adema 
64*c917cd62SIthamar R. Adema public:
65*c917cd62SIthamar R. Adema 	static	PhysicalPageSlotPool sInitialPhysicalPagePool;
66*c917cd62SIthamar R. Adema 
67*c917cd62SIthamar R. Adema private:
68*c917cd62SIthamar R. Adema 	area_id					fDataArea;
69*c917cd62SIthamar R. Adema 	area_id					fVirtualArea;
70*c917cd62SIthamar R. Adema 	addr_t					fVirtualBase;
71*c917cd62SIthamar R. Adema 	page_table_entry*		fPageTable;
72*c917cd62SIthamar R. Adema };
73*c917cd62SIthamar R. Adema 
74*c917cd62SIthamar R. Adema 
75*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool
76*c917cd62SIthamar R. Adema 	ARMPagingMethod32Bit::PhysicalPageSlotPool::sInitialPhysicalPagePool;
77*c917cd62SIthamar R. Adema 
78*c917cd62SIthamar R. Adema 
79*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::~PhysicalPageSlotPool()
80*c917cd62SIthamar R. Adema {
81*c917cd62SIthamar R. Adema }
82*c917cd62SIthamar R. Adema 
83*c917cd62SIthamar R. Adema 
84*c917cd62SIthamar R. Adema status_t
85*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::InitInitial(kernel_args* args)
86*c917cd62SIthamar R. Adema {
87*c917cd62SIthamar R. Adema 	// allocate a virtual address range for the pages to be mapped into
88*c917cd62SIthamar R. Adema 	addr_t virtualBase = vm_allocate_early(args, 1024 * B_PAGE_SIZE, 0, 0,
89*c917cd62SIthamar R. Adema 		kPageTableAlignment);
90*c917cd62SIthamar R. Adema 	if (virtualBase == 0) {
91*c917cd62SIthamar R. Adema 		panic("LargeMemoryPhysicalPageMapper::Init(): Failed to reserve "
92*c917cd62SIthamar R. Adema 			"physical page pool space in virtual address space!");
93*c917cd62SIthamar R. Adema 		return B_ERROR;
94*c917cd62SIthamar R. Adema 	}
95*c917cd62SIthamar R. Adema 
96*c917cd62SIthamar R. Adema 	// allocate memory for the page table and data
97*c917cd62SIthamar R. Adema 	size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]);
98*c917cd62SIthamar R. Adema 	page_table_entry* pageTable = (page_table_entry*)vm_allocate_early(args,
99*c917cd62SIthamar R. Adema 		areaSize, ~0L, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 0);
100*c917cd62SIthamar R. Adema 
101*c917cd62SIthamar R. Adema 	// prepare the page table
102*c917cd62SIthamar R. Adema 	_EarlyPreparePageTables(pageTable, virtualBase, 1024 * B_PAGE_SIZE);
103*c917cd62SIthamar R. Adema 
104*c917cd62SIthamar R. Adema 	// init the pool structure and add the initial pool
105*c917cd62SIthamar R. Adema 	Init(-1, pageTable, -1, (addr_t)virtualBase);
106*c917cd62SIthamar R. Adema 
107*c917cd62SIthamar R. Adema 	return B_OK;
108*c917cd62SIthamar R. Adema }
109*c917cd62SIthamar R. Adema 
110*c917cd62SIthamar R. Adema 
111*c917cd62SIthamar R. Adema status_t
112*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::InitInitialPostArea(
113*c917cd62SIthamar R. Adema 	kernel_args* args)
114*c917cd62SIthamar R. Adema {
115*c917cd62SIthamar R. Adema 	// create an area for the (already allocated) data
116*c917cd62SIthamar R. Adema 	size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]);
117*c917cd62SIthamar R. Adema 	void* temp = fPageTable;
118*c917cd62SIthamar R. Adema 	area_id area = create_area("physical page pool", &temp,
119*c917cd62SIthamar R. Adema 		B_EXACT_ADDRESS, areaSize, B_ALREADY_WIRED,
120*c917cd62SIthamar R. Adema 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
121*c917cd62SIthamar R. Adema 	if (area < B_OK) {
122*c917cd62SIthamar R. Adema 		panic("LargeMemoryPhysicalPageMapper::InitPostArea(): Failed to "
123*c917cd62SIthamar R. Adema 			"create area for physical page pool.");
124*c917cd62SIthamar R. Adema 		return area;
125*c917cd62SIthamar R. Adema 	}
126*c917cd62SIthamar R. Adema 	fDataArea = area;
127*c917cd62SIthamar R. Adema 
128*c917cd62SIthamar R. Adema 	// create an area for the virtual address space
129*c917cd62SIthamar R. Adema 	temp = (void*)fVirtualBase;
130*c917cd62SIthamar R. Adema 	area = vm_create_null_area(VMAddressSpace::KernelID(),
131*c917cd62SIthamar R. Adema 		"physical page pool space", &temp, B_EXACT_ADDRESS,
132*c917cd62SIthamar R. Adema 		1024 * B_PAGE_SIZE, 0);
133*c917cd62SIthamar R. Adema 	if (area < B_OK) {
134*c917cd62SIthamar R. Adema 		panic("LargeMemoryPhysicalPageMapper::InitPostArea(): Failed to "
135*c917cd62SIthamar R. Adema 			"create area for physical page pool space.");
136*c917cd62SIthamar R. Adema 		return area;
137*c917cd62SIthamar R. Adema 	}
138*c917cd62SIthamar R. Adema 	fVirtualArea = area;
139*c917cd62SIthamar R. Adema 
140*c917cd62SIthamar R. Adema 	return B_OK;
141*c917cd62SIthamar R. Adema }
142*c917cd62SIthamar R. Adema 
143*c917cd62SIthamar R. Adema 
144*c917cd62SIthamar R. Adema void
145*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::Init(area_id dataArea, void* data,
146*c917cd62SIthamar R. Adema 	area_id virtualArea, addr_t virtualBase)
147*c917cd62SIthamar R. Adema {
148*c917cd62SIthamar R. Adema 	fDataArea = dataArea;
149*c917cd62SIthamar R. Adema 	fVirtualArea = virtualArea;
150*c917cd62SIthamar R. Adema 	fVirtualBase = virtualBase;
151*c917cd62SIthamar R. Adema 	fPageTable = (page_table_entry*)data;
152*c917cd62SIthamar R. Adema 
153*c917cd62SIthamar R. Adema 	// init slot list
154*c917cd62SIthamar R. Adema 	fSlots = (PhysicalPageSlot*)(fPageTable + 1024);
155*c917cd62SIthamar R. Adema 	addr_t slotAddress = virtualBase;
156*c917cd62SIthamar R. Adema 	for (int32 i = 0; i < 1024; i++, slotAddress += B_PAGE_SIZE) {
157*c917cd62SIthamar R. Adema 		PhysicalPageSlot* slot = &fSlots[i];
158*c917cd62SIthamar R. Adema 		slot->next = slot + 1;
159*c917cd62SIthamar R. Adema 		slot->pool = this;
160*c917cd62SIthamar R. Adema 		slot->address = slotAddress;
161*c917cd62SIthamar R. Adema 	}
162*c917cd62SIthamar R. Adema 
163*c917cd62SIthamar R. Adema 	fSlots[1023].next = NULL;
164*c917cd62SIthamar R. Adema 		// terminate list
165*c917cd62SIthamar R. Adema }
166*c917cd62SIthamar R. Adema 
167*c917cd62SIthamar R. Adema 
168*c917cd62SIthamar R. Adema void
169*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::Map(phys_addr_t physicalAddress,
170*c917cd62SIthamar R. Adema 	addr_t virtualAddress)
171*c917cd62SIthamar R. Adema {
172*c917cd62SIthamar R. Adema 	page_table_entry& pte = fPageTable[(virtualAddress - fVirtualBase) / B_PAGE_SIZE];
173*c917cd62SIthamar R. Adema 	pte = (physicalAddress & ARM_PTE_ADDRESS_MASK)
174*c917cd62SIthamar R. Adema 		| ARM_PTE_TYPE_SMALL_PAGE;
175*c917cd62SIthamar R. Adema 
176*c917cd62SIthamar R. Adema 	arch_cpu_invalidate_TLB_range(virtualAddress, virtualAddress + B_PAGE_SIZE);
177*c917cd62SIthamar R. Adema //	invalidate_TLB(virtualAddress);
178*c917cd62SIthamar R. Adema }
179*c917cd62SIthamar R. Adema 
180*c917cd62SIthamar R. Adema 
181*c917cd62SIthamar R. Adema status_t
182*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::AllocatePool(
183*c917cd62SIthamar R. Adema 	ARMLargePhysicalPageMapper::PhysicalPageSlotPool*& _pool)
184*c917cd62SIthamar R. Adema {
185*c917cd62SIthamar R. Adema 	// create the pool structure
186*c917cd62SIthamar R. Adema 	PhysicalPageSlotPool* pool = new(std::nothrow) PhysicalPageSlotPool;
187*c917cd62SIthamar R. Adema 	if (pool == NULL)
188*c917cd62SIthamar R. Adema 		return B_NO_MEMORY;
189*c917cd62SIthamar R. Adema 	ObjectDeleter<PhysicalPageSlotPool> poolDeleter(pool);
190*c917cd62SIthamar R. Adema 
191*c917cd62SIthamar R. Adema 	// create an area that can contain the page table and the slot
192*c917cd62SIthamar R. Adema 	// structures
193*c917cd62SIthamar R. Adema 	size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]);
194*c917cd62SIthamar R. Adema 	void* data;
195*c917cd62SIthamar R. Adema 	virtual_address_restrictions virtualRestrictions = {};
196*c917cd62SIthamar R. Adema 	virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
197*c917cd62SIthamar R. Adema 	physical_address_restrictions physicalRestrictions = {};
198*c917cd62SIthamar R. Adema 	area_id dataArea = create_area_etc(B_SYSTEM_TEAM, "physical page pool",
199*c917cd62SIthamar R. Adema 		PAGE_ALIGN(areaSize), B_FULL_LOCK,
200*c917cd62SIthamar R. Adema 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT,
201*c917cd62SIthamar R. Adema 		&virtualRestrictions, &physicalRestrictions, &data);
202*c917cd62SIthamar R. Adema 	if (dataArea < 0)
203*c917cd62SIthamar R. Adema 		return dataArea;
204*c917cd62SIthamar R. Adema 
205*c917cd62SIthamar R. Adema 	// create the null area for the virtual address space
206*c917cd62SIthamar R. Adema 	void* virtualBase;
207*c917cd62SIthamar R. Adema 	area_id virtualArea = vm_create_null_area(
208*c917cd62SIthamar R. Adema 		VMAddressSpace::KernelID(), "physical page pool space",
209*c917cd62SIthamar R. Adema 		&virtualBase, B_ANY_KERNEL_BLOCK_ADDRESS, 1024 * B_PAGE_SIZE,
210*c917cd62SIthamar R. Adema 		CREATE_AREA_PRIORITY_VIP);
211*c917cd62SIthamar R. Adema 	if (virtualArea < 0) {
212*c917cd62SIthamar R. Adema 		delete_area(dataArea);
213*c917cd62SIthamar R. Adema 		return virtualArea;
214*c917cd62SIthamar R. Adema 	}
215*c917cd62SIthamar R. Adema 
216*c917cd62SIthamar R. Adema 	// prepare the page table
217*c917cd62SIthamar R. Adema 	memset(data, 0, B_PAGE_SIZE);
218*c917cd62SIthamar R. Adema 
219*c917cd62SIthamar R. Adema 	// get the page table's physical address
220*c917cd62SIthamar R. Adema 	phys_addr_t physicalTable;
221*c917cd62SIthamar R. Adema 	ARMVMTranslationMap32Bit* map = static_cast<ARMVMTranslationMap32Bit*>(
222*c917cd62SIthamar R. Adema 		VMAddressSpace::Kernel()->TranslationMap());
223*c917cd62SIthamar R. Adema 	uint32 dummyFlags;
224*c917cd62SIthamar R. Adema 	cpu_status state = disable_interrupts();
225*c917cd62SIthamar R. Adema 	map->QueryInterrupt((addr_t)data, &physicalTable, &dummyFlags);
226*c917cd62SIthamar R. Adema 	restore_interrupts(state);
227*c917cd62SIthamar R. Adema 
228*c917cd62SIthamar R. Adema 	// put the page table into the page directory
229*c917cd62SIthamar R. Adema 	int32 index = VADDR_TO_PDENT((addr_t)virtualBase);
230*c917cd62SIthamar R. Adema 	page_directory_entry* entry
231*c917cd62SIthamar R. Adema 		= &map->PagingStructures32Bit()->pgdir_virt[index];
232*c917cd62SIthamar R. Adema 	PutPageTableInPageDir(entry, physicalTable,
233*c917cd62SIthamar R. Adema 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
234*c917cd62SIthamar R. Adema 	ARMPagingStructures32Bit::UpdateAllPageDirs(index, *entry);
235*c917cd62SIthamar R. Adema 
236*c917cd62SIthamar R. Adema 	// init the pool structure
237*c917cd62SIthamar R. Adema 	pool->Init(dataArea, data, virtualArea, (addr_t)virtualBase);
238*c917cd62SIthamar R. Adema 	poolDeleter.Detach();
239*c917cd62SIthamar R. Adema 	_pool = pool;
240*c917cd62SIthamar R. Adema 	return B_OK;
241*c917cd62SIthamar R. Adema }
242*c917cd62SIthamar R. Adema 
243*c917cd62SIthamar R. Adema 
244*c917cd62SIthamar R. Adema // #pragma mark - ARMPagingMethod32Bit
245*c917cd62SIthamar R. Adema 
246*c917cd62SIthamar R. Adema 
247*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::ARMPagingMethod32Bit()
248*c917cd62SIthamar R. Adema 	:
249*c917cd62SIthamar R. Adema 	fKernelPhysicalPageDirectory(0),
250*c917cd62SIthamar R. Adema 	fKernelVirtualPageDirectory(NULL),
251*c917cd62SIthamar R. Adema 	fPhysicalPageMapper(NULL),
252*c917cd62SIthamar R. Adema 	fKernelPhysicalPageMapper(NULL)
253*c917cd62SIthamar R. Adema {
254*c917cd62SIthamar R. Adema }
255*c917cd62SIthamar R. Adema 
256*c917cd62SIthamar R. Adema 
257*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::~ARMPagingMethod32Bit()
258*c917cd62SIthamar R. Adema {
259*c917cd62SIthamar R. Adema }
260*c917cd62SIthamar R. Adema 
261*c917cd62SIthamar R. Adema 
262*c917cd62SIthamar R. Adema status_t
263*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::Init(kernel_args* args,
264*c917cd62SIthamar R. Adema 	VMPhysicalPageMapper** _physicalPageMapper)
265*c917cd62SIthamar R. Adema {
266*c917cd62SIthamar R. Adema 	TRACE("vm_translation_map_init: entry\n");
267*c917cd62SIthamar R. Adema 
268*c917cd62SIthamar R. Adema 	fKernelPhysicalPageDirectory = args->arch_args.phys_pgdir;
269*c917cd62SIthamar R. Adema 	fKernelVirtualPageDirectory = (page_directory_entry*)
270*c917cd62SIthamar R. Adema 		args->arch_args.vir_pgdir;
271*c917cd62SIthamar R. Adema 
272*c917cd62SIthamar R. Adema 	TRACE("page dir: %p (physical: %#" B_PRIx32 ")\n",
273*c917cd62SIthamar R. Adema 		fKernelVirtualPageDirectory, fKernelPhysicalPageDirectory);
274*c917cd62SIthamar R. Adema 
275*c917cd62SIthamar R. Adema 	ARMPagingStructures32Bit::StaticInit();
276*c917cd62SIthamar R. Adema 
277*c917cd62SIthamar R. Adema 	// create the initial pool for the physical page mapper
278*c917cd62SIthamar R. Adema 	PhysicalPageSlotPool* pool
279*c917cd62SIthamar R. Adema 		= new(&PhysicalPageSlotPool::sInitialPhysicalPagePool)
280*c917cd62SIthamar R. Adema 			PhysicalPageSlotPool;
281*c917cd62SIthamar R. Adema 	status_t error = pool->InitInitial(args);
282*c917cd62SIthamar R. Adema 	if (error != B_OK) {
283*c917cd62SIthamar R. Adema 		panic("ARMPagingMethod32Bit::Init(): Failed to create initial pool "
284*c917cd62SIthamar R. Adema 			"for physical page mapper!");
285*c917cd62SIthamar R. Adema 		return error;
286*c917cd62SIthamar R. Adema 	}
287*c917cd62SIthamar R. Adema 
288*c917cd62SIthamar R. Adema 	// create physical page mapper
289*c917cd62SIthamar R. Adema 	large_memory_physical_page_ops_init(args, pool, fPhysicalPageMapper,
290*c917cd62SIthamar R. Adema 		fKernelPhysicalPageMapper);
291*c917cd62SIthamar R. Adema 		// TODO: Select the best page mapper!
292*c917cd62SIthamar R. Adema 
293*c917cd62SIthamar R. Adema 	// enable global page feature if available
294*c917cd62SIthamar R. Adema #if 0 //IRA: check for ARMv6!!
295*c917cd62SIthamar R. Adema 	if (x86_check_feature(IA32_FEATURE_PGE, FEATURE_COMMON)) {
296*c917cd62SIthamar R. Adema 		// this prevents kernel pages from being flushed from TLB on
297*c917cd62SIthamar R. Adema 		// context-switch
298*c917cd62SIthamar R. Adema 		x86_write_cr4(x86_read_cr4() | IA32_CR4_GLOBAL_PAGES);
299*c917cd62SIthamar R. Adema 	}
300*c917cd62SIthamar R. Adema #endif
301*c917cd62SIthamar R. Adema 	TRACE("vm_translation_map_init: done\n");
302*c917cd62SIthamar R. Adema 
303*c917cd62SIthamar R. Adema 	*_physicalPageMapper = fPhysicalPageMapper;
304*c917cd62SIthamar R. Adema 	return B_OK;
305*c917cd62SIthamar R. Adema }
306*c917cd62SIthamar R. Adema 
307*c917cd62SIthamar R. Adema 
308*c917cd62SIthamar R. Adema status_t
309*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::InitPostArea(kernel_args* args)
310*c917cd62SIthamar R. Adema {
311*c917cd62SIthamar R. Adema 	void *temp;
312*c917cd62SIthamar R. Adema 	status_t error;
313*c917cd62SIthamar R. Adema 	area_id area;
314*c917cd62SIthamar R. Adema 
315*c917cd62SIthamar R. Adema 	temp = (void*)fKernelVirtualPageDirectory;
316*c917cd62SIthamar R. Adema 	area = create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, MMU_L1_TABLE_SIZE,
317*c917cd62SIthamar R. Adema 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
318*c917cd62SIthamar R. Adema 	if (area < B_OK)
319*c917cd62SIthamar R. Adema 		return area;
320*c917cd62SIthamar R. Adema 
321*c917cd62SIthamar R. Adema 	error = PhysicalPageSlotPool::sInitialPhysicalPagePool
322*c917cd62SIthamar R. Adema 		.InitInitialPostArea(args);
323*c917cd62SIthamar R. Adema 	if (error != B_OK)
324*c917cd62SIthamar R. Adema 		return error;
325*c917cd62SIthamar R. Adema 
326*c917cd62SIthamar R. Adema 	return B_OK;
327*c917cd62SIthamar R. Adema }
328*c917cd62SIthamar R. Adema 
329*c917cd62SIthamar R. Adema 
330*c917cd62SIthamar R. Adema status_t
331*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::CreateTranslationMap(bool kernel, VMTranslationMap** _map)
332*c917cd62SIthamar R. Adema {
333*c917cd62SIthamar R. Adema 	ARMVMTranslationMap32Bit* map = new(std::nothrow) ARMVMTranslationMap32Bit;
334*c917cd62SIthamar R. Adema 	if (map == NULL)
335*c917cd62SIthamar R. Adema 		return B_NO_MEMORY;
336*c917cd62SIthamar R. Adema 
337*c917cd62SIthamar R. Adema 	status_t error = map->Init(kernel);
338*c917cd62SIthamar R. Adema 	if (error != B_OK) {
339*c917cd62SIthamar R. Adema 		delete map;
340*c917cd62SIthamar R. Adema 		return error;
341*c917cd62SIthamar R. Adema 	}
342*c917cd62SIthamar R. Adema 
343*c917cd62SIthamar R. Adema 	*_map = map;
344*c917cd62SIthamar R. Adema 	return B_OK;
345*c917cd62SIthamar R. Adema }
346*c917cd62SIthamar R. Adema 
347*c917cd62SIthamar R. Adema 
348*c917cd62SIthamar R. Adema status_t
349*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress,
350*c917cd62SIthamar R. Adema 	phys_addr_t physicalAddress, uint8 attributes,
351*c917cd62SIthamar R. Adema 	phys_addr_t (*get_free_page)(kernel_args*))
352*c917cd62SIthamar R. Adema {
353*c917cd62SIthamar R. Adema 	// check to see if a page table exists for this range
354*c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(virtualAddress);
355*c917cd62SIthamar R. Adema 	if ((fKernelVirtualPageDirectory[index] & ARM_PDE_TYPE_MASK) == 0) {
356*c917cd62SIthamar R. Adema 		phys_addr_t pgtable;
357*c917cd62SIthamar R. Adema 		page_directory_entry *e;
358*c917cd62SIthamar R. Adema 		// we need to allocate a pgtable
359*c917cd62SIthamar R. Adema 		pgtable = get_free_page(args);
360*c917cd62SIthamar R. Adema 		// pgtable is in pages, convert to physical address
361*c917cd62SIthamar R. Adema 		pgtable *= B_PAGE_SIZE;
362*c917cd62SIthamar R. Adema 
363*c917cd62SIthamar R. Adema 		TRACE("ARMPagingMethod32Bit::MapEarly(): asked for free page for "
364*c917cd62SIthamar R. Adema 			"pgtable. %#" B_PRIxPHYSADDR "\n", pgtable);
365*c917cd62SIthamar R. Adema 
366*c917cd62SIthamar R. Adema 		// put it in the pgdir
367*c917cd62SIthamar R. Adema 		e = &fKernelVirtualPageDirectory[index];
368*c917cd62SIthamar R. Adema 		PutPageTableInPageDir(e, pgtable, attributes);
369*c917cd62SIthamar R. Adema 
370*c917cd62SIthamar R. Adema 		// zero it out in it's new mapping
371*c917cd62SIthamar R. Adema 		memset((void*)pgtable, 0, B_PAGE_SIZE);
372*c917cd62SIthamar R. Adema 	}
373*c917cd62SIthamar R. Adema 
374*c917cd62SIthamar R. Adema 	page_table_entry *ptEntry = (page_table_entry*)
375*c917cd62SIthamar R. Adema 		(fKernelVirtualPageDirectory[index] & ARM_PDE_ADDRESS_MASK);
376*c917cd62SIthamar R. Adema 	ptEntry += VADDR_TO_PTENT(virtualAddress);
377*c917cd62SIthamar R. Adema 
378*c917cd62SIthamar R. Adema 	ASSERT_PRINT(
379*c917cd62SIthamar R. Adema 		(*ptEntry & ARM_PTE_TYPE_MASK) == 0,
380*c917cd62SIthamar R. Adema 		"virtual address: %#" B_PRIxADDR ", pde: %#" B_PRIx32
381*c917cd62SIthamar R. Adema 		", existing pte: %#" B_PRIx32, virtualAddress, fKernelVirtualPageDirectory[index],
382*c917cd62SIthamar R. Adema 		*ptEntry);
383*c917cd62SIthamar R. Adema 
384*c917cd62SIthamar R. Adema 	// now, fill in the pentry
385*c917cd62SIthamar R. Adema 	PutPageTableEntryInTable(ptEntry,
386*c917cd62SIthamar R. Adema 		physicalAddress, attributes, 0, IS_KERNEL_ADDRESS(virtualAddress));
387*c917cd62SIthamar R. Adema 
388*c917cd62SIthamar R. Adema 	return B_OK;
389*c917cd62SIthamar R. Adema }
390*c917cd62SIthamar R. Adema 
391*c917cd62SIthamar R. Adema 
392*c917cd62SIthamar R. Adema bool
393*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::IsKernelPageAccessible(addr_t virtualAddress,
394*c917cd62SIthamar R. Adema 	uint32 protection)
395*c917cd62SIthamar R. Adema {
396*c917cd62SIthamar R. Adema #if 0
397*c917cd62SIthamar R. Adema 	// We only trust the kernel team's page directory. So switch to it first.
398*c917cd62SIthamar R. Adema 	// Always set it to make sure the TLBs don't contain obsolete data.
399*c917cd62SIthamar R. Adema 	uint32 physicalPageDirectory;
400*c917cd62SIthamar R. Adema 	read_cr3(physicalPageDirectory);
401*c917cd62SIthamar R. Adema 	write_cr3(fKernelPhysicalPageDirectory);
402*c917cd62SIthamar R. Adema 
403*c917cd62SIthamar R. Adema 	// get the page directory entry for the address
404*c917cd62SIthamar R. Adema 	page_directory_entry pageDirectoryEntry;
405*c917cd62SIthamar R. Adema 	uint32 index = VADDR_TO_PDENT(virtualAddress);
406*c917cd62SIthamar R. Adema 
407*c917cd62SIthamar R. Adema 	if (physicalPageDirectory == fKernelPhysicalPageDirectory) {
408*c917cd62SIthamar R. Adema 		pageDirectoryEntry = fKernelVirtualPageDirectory[index];
409*c917cd62SIthamar R. Adema 	} else if (fPhysicalPageMapper != NULL) {
410*c917cd62SIthamar R. Adema 		// map the original page directory and get the entry
411*c917cd62SIthamar R. Adema 		void* handle;
412*c917cd62SIthamar R. Adema 		addr_t virtualPageDirectory;
413*c917cd62SIthamar R. Adema 		status_t error = fPhysicalPageMapper->GetPageDebug(
414*c917cd62SIthamar R. Adema 			physicalPageDirectory, &virtualPageDirectory, &handle);
415*c917cd62SIthamar R. Adema 		if (error == B_OK) {
416*c917cd62SIthamar R. Adema 			pageDirectoryEntry
417*c917cd62SIthamar R. Adema 				= ((page_directory_entry*)virtualPageDirectory)[index];
418*c917cd62SIthamar R. Adema 			fPhysicalPageMapper->PutPageDebug(virtualPageDirectory, handle);
419*c917cd62SIthamar R. Adema 		} else
420*c917cd62SIthamar R. Adema 			pageDirectoryEntry = 0;
421*c917cd62SIthamar R. Adema 	} else
422*c917cd62SIthamar R. Adema 		pageDirectoryEntry = 0;
423*c917cd62SIthamar R. Adema 
424*c917cd62SIthamar R. Adema 	// map the page table and get the entry
425*c917cd62SIthamar R. Adema 	page_table_entry pageTableEntry;
426*c917cd62SIthamar R. Adema 	index = VADDR_TO_PTENT(virtualAddress);
427*c917cd62SIthamar R. Adema 
428*c917cd62SIthamar R. Adema 	if ((pageDirectoryEntry & ARM_PDE_PRESENT) != 0
429*c917cd62SIthamar R. Adema 			&& fPhysicalPageMapper != NULL) {
430*c917cd62SIthamar R. Adema 		void* handle;
431*c917cd62SIthamar R. Adema 		addr_t virtualPageTable;
432*c917cd62SIthamar R. Adema 		status_t error = fPhysicalPageMapper->GetPageDebug(
433*c917cd62SIthamar R. Adema 			pageDirectoryEntry & ARM_PDE_ADDRESS_MASK, &virtualPageTable,
434*c917cd62SIthamar R. Adema 			&handle);
435*c917cd62SIthamar R. Adema 		if (error == B_OK) {
436*c917cd62SIthamar R. Adema 			pageTableEntry = ((page_table_entry*)virtualPageTable)[index];
437*c917cd62SIthamar R. Adema 			fPhysicalPageMapper->PutPageDebug(virtualPageTable, handle);
438*c917cd62SIthamar R. Adema 		} else
439*c917cd62SIthamar R. Adema 			pageTableEntry = 0;
440*c917cd62SIthamar R. Adema 	} else
441*c917cd62SIthamar R. Adema 		pageTableEntry = 0;
442*c917cd62SIthamar R. Adema 
443*c917cd62SIthamar R. Adema 	// switch back to the original page directory
444*c917cd62SIthamar R. Adema 	if (physicalPageDirectory != fKernelPhysicalPageDirectory)
445*c917cd62SIthamar R. Adema 		write_cr3(physicalPageDirectory);
446*c917cd62SIthamar R. Adema 
447*c917cd62SIthamar R. Adema 	if ((pageTableEntry & ARM_PTE_PRESENT) == 0)
448*c917cd62SIthamar R. Adema 		return false;
449*c917cd62SIthamar R. Adema 
450*c917cd62SIthamar R. Adema 	// present means kernel-readable, so check for writable
451*c917cd62SIthamar R. Adema 	return (protection & B_KERNEL_WRITE_AREA) == 0
452*c917cd62SIthamar R. Adema 		|| (pageTableEntry & ARM_PTE_WRITABLE) != 0;
453*c917cd62SIthamar R. Adema #endif
454*c917cd62SIthamar R. Adema 	//IRA: fix the above!
455*c917cd62SIthamar R. Adema 	return true;
456*c917cd62SIthamar R. Adema }
457*c917cd62SIthamar R. Adema 
458*c917cd62SIthamar R. Adema 
459*c917cd62SIthamar R. Adema /*static*/ void
460*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PutPageTableInPageDir(page_directory_entry* entry,
461*c917cd62SIthamar R. Adema 	phys_addr_t pgtablePhysical, uint32 attributes)
462*c917cd62SIthamar R. Adema {
463*c917cd62SIthamar R. Adema 	*entry = (pgtablePhysical & ARM_PDE_ADDRESS_MASK)
464*c917cd62SIthamar R. Adema 		| ARM_PDE_TYPE_COARSE_L2_PAGE_TABLE;
465*c917cd62SIthamar R. Adema 		// TODO: we ignore the attributes of the page table - for compatibility
466*c917cd62SIthamar R. Adema 		// with BeOS we allow having user accessible areas in the kernel address
467*c917cd62SIthamar R. Adema 		// space. This is currently being used by some drivers, mainly for the
468*c917cd62SIthamar R. Adema 		// frame buffer. Our current real time data implementation makes use of
469*c917cd62SIthamar R. Adema 		// this fact, too.
470*c917cd62SIthamar R. Adema 		// We might want to get rid of this possibility one day, especially if
471*c917cd62SIthamar R. Adema 		// we intend to port it to a platform that does not support this.
472*c917cd62SIthamar R. Adema }
473*c917cd62SIthamar R. Adema 
474*c917cd62SIthamar R. Adema 
475*c917cd62SIthamar R. Adema /*static*/ void
476*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PutPageTableEntryInTable(page_table_entry* entry,
477*c917cd62SIthamar R. Adema 	phys_addr_t physicalAddress, uint32 attributes, uint32 memoryType,
478*c917cd62SIthamar R. Adema 	bool globalPage)
479*c917cd62SIthamar R. Adema {
480*c917cd62SIthamar R. Adema 	page_table_entry page = (physicalAddress & ARM_PTE_ADDRESS_MASK)
481*c917cd62SIthamar R. Adema 		| ARM_PTE_TYPE_SMALL_PAGE;
482*c917cd62SIthamar R. Adema #if 0 //IRA
483*c917cd62SIthamar R. Adema 		| ARM_PTE_PRESENT | (globalPage ? ARM_PTE_GLOBAL : 0)
484*c917cd62SIthamar R. Adema 		| MemoryTypeToPageTableEntryFlags(memoryType);
485*c917cd62SIthamar R. Adema 
486*c917cd62SIthamar R. Adema 	// if the page is user accessible, it's automatically
487*c917cd62SIthamar R. Adema 	// accessible in kernel space, too (but with the same
488*c917cd62SIthamar R. Adema 	// protection)
489*c917cd62SIthamar R. Adema 	if ((attributes & B_USER_PROTECTION) != 0) {
490*c917cd62SIthamar R. Adema 		page |= ARM_PTE_USER;
491*c917cd62SIthamar R. Adema 		if ((attributes & B_WRITE_AREA) != 0)
492*c917cd62SIthamar R. Adema 			page |= ARM_PTE_WRITABLE;
493*c917cd62SIthamar R. Adema 	} else if ((attributes & B_KERNEL_WRITE_AREA) != 0)
494*c917cd62SIthamar R. Adema 		page |= ARM_PTE_WRITABLE;
495*c917cd62SIthamar R. Adema #endif
496*c917cd62SIthamar R. Adema 	// put it in the page table
497*c917cd62SIthamar R. Adema 	*(volatile page_table_entry*)entry = page;
498*c917cd62SIthamar R. Adema }
499*c917cd62SIthamar R. Adema 
500*c917cd62SIthamar R. Adema 
501*c917cd62SIthamar R. Adema /*static*/ void
502*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::_EarlyPreparePageTables(page_table_entry* pageTables,
503*c917cd62SIthamar R. Adema 	addr_t address, size_t size)
504*c917cd62SIthamar R. Adema {
505*c917cd62SIthamar R. Adema 	ARMPagingMethod32Bit* method = ARMPagingMethod32Bit::Method();
506*c917cd62SIthamar R. Adema 	memset(pageTables, 0, 256 * (size / (B_PAGE_SIZE * 256)));
507*c917cd62SIthamar R. Adema 
508*c917cd62SIthamar R. Adema 	// put the array of pgtables directly into the kernel pagedir
509*c917cd62SIthamar R. Adema 	// these will be wired and kept mapped into virtual space to be easy to get
510*c917cd62SIthamar R. Adema 	// to
511*c917cd62SIthamar R. Adema 	{
512*c917cd62SIthamar R. Adema 		addr_t virtualTable = (addr_t)pageTables;
513*c917cd62SIthamar R. Adema 
514*c917cd62SIthamar R. Adema 		for (size_t i = 0; i < (size / (B_PAGE_SIZE * 256));
515*c917cd62SIthamar R. Adema 				i++, virtualTable += 256*sizeof(page_directory_entry)) {
516*c917cd62SIthamar R. Adema 			phys_addr_t physicalTable = 0;
517*c917cd62SIthamar R. Adema 			_EarlyQuery(virtualTable, &physicalTable);
518*c917cd62SIthamar R. Adema 			page_directory_entry* entry = method->KernelVirtualPageDirectory()
519*c917cd62SIthamar R. Adema 				+ VADDR_TO_PDENT(address) + i;
520*c917cd62SIthamar R. Adema 			PutPageTableInPageDir(entry, physicalTable,
521*c917cd62SIthamar R. Adema 				B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
522*c917cd62SIthamar R. Adema 		}
523*c917cd62SIthamar R. Adema 	}
524*c917cd62SIthamar R. Adema }
525*c917cd62SIthamar R. Adema 
526*c917cd62SIthamar R. Adema 
527*c917cd62SIthamar R. Adema //! TODO: currently assumes this translation map is active
528*c917cd62SIthamar R. Adema /*static*/ status_t
529*c917cd62SIthamar R. Adema ARMPagingMethod32Bit::_EarlyQuery(addr_t virtualAddress,
530*c917cd62SIthamar R. Adema 	phys_addr_t *_physicalAddress)
531*c917cd62SIthamar R. Adema {
532*c917cd62SIthamar R. Adema 	ARMPagingMethod32Bit* method = ARMPagingMethod32Bit::Method();
533*c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(virtualAddress);
534*c917cd62SIthamar R. Adema 	if ((method->KernelVirtualPageDirectory()[index] & ARM_PDE_TYPE_MASK) == 0) {
535*c917cd62SIthamar R. Adema 		// no pagetable here
536*c917cd62SIthamar R. Adema 		return B_ERROR;
537*c917cd62SIthamar R. Adema 	}
538*c917cd62SIthamar R. Adema 
539*c917cd62SIthamar R. Adema 	page_table_entry* entry = (page_table_entry*)
540*c917cd62SIthamar R. Adema 		(method->KernelVirtualPageDirectory()[index] & ARM_PDE_ADDRESS_MASK);
541*c917cd62SIthamar R. Adema 	entry += VADDR_TO_PTENT(virtualAddress);
542*c917cd62SIthamar R. Adema 
543*c917cd62SIthamar R. Adema 	if ((*entry & ARM_PTE_TYPE_MASK) == 0) {
544*c917cd62SIthamar R. Adema 		// page mapping not valid
545*c917cd62SIthamar R. Adema 		return B_ERROR;
546*c917cd62SIthamar R. Adema 	}
547*c917cd62SIthamar R. Adema 
548*c917cd62SIthamar R. Adema 	*_physicalAddress = (*entry & ARM_PTE_ADDRESS_MASK)
549*c917cd62SIthamar R. Adema 		| VADDR_TO_PGOFF(virtualAddress);
550*c917cd62SIthamar R. Adema 
551*c917cd62SIthamar R. Adema 	return B_OK;
552*c917cd62SIthamar R. Adema }
553