xref: /haiku/src/system/kernel/arch/arm/paging/32bit/ARMPagingMethod32Bit.cpp (revision b799d160f29b4cdf3651e118d5d33ae3f825d1cc)
1c917cd62SIthamar R. Adema /*
23091264bSFrançois Revol  * Copyright 2010, Ithamar R. Adema, ithamar.adema@team-embedded.nl
3c917cd62SIthamar R. Adema  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
4c917cd62SIthamar R. Adema  * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
5c917cd62SIthamar R. Adema  * Distributed under the terms of the MIT License.
6c917cd62SIthamar R. Adema  *
7c917cd62SIthamar R. Adema  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
8c917cd62SIthamar R. Adema  * Distributed under the terms of the NewOS License.
9c917cd62SIthamar R. Adema  */
10c917cd62SIthamar R. Adema 
11c917cd62SIthamar R. Adema 
12c917cd62SIthamar R. Adema #include "paging/32bit/ARMPagingMethod32Bit.h"
13c917cd62SIthamar R. Adema 
14c917cd62SIthamar R. Adema #include <stdlib.h>
15c917cd62SIthamar R. Adema #include <string.h>
16c917cd62SIthamar R. Adema 
17c917cd62SIthamar R. Adema #include <AutoDeleter.h>
18c917cd62SIthamar R. Adema 
191819aa71SIthamar R. Adema #include <arch/smp.h>
20c917cd62SIthamar R. Adema #include <arch_system_info.h>
21c917cd62SIthamar R. Adema #include <boot/kernel_args.h>
22c917cd62SIthamar R. Adema #include <int.h>
23c917cd62SIthamar R. Adema #include <thread.h>
24c917cd62SIthamar R. Adema #include <vm/vm.h>
25c917cd62SIthamar R. Adema #include <vm/VMAddressSpace.h>
26c917cd62SIthamar R. Adema 
27c917cd62SIthamar R. Adema #include "paging/32bit/ARMPagingStructures32Bit.h"
28c917cd62SIthamar R. Adema #include "paging/32bit/ARMVMTranslationMap32Bit.h"
29c917cd62SIthamar R. Adema #include "paging/arm_physical_page_mapper.h"
30c917cd62SIthamar R. Adema #include "paging/arm_physical_page_mapper_large_memory.h"
31c917cd62SIthamar R. Adema 
32c917cd62SIthamar R. Adema 
33f86b5828SIthamar R. Adema //#define TRACE_ARM_PAGING_METHOD_32_BIT
34c917cd62SIthamar R. Adema #ifdef TRACE_ARM_PAGING_METHOD_32_BIT
35c917cd62SIthamar R. Adema #	define TRACE(x...) dprintf(x)
36c917cd62SIthamar R. Adema #else
37c917cd62SIthamar R. Adema #	define TRACE(x...) ;
38c917cd62SIthamar R. Adema #endif
39c917cd62SIthamar R. Adema 
40c917cd62SIthamar R. Adema 
411819aa71SIthamar R. Adema #define MAX_INITIAL_POOLS	\
421819aa71SIthamar R. Adema 	(ROUNDUP(SMP_MAX_CPUS * TOTAL_SLOTS_PER_CPU + EXTRA_SLOTS, 1024) / 1024)
431819aa71SIthamar R. Adema 
441819aa71SIthamar R. Adema 
45c917cd62SIthamar R. Adema using ARMLargePhysicalPageMapper::PhysicalPageSlot;
46c917cd62SIthamar R. Adema 
47c917cd62SIthamar R. Adema 
48375c2129SDavid Karoly // #pragma mark - ARMPagingMethod32Bit::PhysicalPageSlotPool
49c917cd62SIthamar R. Adema 
50c917cd62SIthamar R. Adema struct ARMPagingMethod32Bit::PhysicalPageSlotPool
51c917cd62SIthamar R. Adema 	: ARMLargePhysicalPageMapper::PhysicalPageSlotPool {
52c917cd62SIthamar R. Adema public:
53c917cd62SIthamar R. Adema 	virtual						~PhysicalPageSlotPool();
54c917cd62SIthamar R. Adema 
55c917cd62SIthamar R. Adema 			status_t			InitInitial(kernel_args* args);
56c917cd62SIthamar R. Adema 			status_t			InitInitialPostArea(kernel_args* args);
57c917cd62SIthamar R. Adema 
58c917cd62SIthamar R. Adema 			void				Init(area_id dataArea, void* data,
59c917cd62SIthamar R. Adema 									area_id virtualArea, addr_t virtualBase);
60c917cd62SIthamar R. Adema 
61c917cd62SIthamar R. Adema 	virtual	status_t			AllocatePool(
62c917cd62SIthamar R. Adema 									ARMLargePhysicalPageMapper
63c917cd62SIthamar R. Adema 										::PhysicalPageSlotPool*& _pool);
64c917cd62SIthamar R. Adema 	virtual	void				Map(phys_addr_t physicalAddress,
65c917cd62SIthamar R. Adema 									addr_t virtualAddress);
66c917cd62SIthamar R. Adema 
67c917cd62SIthamar R. Adema public:
681819aa71SIthamar R. Adema 	static	PhysicalPageSlotPool sInitialPhysicalPagePool[MAX_INITIAL_POOLS];
69c917cd62SIthamar R. Adema 
70c917cd62SIthamar R. Adema private:
71c917cd62SIthamar R. Adema 	area_id					fDataArea;
72c917cd62SIthamar R. Adema 	area_id					fVirtualArea;
73c917cd62SIthamar R. Adema 	addr_t					fVirtualBase;
74c917cd62SIthamar R. Adema 	page_table_entry*		fPageTable;
75c917cd62SIthamar R. Adema };
76c917cd62SIthamar R. Adema 
77c917cd62SIthamar R. Adema 
78c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool
791819aa71SIthamar R. Adema 	ARMPagingMethod32Bit::PhysicalPageSlotPool::sInitialPhysicalPagePool[
801819aa71SIthamar R. Adema 		MAX_INITIAL_POOLS];
81c917cd62SIthamar R. Adema 
82c917cd62SIthamar R. Adema 
~PhysicalPageSlotPool()83c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::~PhysicalPageSlotPool()
84c917cd62SIthamar R. Adema {
85c917cd62SIthamar R. Adema }
86c917cd62SIthamar R. Adema 
87c917cd62SIthamar R. Adema 
88c917cd62SIthamar R. Adema status_t
InitInitial(kernel_args * args)89c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::InitInitial(kernel_args* args)
90c917cd62SIthamar R. Adema {
91c917cd62SIthamar R. Adema 	// allocate a virtual address range for the pages to be mapped into
92c917cd62SIthamar R. Adema 	addr_t virtualBase = vm_allocate_early(args, 1024 * B_PAGE_SIZE, 0, 0,
93c917cd62SIthamar R. Adema 		kPageTableAlignment);
94c917cd62SIthamar R. Adema 	if (virtualBase == 0) {
95c917cd62SIthamar R. Adema 		panic("LargeMemoryPhysicalPageMapper::Init(): Failed to reserve "
96c917cd62SIthamar R. Adema 			"physical page pool space in virtual address space!");
97c917cd62SIthamar R. Adema 		return B_ERROR;
98c917cd62SIthamar R. Adema 	}
99c917cd62SIthamar R. Adema 
100c917cd62SIthamar R. Adema 	// allocate memory for the page table and data
101c917cd62SIthamar R. Adema 	size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]);
102c917cd62SIthamar R. Adema 	page_table_entry* pageTable = (page_table_entry*)vm_allocate_early(args,
103c917cd62SIthamar R. Adema 		areaSize, ~0L, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 0);
1041819aa71SIthamar R. Adema 	if (pageTable == 0) {
1051819aa71SIthamar R. Adema 		panic("ARMPagingMethod32Bit::PhysicalPageSlotPool::InitInitial(): "
1061819aa71SIthamar R. Adema 			"Failed to allocate memory for page table!");
1071819aa71SIthamar R. Adema 		return B_ERROR;
1081819aa71SIthamar R. Adema 	}
109c917cd62SIthamar R. Adema 
110c917cd62SIthamar R. Adema 	// prepare the page table
111c917cd62SIthamar R. Adema 	_EarlyPreparePageTables(pageTable, virtualBase, 1024 * B_PAGE_SIZE);
112c917cd62SIthamar R. Adema 
113c917cd62SIthamar R. Adema 	// init the pool structure and add the initial pool
114c917cd62SIthamar R. Adema 	Init(-1, pageTable, -1, (addr_t)virtualBase);
115c917cd62SIthamar R. Adema 
116c917cd62SIthamar R. Adema 	return B_OK;
117c917cd62SIthamar R. Adema }
118c917cd62SIthamar R. Adema 
119c917cd62SIthamar R. Adema 
120c917cd62SIthamar R. Adema status_t
InitInitialPostArea(kernel_args * args)121c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::InitInitialPostArea(
122c917cd62SIthamar R. Adema 	kernel_args* args)
123c917cd62SIthamar R. Adema {
124c917cd62SIthamar R. Adema 	// create an area for the (already allocated) data
125c917cd62SIthamar R. Adema 	size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]);
126c917cd62SIthamar R. Adema 	void* temp = fPageTable;
127c917cd62SIthamar R. Adema 	area_id area = create_area("physical page pool", &temp,
128c917cd62SIthamar R. Adema 		B_EXACT_ADDRESS, areaSize, B_ALREADY_WIRED,
129c917cd62SIthamar R. Adema 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
130760de9b2SMichael Lotz 	if (area < 0) {
131c917cd62SIthamar R. Adema 		panic("LargeMemoryPhysicalPageMapper::InitPostArea(): Failed to "
132c917cd62SIthamar R. Adema 			"create area for physical page pool.");
133c917cd62SIthamar R. Adema 		return area;
134c917cd62SIthamar R. Adema 	}
135c917cd62SIthamar R. Adema 	fDataArea = area;
136c917cd62SIthamar R. Adema 
137c917cd62SIthamar R. Adema 	// create an area for the virtual address space
138c917cd62SIthamar R. Adema 	temp = (void*)fVirtualBase;
139c917cd62SIthamar R. Adema 	area = vm_create_null_area(VMAddressSpace::KernelID(),
140c917cd62SIthamar R. Adema 		"physical page pool space", &temp, B_EXACT_ADDRESS,
141c917cd62SIthamar R. Adema 		1024 * B_PAGE_SIZE, 0);
142c917cd62SIthamar R. Adema 	if (area < B_OK) {
143c917cd62SIthamar R. Adema 		panic("LargeMemoryPhysicalPageMapper::InitPostArea(): Failed to "
144c917cd62SIthamar R. Adema 			"create area for physical page pool space.");
145c917cd62SIthamar R. Adema 		return area;
146c917cd62SIthamar R. Adema 	}
147c917cd62SIthamar R. Adema 	fVirtualArea = area;
148c917cd62SIthamar R. Adema 
149c917cd62SIthamar R. Adema 	return B_OK;
150c917cd62SIthamar R. Adema }
151c917cd62SIthamar R. Adema 
152c917cd62SIthamar R. Adema 
153c917cd62SIthamar R. Adema void
Init(area_id dataArea,void * data,area_id virtualArea,addr_t virtualBase)154c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::Init(area_id dataArea, void* data,
155c917cd62SIthamar R. Adema 	area_id virtualArea, addr_t virtualBase)
156c917cd62SIthamar R. Adema {
157c917cd62SIthamar R. Adema 	fDataArea = dataArea;
158c917cd62SIthamar R. Adema 	fVirtualArea = virtualArea;
159c917cd62SIthamar R. Adema 	fVirtualBase = virtualBase;
160c917cd62SIthamar R. Adema 	fPageTable = (page_table_entry*)data;
161c917cd62SIthamar R. Adema 
162c917cd62SIthamar R. Adema 	// init slot list
163c917cd62SIthamar R. Adema 	fSlots = (PhysicalPageSlot*)(fPageTable + 1024);
164c917cd62SIthamar R. Adema 	addr_t slotAddress = virtualBase;
165c917cd62SIthamar R. Adema 	for (int32 i = 0; i < 1024; i++, slotAddress += B_PAGE_SIZE) {
166c917cd62SIthamar R. Adema 		PhysicalPageSlot* slot = &fSlots[i];
167c917cd62SIthamar R. Adema 		slot->next = slot + 1;
168c917cd62SIthamar R. Adema 		slot->pool = this;
169c917cd62SIthamar R. Adema 		slot->address = slotAddress;
170c917cd62SIthamar R. Adema 	}
171c917cd62SIthamar R. Adema 
172c917cd62SIthamar R. Adema 	fSlots[1023].next = NULL;
173c917cd62SIthamar R. Adema 		// terminate list
174c917cd62SIthamar R. Adema }
175c917cd62SIthamar R. Adema 
176c917cd62SIthamar R. Adema 
177c917cd62SIthamar R. Adema void
Map(phys_addr_t physicalAddress,addr_t virtualAddress)178c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::Map(phys_addr_t physicalAddress,
179c917cd62SIthamar R. Adema 	addr_t virtualAddress)
180c917cd62SIthamar R. Adema {
1810e5d97e9SIthamar R. Adema 	page_table_entry& pte = fPageTable[
1820e5d97e9SIthamar R. Adema 		(virtualAddress - fVirtualBase) / B_PAGE_SIZE];
183c917cd62SIthamar R. Adema 	pte = (physicalAddress & ARM_PTE_ADDRESS_MASK)
1849b592446SDavid Karoly 		| ARM_MMU_L2_TYPE_SMALLNEW
185adc32659SDavid Karoly 		| ARM_MMU_L2_FLAG_B | ARM_MMU_L2_FLAG_C
186*b799d160SDavid Karoly 		| ARM_MMU_L2_FLAG_HAIKU_KERNEL_RW | ARM_MMU_L2_FLAG_XN;
187c917cd62SIthamar R. Adema 
18883f755b5SDavid Karoly 	arch_cpu_invalidate_TLB_page(virtualAddress);
189c917cd62SIthamar R. Adema }
190c917cd62SIthamar R. Adema 
191c917cd62SIthamar R. Adema 
192c917cd62SIthamar R. Adema status_t
AllocatePool(ARMLargePhysicalPageMapper::PhysicalPageSlotPool * & _pool)193c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PhysicalPageSlotPool::AllocatePool(
194c917cd62SIthamar R. Adema 	ARMLargePhysicalPageMapper::PhysicalPageSlotPool*& _pool)
195c917cd62SIthamar R. Adema {
196c917cd62SIthamar R. Adema 	// create the pool structure
197c917cd62SIthamar R. Adema 	PhysicalPageSlotPool* pool = new(std::nothrow) PhysicalPageSlotPool;
198c917cd62SIthamar R. Adema 	if (pool == NULL)
199c917cd62SIthamar R. Adema 		return B_NO_MEMORY;
200c917cd62SIthamar R. Adema 	ObjectDeleter<PhysicalPageSlotPool> poolDeleter(pool);
201c917cd62SIthamar R. Adema 
202c917cd62SIthamar R. Adema 	// create an area that can contain the page table and the slot
203c917cd62SIthamar R. Adema 	// structures
204c917cd62SIthamar R. Adema 	size_t areaSize = B_PAGE_SIZE + sizeof(PhysicalPageSlot[1024]);
205c917cd62SIthamar R. Adema 	void* data;
206c917cd62SIthamar R. Adema 	virtual_address_restrictions virtualRestrictions = {};
207c917cd62SIthamar R. Adema 	virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
208c917cd62SIthamar R. Adema 	physical_address_restrictions physicalRestrictions = {};
209c917cd62SIthamar R. Adema 	area_id dataArea = create_area_etc(B_SYSTEM_TEAM, "physical page pool",
210c917cd62SIthamar R. Adema 		PAGE_ALIGN(areaSize), B_FULL_LOCK,
211d1f280c8SHamish Morrison 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT, 0,
212c917cd62SIthamar R. Adema 		&virtualRestrictions, &physicalRestrictions, &data);
213c917cd62SIthamar R. Adema 	if (dataArea < 0)
214c917cd62SIthamar R. Adema 		return dataArea;
215c917cd62SIthamar R. Adema 
216c917cd62SIthamar R. Adema 	// create the null area for the virtual address space
217c917cd62SIthamar R. Adema 	void* virtualBase;
218c917cd62SIthamar R. Adema 	area_id virtualArea = vm_create_null_area(
219c917cd62SIthamar R. Adema 		VMAddressSpace::KernelID(), "physical page pool space",
220c917cd62SIthamar R. Adema 		&virtualBase, B_ANY_KERNEL_BLOCK_ADDRESS, 1024 * B_PAGE_SIZE,
221c917cd62SIthamar R. Adema 		CREATE_AREA_PRIORITY_VIP);
222c917cd62SIthamar R. Adema 	if (virtualArea < 0) {
223c917cd62SIthamar R. Adema 		delete_area(dataArea);
224c917cd62SIthamar R. Adema 		return virtualArea;
225c917cd62SIthamar R. Adema 	}
226c917cd62SIthamar R. Adema 
227c917cd62SIthamar R. Adema 	// prepare the page table
228c917cd62SIthamar R. Adema 	memset(data, 0, B_PAGE_SIZE);
229c917cd62SIthamar R. Adema 
230c917cd62SIthamar R. Adema 	// get the page table's physical address
231c917cd62SIthamar R. Adema 	phys_addr_t physicalTable;
232c917cd62SIthamar R. Adema 	ARMVMTranslationMap32Bit* map = static_cast<ARMVMTranslationMap32Bit*>(
233c917cd62SIthamar R. Adema 		VMAddressSpace::Kernel()->TranslationMap());
234c917cd62SIthamar R. Adema 	uint32 dummyFlags;
235c917cd62SIthamar R. Adema 	cpu_status state = disable_interrupts();
236c917cd62SIthamar R. Adema 	map->QueryInterrupt((addr_t)data, &physicalTable, &dummyFlags);
237c917cd62SIthamar R. Adema 	restore_interrupts(state);
238c917cd62SIthamar R. Adema 
239c917cd62SIthamar R. Adema 	// put the page table into the page directory
240c917cd62SIthamar R. Adema 	int32 index = VADDR_TO_PDENT((addr_t)virtualBase);
241c917cd62SIthamar R. Adema 	page_directory_entry* entry
242c917cd62SIthamar R. Adema 		= &map->PagingStructures32Bit()->pgdir_virt[index];
2433d79cd33SDavid Karoly 	PutPageTableInPageDir(entry, physicalTable, ARM_MMU_L1_FLAG_PXN);
244c917cd62SIthamar R. Adema 	ARMPagingStructures32Bit::UpdateAllPageDirs(index, *entry);
245c917cd62SIthamar R. Adema 
246c917cd62SIthamar R. Adema 	// init the pool structure
247c917cd62SIthamar R. Adema 	pool->Init(dataArea, data, virtualArea, (addr_t)virtualBase);
248c917cd62SIthamar R. Adema 	poolDeleter.Detach();
249c917cd62SIthamar R. Adema 	_pool = pool;
250c917cd62SIthamar R. Adema 	return B_OK;
251c917cd62SIthamar R. Adema }
252c917cd62SIthamar R. Adema 
253c917cd62SIthamar R. Adema 
254c917cd62SIthamar R. Adema // #pragma mark - ARMPagingMethod32Bit
255c917cd62SIthamar R. Adema 
256c917cd62SIthamar R. Adema 
ARMPagingMethod32Bit()257c917cd62SIthamar R. Adema ARMPagingMethod32Bit::ARMPagingMethod32Bit()
258c917cd62SIthamar R. Adema 	:
259c917cd62SIthamar R. Adema 	fKernelPhysicalPageDirectory(0),
260c917cd62SIthamar R. Adema 	fKernelVirtualPageDirectory(NULL),
261c917cd62SIthamar R. Adema 	fPhysicalPageMapper(NULL),
262c917cd62SIthamar R. Adema 	fKernelPhysicalPageMapper(NULL)
263c917cd62SIthamar R. Adema {
264c917cd62SIthamar R. Adema }
265c917cd62SIthamar R. Adema 
266c917cd62SIthamar R. Adema 
~ARMPagingMethod32Bit()267c917cd62SIthamar R. Adema ARMPagingMethod32Bit::~ARMPagingMethod32Bit()
268c917cd62SIthamar R. Adema {
269c917cd62SIthamar R. Adema }
270c917cd62SIthamar R. Adema 
271c917cd62SIthamar R. Adema 
272c917cd62SIthamar R. Adema status_t
Init(kernel_args * args,VMPhysicalPageMapper ** _physicalPageMapper)273c917cd62SIthamar R. Adema ARMPagingMethod32Bit::Init(kernel_args* args,
274c917cd62SIthamar R. Adema 	VMPhysicalPageMapper** _physicalPageMapper)
275c917cd62SIthamar R. Adema {
276375c2129SDavid Karoly 	TRACE("ARMPagingMethod32Bit::Init(): entry\n");
277c917cd62SIthamar R. Adema 
278c917cd62SIthamar R. Adema 	fKernelPhysicalPageDirectory = args->arch_args.phys_pgdir;
279c917cd62SIthamar R. Adema 	fKernelVirtualPageDirectory = (page_directory_entry*)
280c917cd62SIthamar R. Adema 		args->arch_args.vir_pgdir;
281c917cd62SIthamar R. Adema 
282375c2129SDavid Karoly #ifdef TRACE_ARM_PAGING_METHOD_32_BIT
283c917cd62SIthamar R. Adema 	TRACE("page dir: %p (physical: %#" B_PRIx32 ")\n",
284c917cd62SIthamar R. Adema 		fKernelVirtualPageDirectory, fKernelPhysicalPageDirectory);
2851819aa71SIthamar R. Adema #endif
286c917cd62SIthamar R. Adema 
287c917cd62SIthamar R. Adema 	ARMPagingStructures32Bit::StaticInit();
288c917cd62SIthamar R. Adema 
2891819aa71SIthamar R. Adema 	// create the initial pools for the physical page mapper
2901819aa71SIthamar R. Adema 	int32 poolCount = _GetInitialPoolCount();
2911819aa71SIthamar R. Adema 	PhysicalPageSlotPool* pool = PhysicalPageSlotPool::sInitialPhysicalPagePool;
2921819aa71SIthamar R. Adema 
2931819aa71SIthamar R. Adema 	for (int32 i = 0; i < poolCount; i++) {
2941819aa71SIthamar R. Adema 		new(&pool[i]) PhysicalPageSlotPool;
2951819aa71SIthamar R. Adema 		status_t error = pool[i].InitInitial(args);
296c917cd62SIthamar R. Adema 		if (error != B_OK) {
297c917cd62SIthamar R. Adema 			panic("ARMPagingMethod32Bit::Init(): Failed to create initial pool "
298c917cd62SIthamar R. Adema 				"for physical page mapper!");
299c917cd62SIthamar R. Adema 			return error;
300c917cd62SIthamar R. Adema 		}
3011819aa71SIthamar R. Adema 	}
302c917cd62SIthamar R. Adema 
303c917cd62SIthamar R. Adema 	// create physical page mapper
3041819aa71SIthamar R. Adema 	large_memory_physical_page_ops_init(args, pool, poolCount, sizeof(*pool),
3051819aa71SIthamar R. Adema 		fPhysicalPageMapper, fKernelPhysicalPageMapper);
306c917cd62SIthamar R. Adema 		// TODO: Select the best page mapper!
307c917cd62SIthamar R. Adema 
3080e5d97e9SIthamar R. Adema 	TRACE("ARMPagingMethod32Bit::Init(): done\n");
309c917cd62SIthamar R. Adema 
310c917cd62SIthamar R. Adema 	*_physicalPageMapper = fPhysicalPageMapper;
311c917cd62SIthamar R. Adema 	return B_OK;
312c917cd62SIthamar R. Adema }
313c917cd62SIthamar R. Adema 
314c917cd62SIthamar R. Adema 
315c917cd62SIthamar R. Adema status_t
InitPostArea(kernel_args * args)316c917cd62SIthamar R. Adema ARMPagingMethod32Bit::InitPostArea(kernel_args* args)
317c917cd62SIthamar R. Adema {
318c917cd62SIthamar R. Adema 	void *temp;
319c917cd62SIthamar R. Adema 	area_id area;
320c917cd62SIthamar R. Adema 
321c917cd62SIthamar R. Adema 	temp = (void*)fKernelVirtualPageDirectory;
322ed04ffb5SIthamar R. Adema 	area = create_area("kernel_pgdir", &temp, B_EXACT_ADDRESS, args->arch_args.next_pagetable,
3231819aa71SIthamar R. Adema 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
324ed04ffb5SIthamar R. Adema 	ASSERT_PRINT(area >= 0, "Failed mapping the kernel page directory: 0x%08lx!", area);
325c917cd62SIthamar R. Adema 
3261819aa71SIthamar R. Adema 	int32 poolCount = _GetInitialPoolCount();
3271819aa71SIthamar R. Adema 	for (int32 i = 0; i < poolCount; i++) {
3281819aa71SIthamar R. Adema 		status_t error = PhysicalPageSlotPool::sInitialPhysicalPagePool[i]
329c917cd62SIthamar R. Adema 			.InitInitialPostArea(args);
330c917cd62SIthamar R. Adema 		if (error != B_OK)
331c917cd62SIthamar R. Adema 			return error;
3321819aa71SIthamar R. Adema 	}
333c917cd62SIthamar R. Adema 
334c917cd62SIthamar R. Adema 	return B_OK;
335c917cd62SIthamar R. Adema }
336c917cd62SIthamar R. Adema 
337c917cd62SIthamar R. Adema 
338c917cd62SIthamar R. Adema status_t
CreateTranslationMap(bool kernel,VMTranslationMap ** _map)339c917cd62SIthamar R. Adema ARMPagingMethod32Bit::CreateTranslationMap(bool kernel, VMTranslationMap** _map)
340c917cd62SIthamar R. Adema {
341c917cd62SIthamar R. Adema 	ARMVMTranslationMap32Bit* map = new(std::nothrow) ARMVMTranslationMap32Bit;
342c917cd62SIthamar R. Adema 	if (map == NULL)
343c917cd62SIthamar R. Adema 		return B_NO_MEMORY;
344c917cd62SIthamar R. Adema 
345c917cd62SIthamar R. Adema 	status_t error = map->Init(kernel);
346c917cd62SIthamar R. Adema 	if (error != B_OK) {
347c917cd62SIthamar R. Adema 		delete map;
348c917cd62SIthamar R. Adema 		return error;
349c917cd62SIthamar R. Adema 	}
350c917cd62SIthamar R. Adema 
351c917cd62SIthamar R. Adema 	*_map = map;
352c917cd62SIthamar R. Adema 	return B_OK;
353c917cd62SIthamar R. Adema }
354c917cd62SIthamar R. Adema 
355c917cd62SIthamar R. Adema 
3569103470bSDavid Karoly static void
get_free_pgtable(kernel_args * args,phys_addr_t * phys_addr,addr_t * virt_addr)3579103470bSDavid Karoly get_free_pgtable(kernel_args* args, phys_addr_t* phys_addr, addr_t* virt_addr)
358eea45d0aSIthamar R. Adema {
359d283a8c5SDavid Karoly 	if (args->arch_args.next_pagetable >= args->arch_args.last_pagetable)
360d283a8c5SDavid Karoly 		panic("ran out of early page tables");
361d283a8c5SDavid Karoly 
362eea45d0aSIthamar R. Adema 	phys_addr_t phys = args->arch_args.phys_pgdir + args->arch_args.next_pagetable;
3639103470bSDavid Karoly 	addr_t virt = args->arch_args.vir_pgdir + args->arch_args.next_pagetable;
364eea45d0aSIthamar R. Adema 	args->arch_args.next_pagetable += ARM_MMU_L2_COARSE_TABLE_SIZE;
3659103470bSDavid Karoly 
3669103470bSDavid Karoly 	*phys_addr = phys;
3679103470bSDavid Karoly 	*virt_addr = virt;
368eea45d0aSIthamar R. Adema }
369eea45d0aSIthamar R. Adema 
370c917cd62SIthamar R. Adema status_t
MapEarly(kernel_args * args,addr_t virtualAddress,phys_addr_t physicalAddress,uint8 attributes,page_num_t (* get_free_page)(kernel_args *))371c917cd62SIthamar R. Adema ARMPagingMethod32Bit::MapEarly(kernel_args* args, addr_t virtualAddress,
372c917cd62SIthamar R. Adema 	phys_addr_t physicalAddress, uint8 attributes,
3731819aa71SIthamar R. Adema 	page_num_t (*get_free_page)(kernel_args*))
374c917cd62SIthamar R. Adema {
375c917cd62SIthamar R. Adema 	// check to see if a page table exists for this range
376c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(virtualAddress);
377c917cd62SIthamar R. Adema 	if ((fKernelVirtualPageDirectory[index] & ARM_PDE_TYPE_MASK) == 0) {
3789103470bSDavid Karoly 		phys_addr_t pgtable_phys;
3799103470bSDavid Karoly 		addr_t pgtable_virt;
380c917cd62SIthamar R. Adema 		page_directory_entry *e;
3819103470bSDavid Karoly 
382c917cd62SIthamar R. Adema 		// we need to allocate a pgtable
3839103470bSDavid Karoly 		get_free_pgtable(args, &pgtable_phys, &pgtable_virt);
384c917cd62SIthamar R. Adema 
385c917cd62SIthamar R. Adema 		TRACE("ARMPagingMethod32Bit::MapEarly(): asked for free page for "
3869103470bSDavid Karoly 			"pgtable. phys=%#" B_PRIxPHYSADDR ", virt=%#" B_PRIxADDR "\n",
3879103470bSDavid Karoly 			pgtable_phys, pgtable_virt);
388c917cd62SIthamar R. Adema 
38983f755b5SDavid Karoly 		// zero it out in it's new mapping
39083f755b5SDavid Karoly 		memset((void*)pgtable_virt, 0, B_PAGE_SIZE);
39183f755b5SDavid Karoly 
392c917cd62SIthamar R. Adema 		// put it in the pgdir
393c917cd62SIthamar R. Adema 		e = &fKernelVirtualPageDirectory[index];
3943d79cd33SDavid Karoly 		PutPageTableInPageDir(e, pgtable_phys,
3953d79cd33SDavid Karoly 			(virtualAddress < KERNEL_BASE) ? ARM_MMU_L1_FLAG_PXN : 0);
396c917cd62SIthamar R. Adema 	}
397c917cd62SIthamar R. Adema 
3989103470bSDavid Karoly 	phys_addr_t ptEntryPhys = fKernelVirtualPageDirectory[index] & ARM_PDE_ADDRESS_MASK;
3999103470bSDavid Karoly 	addr_t ptEntryVirt = ptEntryPhys - args->arch_args.phys_pgdir + args->arch_args.vir_pgdir;
4009103470bSDavid Karoly 	page_table_entry* ptEntry = (page_table_entry*)ptEntryVirt;
401c917cd62SIthamar R. Adema 	ptEntry += VADDR_TO_PTENT(virtualAddress);
402c917cd62SIthamar R. Adema 
403c917cd62SIthamar R. Adema 	ASSERT_PRINT(
404c917cd62SIthamar R. Adema 		(*ptEntry & ARM_PTE_TYPE_MASK) == 0,
405c917cd62SIthamar R. Adema 		"virtual address: %#" B_PRIxADDR ", pde: %#" B_PRIx32
406c917cd62SIthamar R. Adema 		", existing pte: %#" B_PRIx32, virtualAddress, fKernelVirtualPageDirectory[index],
407c917cd62SIthamar R. Adema 		*ptEntry);
408c917cd62SIthamar R. Adema 
409c917cd62SIthamar R. Adema 	// now, fill in the pentry
410c917cd62SIthamar R. Adema 	PutPageTableEntryInTable(ptEntry,
411*b799d160SDavid Karoly 		physicalAddress, attributes | PAGE_ACCESSED | PAGE_MODIFIED, 0,
412*b799d160SDavid Karoly 		IS_KERNEL_ADDRESS(virtualAddress));
413c917cd62SIthamar R. Adema 
414c917cd62SIthamar R. Adema 	return B_OK;
415c917cd62SIthamar R. Adema }
416c917cd62SIthamar R. Adema 
417c917cd62SIthamar R. Adema 
418c917cd62SIthamar R. Adema bool
IsKernelPageAccessible(addr_t virtualAddress,uint32 protection)419c917cd62SIthamar R. Adema ARMPagingMethod32Bit::IsKernelPageAccessible(addr_t virtualAddress,
420c917cd62SIthamar R. Adema 	uint32 protection)
421c917cd62SIthamar R. Adema {
422c917cd62SIthamar R. Adema #if 0
423c917cd62SIthamar R. Adema 	// We only trust the kernel team's page directory. So switch to it first.
424c917cd62SIthamar R. Adema 	// Always set it to make sure the TLBs don't contain obsolete data.
4251819aa71SIthamar R. Adema 	uint32 physicalPageDirectory = x86_read_cr3();
4261819aa71SIthamar R. Adema 	x86_write_cr3(fKernelPhysicalPageDirectory);
427c917cd62SIthamar R. Adema 
428c917cd62SIthamar R. Adema 	// get the page directory entry for the address
429c917cd62SIthamar R. Adema 	page_directory_entry pageDirectoryEntry;
430c917cd62SIthamar R. Adema 	uint32 index = VADDR_TO_PDENT(virtualAddress);
431c917cd62SIthamar R. Adema 
432c917cd62SIthamar R. Adema 	if (physicalPageDirectory == fKernelPhysicalPageDirectory) {
433c917cd62SIthamar R. Adema 		pageDirectoryEntry = fKernelVirtualPageDirectory[index];
434c917cd62SIthamar R. Adema 	} else if (fPhysicalPageMapper != NULL) {
435c917cd62SIthamar R. Adema 		// map the original page directory and get the entry
436c917cd62SIthamar R. Adema 		void* handle;
437c917cd62SIthamar R. Adema 		addr_t virtualPageDirectory;
438c917cd62SIthamar R. Adema 		status_t error = fPhysicalPageMapper->GetPageDebug(
439c917cd62SIthamar R. Adema 			physicalPageDirectory, &virtualPageDirectory, &handle);
440c917cd62SIthamar R. Adema 		if (error == B_OK) {
441c917cd62SIthamar R. Adema 			pageDirectoryEntry
442c917cd62SIthamar R. Adema 				= ((page_directory_entry*)virtualPageDirectory)[index];
443c917cd62SIthamar R. Adema 			fPhysicalPageMapper->PutPageDebug(virtualPageDirectory, handle);
444c917cd62SIthamar R. Adema 		} else
445c917cd62SIthamar R. Adema 			pageDirectoryEntry = 0;
446c917cd62SIthamar R. Adema 	} else
447c917cd62SIthamar R. Adema 		pageDirectoryEntry = 0;
448c917cd62SIthamar R. Adema 
449c917cd62SIthamar R. Adema 	// map the page table and get the entry
450c917cd62SIthamar R. Adema 	page_table_entry pageTableEntry;
451c917cd62SIthamar R. Adema 	index = VADDR_TO_PTENT(virtualAddress);
452c917cd62SIthamar R. Adema 
4531819aa71SIthamar R. Adema 	if ((pageDirectoryEntry & X86_PDE_PRESENT) != 0
454c917cd62SIthamar R. Adema 			&& fPhysicalPageMapper != NULL) {
455c917cd62SIthamar R. Adema 		void* handle;
456c917cd62SIthamar R. Adema 		addr_t virtualPageTable;
457c917cd62SIthamar R. Adema 		status_t error = fPhysicalPageMapper->GetPageDebug(
4581819aa71SIthamar R. Adema 			pageDirectoryEntry & X86_PDE_ADDRESS_MASK, &virtualPageTable,
459c917cd62SIthamar R. Adema 			&handle);
460c917cd62SIthamar R. Adema 		if (error == B_OK) {
461c917cd62SIthamar R. Adema 			pageTableEntry = ((page_table_entry*)virtualPageTable)[index];
462c917cd62SIthamar R. Adema 			fPhysicalPageMapper->PutPageDebug(virtualPageTable, handle);
463c917cd62SIthamar R. Adema 		} else
464c917cd62SIthamar R. Adema 			pageTableEntry = 0;
465c917cd62SIthamar R. Adema 	} else
466c917cd62SIthamar R. Adema 		pageTableEntry = 0;
467c917cd62SIthamar R. Adema 
468c917cd62SIthamar R. Adema 	// switch back to the original page directory
469c917cd62SIthamar R. Adema 	if (physicalPageDirectory != fKernelPhysicalPageDirectory)
4701819aa71SIthamar R. Adema 		x86_write_cr3(physicalPageDirectory);
471c917cd62SIthamar R. Adema 
4721819aa71SIthamar R. Adema 	if ((pageTableEntry & X86_PTE_PRESENT) == 0)
473c917cd62SIthamar R. Adema 		return false;
474c917cd62SIthamar R. Adema 
475c917cd62SIthamar R. Adema 	// present means kernel-readable, so check for writable
476c917cd62SIthamar R. Adema 	return (protection & B_KERNEL_WRITE_AREA) == 0
4771819aa71SIthamar R. Adema 		|| (pageTableEntry & X86_PTE_WRITABLE) != 0;
478c917cd62SIthamar R. Adema #endif
479c917cd62SIthamar R. Adema 	//IRA: fix the above!
480c917cd62SIthamar R. Adema 	return true;
481c917cd62SIthamar R. Adema }
482c917cd62SIthamar R. Adema 
483c917cd62SIthamar R. Adema 
484c917cd62SIthamar R. Adema /*static*/ void
PutPageTableInPageDir(page_directory_entry * entry,phys_addr_t pgtablePhysical,uint32 attributes)485c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PutPageTableInPageDir(page_directory_entry* entry,
486c917cd62SIthamar R. Adema 	phys_addr_t pgtablePhysical, uint32 attributes)
487c917cd62SIthamar R. Adema {
48883f755b5SDavid Karoly 	dsb();
48983f755b5SDavid Karoly 
4903d79cd33SDavid Karoly 	*entry = (pgtablePhysical & ARM_PDE_ADDRESS_MASK) | ARM_MMU_L1_TYPE_COARSE | attributes;
49183f755b5SDavid Karoly 
49283f755b5SDavid Karoly 	dsb();
49383f755b5SDavid Karoly 	isb();
494c917cd62SIthamar R. Adema }
495c917cd62SIthamar R. Adema 
496c917cd62SIthamar R. Adema 
497c917cd62SIthamar R. Adema /*static*/ void
PutPageTableEntryInTable(page_table_entry * entry,phys_addr_t physicalAddress,uint32 attributes,uint32 memoryType,bool globalPage)498c917cd62SIthamar R. Adema ARMPagingMethod32Bit::PutPageTableEntryInTable(page_table_entry* entry,
499c917cd62SIthamar R. Adema 	phys_addr_t physicalAddress, uint32 attributes, uint32 memoryType,
500c917cd62SIthamar R. Adema 	bool globalPage)
501c917cd62SIthamar R. Adema {
502c917cd62SIthamar R. Adema 	page_table_entry page = (physicalAddress & ARM_PTE_ADDRESS_MASK)
5039b592446SDavid Karoly 		| ARM_MMU_L2_TYPE_SMALLNEW
504745a40d7SDavid Karoly 		| MemoryTypeToPageTableEntryFlags(memoryType)
505745a40d7SDavid Karoly 		| AttributesToPageTableEntryFlags(attributes)
506745a40d7SDavid Karoly 		| (globalPage ? 0 : ARM_MMU_L2_FLAG_NG);
507c917cd62SIthamar R. Adema 
508c917cd62SIthamar R. Adema 	// put it in the page table
509c917cd62SIthamar R. Adema 	*(volatile page_table_entry*)entry = page;
51083f755b5SDavid Karoly 
51183f755b5SDavid Karoly 	dsb();
51283f755b5SDavid Karoly 	isb();
513c917cd62SIthamar R. Adema }
514c917cd62SIthamar R. Adema 
515c917cd62SIthamar R. Adema 
5161819aa71SIthamar R. Adema inline int32
_GetInitialPoolCount()5171819aa71SIthamar R. Adema ARMPagingMethod32Bit::_GetInitialPoolCount()
5181819aa71SIthamar R. Adema {
5191819aa71SIthamar R. Adema 	int32 requiredSlots = smp_get_num_cpus() * TOTAL_SLOTS_PER_CPU
5201819aa71SIthamar R. Adema 			+ EXTRA_SLOTS;
5211819aa71SIthamar R. Adema 	return (requiredSlots + 1023) / 1024;
5221819aa71SIthamar R. Adema }
5231819aa71SIthamar R. Adema 
5241819aa71SIthamar R. Adema 
525c917cd62SIthamar R. Adema /*static*/ void
_EarlyPreparePageTables(page_table_entry * pageTables,addr_t address,size_t size)526c917cd62SIthamar R. Adema ARMPagingMethod32Bit::_EarlyPreparePageTables(page_table_entry* pageTables,
527c917cd62SIthamar R. Adema 	addr_t address, size_t size)
528c917cd62SIthamar R. Adema {
529c917cd62SIthamar R. Adema 	ARMPagingMethod32Bit* method = ARMPagingMethod32Bit::Method();
530c917cd62SIthamar R. Adema 	memset(pageTables, 0, 256 * (size / (B_PAGE_SIZE * 256)));
531c917cd62SIthamar R. Adema 
532c917cd62SIthamar R. Adema 	// put the array of pgtables directly into the kernel pagedir
533c917cd62SIthamar R. Adema 	// these will be wired and kept mapped into virtual space to be easy to get
534c917cd62SIthamar R. Adema 	// to
535c917cd62SIthamar R. Adema 	{
536c917cd62SIthamar R. Adema 		addr_t virtualTable = (addr_t)pageTables;
537c917cd62SIthamar R. Adema 
538c917cd62SIthamar R. Adema 		for (size_t i = 0; i < (size / (B_PAGE_SIZE * 256));
539c917cd62SIthamar R. Adema 				i++, virtualTable += 256*sizeof(page_directory_entry)) {
540c917cd62SIthamar R. Adema 			phys_addr_t physicalTable = 0;
541c917cd62SIthamar R. Adema 			_EarlyQuery(virtualTable, &physicalTable);
542c917cd62SIthamar R. Adema 			page_directory_entry* entry = method->KernelVirtualPageDirectory()
543c917cd62SIthamar R. Adema 				+ VADDR_TO_PDENT(address) + i;
544c917cd62SIthamar R. Adema 			PutPageTableInPageDir(entry, physicalTable,
5453d79cd33SDavid Karoly 				(address < KERNEL_BASE) ? ARM_MMU_L1_FLAG_PXN : 0);
546c917cd62SIthamar R. Adema 		}
547c917cd62SIthamar R. Adema 	}
548c917cd62SIthamar R. Adema }
549c917cd62SIthamar R. Adema 
550c917cd62SIthamar R. Adema 
551c917cd62SIthamar R. Adema //! TODO: currently assumes this translation map is active
552c917cd62SIthamar R. Adema /*static*/ status_t
_EarlyQuery(addr_t virtualAddress,phys_addr_t * _physicalAddress)553c917cd62SIthamar R. Adema ARMPagingMethod32Bit::_EarlyQuery(addr_t virtualAddress,
554c917cd62SIthamar R. Adema 	phys_addr_t *_physicalAddress)
555c917cd62SIthamar R. Adema {
556c917cd62SIthamar R. Adema 	ARMPagingMethod32Bit* method = ARMPagingMethod32Bit::Method();
557c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(virtualAddress);
558c917cd62SIthamar R. Adema 	if ((method->KernelVirtualPageDirectory()[index] & ARM_PDE_TYPE_MASK) == 0) {
559c917cd62SIthamar R. Adema 		// no pagetable here
560c917cd62SIthamar R. Adema 		return B_ERROR;
561c917cd62SIthamar R. Adema 	}
562c917cd62SIthamar R. Adema 
5639103470bSDavid Karoly 	phys_addr_t ptEntryPhys = method->KernelVirtualPageDirectory()[index] & ARM_PDE_ADDRESS_MASK;
5649103470bSDavid Karoly 	addr_t ptEntryVirt = ptEntryPhys -
5659103470bSDavid Karoly 		(uint32_t)method->KernelPhysicalPageDirectory() +
5669103470bSDavid Karoly 		(uint32_t)method->KernelVirtualPageDirectory();
5679103470bSDavid Karoly 
5689103470bSDavid Karoly 	page_table_entry* entry = (page_table_entry*)ptEntryVirt;
569c917cd62SIthamar R. Adema 	entry += VADDR_TO_PTENT(virtualAddress);
570c917cd62SIthamar R. Adema 
571c917cd62SIthamar R. Adema 	if ((*entry & ARM_PTE_TYPE_MASK) == 0) {
572c917cd62SIthamar R. Adema 		// page mapping not valid
573c917cd62SIthamar R. Adema 		return B_ERROR;
574c917cd62SIthamar R. Adema 	}
575c917cd62SIthamar R. Adema 
576c917cd62SIthamar R. Adema 	*_physicalAddress = (*entry & ARM_PTE_ADDRESS_MASK)
577c917cd62SIthamar R. Adema 		| VADDR_TO_PGOFF(virtualAddress);
578c917cd62SIthamar R. Adema 
579c917cd62SIthamar R. Adema 	return B_OK;
580c917cd62SIthamar R. Adema }
581