xref: /haiku/src/system/kernel/arch/arm/paging/32bit/ARMVMTranslationMap32Bit.cpp (revision 08c53ca964ec548bad28c7e368eac3fc0613f0c2)
1c917cd62SIthamar R. Adema /*
23091264bSFrançois Revol  * Copyright 2010, Ithamar R. Adema, ithamar.adema@team-embedded.nl
34535495dSIngo Weinhold  * Copyright 2008-2011, 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/ARMVMTranslationMap32Bit.h"
13c917cd62SIthamar R. Adema 
14c917cd62SIthamar R. Adema #include <stdlib.h>
15c917cd62SIthamar R. Adema #include <string.h>
16c917cd62SIthamar R. Adema 
17c917cd62SIthamar R. Adema #include <int.h>
18c917cd62SIthamar R. Adema #include <thread.h>
19c917cd62SIthamar R. Adema #include <slab/Slab.h>
20c917cd62SIthamar R. Adema #include <smp.h>
21c917cd62SIthamar R. Adema #include <util/AutoLock.h>
22057fe191SAugustin Cavalier #include <util/ThreadAutoLock.h>
23c917cd62SIthamar R. Adema #include <util/queue.h>
24c917cd62SIthamar R. Adema #include <vm/vm_page.h>
25c917cd62SIthamar R. Adema #include <vm/vm_priv.h>
26c917cd62SIthamar R. Adema #include <vm/VMAddressSpace.h>
27c917cd62SIthamar R. Adema #include <vm/VMCache.h>
28c917cd62SIthamar R. Adema 
29c917cd62SIthamar R. Adema #include "paging/32bit/ARMPagingMethod32Bit.h"
30c917cd62SIthamar R. Adema #include "paging/32bit/ARMPagingStructures32Bit.h"
31c917cd62SIthamar R. Adema #include "paging/arm_physical_page_mapper.h"
32c917cd62SIthamar R. Adema 
33c917cd62SIthamar R. Adema 
345707f251SIthamar R. Adema //#define TRACE_ARM_VM_TRANSLATION_MAP_32_BIT
35c917cd62SIthamar R. Adema #ifdef TRACE_ARM_VM_TRANSLATION_MAP_32_BIT
36c917cd62SIthamar R. Adema #	define TRACE(x...) dprintf(x)
37c917cd62SIthamar R. Adema #else
38c917cd62SIthamar R. Adema #	define TRACE(x...) ;
39c917cd62SIthamar R. Adema #endif
40c917cd62SIthamar R. Adema 
41c917cd62SIthamar R. Adema 
422ab17547SDavid Karoly #define PAGEDIR_SIZE	ARM_MMU_L1_TABLE_SIZE
432ab17547SDavid Karoly #define PAGEDIR_ALIGN	(4 * B_PAGE_SIZE)
442ab17547SDavid Karoly 
452ab17547SDavid Karoly 
ARMVMTranslationMap32Bit()46c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::ARMVMTranslationMap32Bit()
47c917cd62SIthamar R. Adema 	:
48c917cd62SIthamar R. Adema 	fPagingStructures(NULL)
49c917cd62SIthamar R. Adema {
50c917cd62SIthamar R. Adema }
51c917cd62SIthamar R. Adema 
52c917cd62SIthamar R. Adema 
~ARMVMTranslationMap32Bit()53c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::~ARMVMTranslationMap32Bit()
54c917cd62SIthamar R. Adema {
55c917cd62SIthamar R. Adema 	if (fPagingStructures == NULL)
56c917cd62SIthamar R. Adema 		return;
57c917cd62SIthamar R. Adema 
58c917cd62SIthamar R. Adema 	if (fPageMapper != NULL)
59c917cd62SIthamar R. Adema 		fPageMapper->Delete();
60c917cd62SIthamar R. Adema 
61c917cd62SIthamar R. Adema 	if (fPagingStructures->pgdir_virt != NULL) {
62c917cd62SIthamar R. Adema 		// cycle through and free all of the user space pgtables
63c917cd62SIthamar R. Adema 		for (uint32 i = VADDR_TO_PDENT(USER_BASE);
64c917cd62SIthamar R. Adema 				i <= VADDR_TO_PDENT(USER_BASE + (USER_SIZE - 1)); i++) {
65c917cd62SIthamar R. Adema 			if ((fPagingStructures->pgdir_virt[i] & ARM_PDE_TYPE_MASK) != 0) {
66c917cd62SIthamar R. Adema 				addr_t address = fPagingStructures->pgdir_virt[i]
67c917cd62SIthamar R. Adema 					& ARM_PDE_ADDRESS_MASK;
68c917cd62SIthamar R. Adema 				vm_page* page = vm_lookup_page(address / B_PAGE_SIZE);
69c917cd62SIthamar R. Adema 				if (!page)
70c917cd62SIthamar R. Adema 					panic("destroy_tmap: didn't find pgtable page\n");
71c917cd62SIthamar R. Adema 				DEBUG_PAGE_ACCESS_START(page);
72c917cd62SIthamar R. Adema 				vm_page_set_state(page, PAGE_STATE_FREE);
73c917cd62SIthamar R. Adema 			}
74c917cd62SIthamar R. Adema 		}
75c917cd62SIthamar R. Adema 	}
76c917cd62SIthamar R. Adema 
77c917cd62SIthamar R. Adema 	fPagingStructures->RemoveReference();
78c917cd62SIthamar R. Adema }
79c917cd62SIthamar R. Adema 
80c917cd62SIthamar R. Adema 
81c917cd62SIthamar R. Adema status_t
Init(bool kernel)82c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::Init(bool kernel)
83c917cd62SIthamar R. Adema {
84c917cd62SIthamar R. Adema 	TRACE("ARMVMTranslationMap32Bit::Init()\n");
85c917cd62SIthamar R. Adema 
86c917cd62SIthamar R. Adema 	ARMVMTranslationMap::Init(kernel);
87c917cd62SIthamar R. Adema 
88c917cd62SIthamar R. Adema 	fPagingStructures = new(std::nothrow) ARMPagingStructures32Bit;
89c917cd62SIthamar R. Adema 	if (fPagingStructures == NULL)
90c917cd62SIthamar R. Adema 		return B_NO_MEMORY;
91c917cd62SIthamar R. Adema 
92c917cd62SIthamar R. Adema 	ARMPagingMethod32Bit* method = ARMPagingMethod32Bit::Method();
93c917cd62SIthamar R. Adema 
94c917cd62SIthamar R. Adema 	if (!kernel) {
95c917cd62SIthamar R. Adema 		// user
96c917cd62SIthamar R. Adema 		// allocate a physical page mapper
97c917cd62SIthamar R. Adema 		status_t error = method->PhysicalPageMapper()
98c917cd62SIthamar R. Adema 			->CreateTranslationMapPhysicalPageMapper(&fPageMapper);
99c917cd62SIthamar R. Adema 		if (error != B_OK)
100c917cd62SIthamar R. Adema 			return error;
101c917cd62SIthamar R. Adema 
102c917cd62SIthamar R. Adema 		// allocate the page directory
103fe3405c0SDavid Karoly 		page_directory_entry *virtualPageDir = NULL;
104fe3405c0SDavid Karoly 
105fe3405c0SDavid Karoly 		virtual_address_restrictions virtualRestrictions = {};
106fe3405c0SDavid Karoly 		virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
107fe3405c0SDavid Karoly 
108fe3405c0SDavid Karoly 		physical_address_restrictions physicalRestrictions = {};
109fe3405c0SDavid Karoly 		physicalRestrictions.alignment = PAGEDIR_ALIGN;
110fe3405c0SDavid Karoly 
111fe3405c0SDavid Karoly 		area_id pgdir_area = create_area_etc(B_SYSTEM_TEAM, "pgdir",
112fe3405c0SDavid Karoly 			PAGEDIR_SIZE, B_CONTIGUOUS,
113fe3405c0SDavid Karoly 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 0, 0,
114fe3405c0SDavid Karoly 			&virtualRestrictions, &physicalRestrictions, (void **)&virtualPageDir);
115fe3405c0SDavid Karoly 
116fe3405c0SDavid Karoly 		if (pgdir_area < 0) {
117c917cd62SIthamar R. Adema 			return B_NO_MEMORY;
118fe3405c0SDavid Karoly 		}
119c917cd62SIthamar R. Adema 
120c917cd62SIthamar R. Adema 		// look up the page directory's physical address
121c917cd62SIthamar R. Adema 		phys_addr_t physicalPageDir;
122c917cd62SIthamar R. Adema 		vm_get_page_mapping(VMAddressSpace::KernelID(),
123c917cd62SIthamar R. Adema 			(addr_t)virtualPageDir, &physicalPageDir);
124c917cd62SIthamar R. Adema 
125c917cd62SIthamar R. Adema 		fPagingStructures->Init(virtualPageDir, physicalPageDir,
126c917cd62SIthamar R. Adema 			method->KernelVirtualPageDirectory());
127c917cd62SIthamar R. Adema 	} else {
128c917cd62SIthamar R. Adema 		// kernel
129c917cd62SIthamar R. Adema 		// get the physical page mapper
130c917cd62SIthamar R. Adema 		fPageMapper = method->KernelPhysicalPageMapper();
131c917cd62SIthamar R. Adema 
132c917cd62SIthamar R. Adema 		// we already know the kernel pgdir mapping
133c917cd62SIthamar R. Adema 		fPagingStructures->Init(method->KernelVirtualPageDirectory(),
134c917cd62SIthamar R. Adema 			method->KernelPhysicalPageDirectory(), NULL);
135c917cd62SIthamar R. Adema 	}
136c917cd62SIthamar R. Adema 
137c917cd62SIthamar R. Adema 	return B_OK;
138c917cd62SIthamar R. Adema }
139c917cd62SIthamar R. Adema 
140c917cd62SIthamar R. Adema 
141c917cd62SIthamar R. Adema size_t
MaxPagesNeededToMap(addr_t start,addr_t end) const142c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::MaxPagesNeededToMap(addr_t start, addr_t end) const
143c917cd62SIthamar R. Adema {
144c917cd62SIthamar R. Adema 	// If start == 0, the actual base address is not yet known to the caller and
145c917cd62SIthamar R. Adema 	// we shall assume the worst case.
146c917cd62SIthamar R. Adema 	if (start == 0) {
147c917cd62SIthamar R. Adema 		// offset the range so it has the worst possible alignment
148c917cd62SIthamar R. Adema 		start = 1023 * B_PAGE_SIZE;
149c917cd62SIthamar R. Adema 		end += 1023 * B_PAGE_SIZE;
150c917cd62SIthamar R. Adema 	}
151c917cd62SIthamar R. Adema 
152c917cd62SIthamar R. Adema 	return VADDR_TO_PDENT(end) + 1 - VADDR_TO_PDENT(start);
153c917cd62SIthamar R. Adema }
154c917cd62SIthamar R. Adema 
155c917cd62SIthamar R. Adema 
156c917cd62SIthamar R. Adema status_t
Map(addr_t va,phys_addr_t pa,uint32 attributes,uint32 memoryType,vm_page_reservation * reservation)157c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::Map(addr_t va, phys_addr_t pa, uint32 attributes,
158c917cd62SIthamar R. Adema 	uint32 memoryType, vm_page_reservation* reservation)
159c917cd62SIthamar R. Adema {
160c917cd62SIthamar R. Adema 	TRACE("map_tmap: entry pa 0x%lx va 0x%lx\n", pa, va);
161c917cd62SIthamar R. Adema 
162c917cd62SIthamar R. Adema /*
163c917cd62SIthamar R. Adema 	dprintf("pgdir at 0x%x\n", pgdir);
164c917cd62SIthamar R. Adema 	dprintf("index is %d\n", va / B_PAGE_SIZE / 1024);
165c917cd62SIthamar R. Adema 	dprintf("final at 0x%x\n", &pgdir[va / B_PAGE_SIZE / 1024]);
166c917cd62SIthamar R. Adema 	dprintf("value is 0x%x\n", *(int *)&pgdir[va / B_PAGE_SIZE / 1024]);
167c917cd62SIthamar R. Adema 	dprintf("present bit is %d\n", pgdir[va / B_PAGE_SIZE / 1024].present);
168c917cd62SIthamar R. Adema 	dprintf("addr is %d\n", pgdir[va / B_PAGE_SIZE / 1024].addr);
169c917cd62SIthamar R. Adema */
170c917cd62SIthamar R. Adema 	page_directory_entry* pd = fPagingStructures->pgdir_virt;
171c917cd62SIthamar R. Adema 
172c917cd62SIthamar R. Adema 	// check to see if a page table exists for this range
173c917cd62SIthamar R. Adema 	uint32 index = VADDR_TO_PDENT(va);
174c917cd62SIthamar R. Adema 	if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
175c917cd62SIthamar R. Adema 		phys_addr_t pgtable;
176c917cd62SIthamar R. Adema 		vm_page *page;
177c917cd62SIthamar R. Adema 
178c917cd62SIthamar R. Adema 		// we need to allocate a pgtable
179c917cd62SIthamar R. Adema 		page = vm_page_allocate_page(reservation,
180c917cd62SIthamar R. Adema 			PAGE_STATE_WIRED | VM_PAGE_ALLOC_CLEAR);
181c917cd62SIthamar R. Adema 
182c917cd62SIthamar R. Adema 		DEBUG_PAGE_ACCESS_END(page);
183c917cd62SIthamar R. Adema 
184c917cd62SIthamar R. Adema 		pgtable = (phys_addr_t)page->physical_page_number * B_PAGE_SIZE;
185c917cd62SIthamar R. Adema 
186c917cd62SIthamar R. Adema 		TRACE("map_tmap: asked for free page for pgtable. 0x%lx\n", pgtable);
187c917cd62SIthamar R. Adema 
188c917cd62SIthamar R. Adema 		// put it in the pgdir
189c917cd62SIthamar R. Adema 		ARMPagingMethod32Bit::PutPageTableInPageDir(&pd[index], pgtable,
1903d79cd33SDavid Karoly 			(va < KERNEL_BASE) ? ARM_MMU_L1_FLAG_PXN : 0);
191c917cd62SIthamar R. Adema 
192c917cd62SIthamar R. Adema 		// update any other page directories, if it maps kernel space
193c917cd62SIthamar R. Adema 		if (index >= FIRST_KERNEL_PGDIR_ENT
194c917cd62SIthamar R. Adema 			&& index < (FIRST_KERNEL_PGDIR_ENT + NUM_KERNEL_PGDIR_ENTS)) {
195c917cd62SIthamar R. Adema 			ARMPagingStructures32Bit::UpdateAllPageDirs(index, pd[index]);
196c917cd62SIthamar R. Adema 		}
197c917cd62SIthamar R. Adema 
198c917cd62SIthamar R. Adema 		fMapCount++;
199c917cd62SIthamar R. Adema 	}
200c917cd62SIthamar R. Adema 
201c917cd62SIthamar R. Adema 	// now, fill in the pentry
2024535495dSIngo Weinhold 	Thread* thread = thread_get_current_thread();
203c917cd62SIthamar R. Adema 	ThreadCPUPinner pinner(thread);
204c917cd62SIthamar R. Adema 
205c917cd62SIthamar R. Adema 	page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
206c917cd62SIthamar R. Adema 		pd[index] & ARM_PDE_ADDRESS_MASK);
207c917cd62SIthamar R. Adema 	index = VADDR_TO_PTENT(va);
208c917cd62SIthamar R. Adema 
209c917cd62SIthamar R. Adema 	ASSERT_PRINT((pt[index] & ARM_PTE_TYPE_MASK) == 0,
210c917cd62SIthamar R. Adema 		"virtual address: %#" B_PRIxADDR ", existing pte: %#" B_PRIx32, va,
211c917cd62SIthamar R. Adema 		pt[index]);
212c917cd62SIthamar R. Adema 
213c917cd62SIthamar R. Adema 	ARMPagingMethod32Bit::PutPageTableEntryInTable(&pt[index], pa, attributes,
214c917cd62SIthamar R. Adema 		memoryType, fIsKernelMap);
215c917cd62SIthamar R. Adema 
216c917cd62SIthamar R. Adema 	pinner.Unlock();
217c917cd62SIthamar R. Adema 
218c917cd62SIthamar R. Adema 	// Note: We don't need to invalidate the TLB for this address, as previously
219c917cd62SIthamar R. Adema 	// the entry was not present and the TLB doesn't cache those entries.
220c917cd62SIthamar R. Adema 
221c917cd62SIthamar R. Adema 	fMapCount++;
222c917cd62SIthamar R. Adema 
223c917cd62SIthamar R. Adema 	return 0;
224c917cd62SIthamar R. Adema }
225c917cd62SIthamar R. Adema 
226c917cd62SIthamar R. Adema 
227c917cd62SIthamar R. Adema status_t
Unmap(addr_t start,addr_t end)228c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::Unmap(addr_t start, addr_t end)
229c917cd62SIthamar R. Adema {
230c917cd62SIthamar R. Adema 	start = ROUNDDOWN(start, B_PAGE_SIZE);
231c917cd62SIthamar R. Adema 	if (start >= end)
232c917cd62SIthamar R. Adema 		return B_OK;
233c917cd62SIthamar R. Adema 
234c917cd62SIthamar R. Adema 	TRACE("unmap_tmap: asked to free pages 0x%lx to 0x%lx\n", start, end);
235c917cd62SIthamar R. Adema 
236c917cd62SIthamar R. Adema 	page_directory_entry *pd = fPagingStructures->pgdir_virt;
237c917cd62SIthamar R. Adema 
238c917cd62SIthamar R. Adema 	do {
239c917cd62SIthamar R. Adema 		int index = VADDR_TO_PDENT(start);
240c917cd62SIthamar R. Adema 		if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
241c917cd62SIthamar R. Adema 			// no page table here, move the start up to access the next page
242c917cd62SIthamar R. Adema 			// table
243c917cd62SIthamar R. Adema 			start = ROUNDUP(start + 1, kPageTableAlignment);
244c917cd62SIthamar R. Adema 			continue;
245c917cd62SIthamar R. Adema 		}
246c917cd62SIthamar R. Adema 
2474535495dSIngo Weinhold 		Thread* thread = thread_get_current_thread();
248c917cd62SIthamar R. Adema 		ThreadCPUPinner pinner(thread);
249c917cd62SIthamar R. Adema 
250c917cd62SIthamar R. Adema 		page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
251c917cd62SIthamar R. Adema 			pd[index] & ARM_PDE_ADDRESS_MASK);
252c917cd62SIthamar R. Adema 
253fed8bb7dSMichael Lotz 		for (index = VADDR_TO_PTENT(start); (index < 256) && (start < end);
254c917cd62SIthamar R. Adema 				index++, start += B_PAGE_SIZE) {
255c917cd62SIthamar R. Adema 			if ((pt[index] & ARM_PTE_TYPE_MASK) == 0) {
256c917cd62SIthamar R. Adema 				// page mapping not valid
257c917cd62SIthamar R. Adema 				continue;
258c917cd62SIthamar R. Adema 			}
259c917cd62SIthamar R. Adema 
260c917cd62SIthamar R. Adema 			TRACE("unmap_tmap: removing page 0x%lx\n", start);
261c917cd62SIthamar R. Adema 
262c917cd62SIthamar R. Adema 			page_table_entry oldEntry
263c917cd62SIthamar R. Adema 				= ARMPagingMethod32Bit::ClearPageTableEntryFlags(&pt[index],
264c917cd62SIthamar R. Adema 					ARM_PTE_TYPE_MASK);
265c917cd62SIthamar R. Adema 			fMapCount--;
266c917cd62SIthamar R. Adema 
267d38dcddeSDavid Karoly 			if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
268c917cd62SIthamar R. Adema 				// Note, that we only need to invalidate the address, if the
269c917cd62SIthamar R. Adema 				// accessed flags was set, since only then the entry could have
270c917cd62SIthamar R. Adema 				// been in any TLB.
271c917cd62SIthamar R. Adema 				InvalidatePage(start);
272c917cd62SIthamar R. Adema 			}
273c917cd62SIthamar R. Adema 		}
274c917cd62SIthamar R. Adema 	} while (start != 0 && start < end);
275c917cd62SIthamar R. Adema 
276c917cd62SIthamar R. Adema 	return B_OK;
277c917cd62SIthamar R. Adema }
278c917cd62SIthamar R. Adema 
279c917cd62SIthamar R. Adema 
2801819aa71SIthamar R. Adema status_t
DebugMarkRangePresent(addr_t start,addr_t end,bool markPresent)2811819aa71SIthamar R. Adema ARMVMTranslationMap32Bit::DebugMarkRangePresent(addr_t start, addr_t end,
2821819aa71SIthamar R. Adema 	bool markPresent)
2831819aa71SIthamar R. Adema {
2841819aa71SIthamar R. Adema #if 0
2851819aa71SIthamar R. Adema 	start = ROUNDDOWN(start, B_PAGE_SIZE);
2861819aa71SIthamar R. Adema 	if (start >= end)
2871819aa71SIthamar R. Adema 		return B_OK;
2881819aa71SIthamar R. Adema 
2891819aa71SIthamar R. Adema 	page_directory_entry *pd = fPagingStructures->pgdir_virt;
2901819aa71SIthamar R. Adema 
2911819aa71SIthamar R. Adema 	do {
2921819aa71SIthamar R. Adema 		int index = VADDR_TO_PDENT(start);
2931819aa71SIthamar R. Adema 		if ((pd[index] & X86_PDE_PRESENT) == 0) {
2941819aa71SIthamar R. Adema 			// no page table here, move the start up to access the next page
2951819aa71SIthamar R. Adema 			// table
2961819aa71SIthamar R. Adema 			start = ROUNDUP(start + 1, kPageTableAlignment);
2971819aa71SIthamar R. Adema 			continue;
2981819aa71SIthamar R. Adema 		}
2991819aa71SIthamar R. Adema 
3001819aa71SIthamar R. Adema 		Thread* thread = thread_get_current_thread();
3011819aa71SIthamar R. Adema 		ThreadCPUPinner pinner(thread);
3021819aa71SIthamar R. Adema 
3031819aa71SIthamar R. Adema 		page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
3041819aa71SIthamar R. Adema 			pd[index] & X86_PDE_ADDRESS_MASK);
3051819aa71SIthamar R. Adema 
3061819aa71SIthamar R. Adema 		for (index = VADDR_TO_PTENT(start); (index < 1024) && (start < end);
3071819aa71SIthamar R. Adema 				index++, start += B_PAGE_SIZE) {
3081819aa71SIthamar R. Adema 			if ((pt[index] & X86_PTE_PRESENT) == 0) {
3091819aa71SIthamar R. Adema 				if (!markPresent)
3101819aa71SIthamar R. Adema 					continue;
3111819aa71SIthamar R. Adema 
3121819aa71SIthamar R. Adema 				X86PagingMethod32Bit::SetPageTableEntryFlags(&pt[index],
3131819aa71SIthamar R. Adema 					X86_PTE_PRESENT);
3141819aa71SIthamar R. Adema 			} else {
3151819aa71SIthamar R. Adema 				if (markPresent)
3161819aa71SIthamar R. Adema 					continue;
3171819aa71SIthamar R. Adema 
3181819aa71SIthamar R. Adema 				page_table_entry oldEntry
3191819aa71SIthamar R. Adema 					= X86PagingMethod32Bit::ClearPageTableEntryFlags(&pt[index],
3201819aa71SIthamar R. Adema 						X86_PTE_PRESENT);
3211819aa71SIthamar R. Adema 
322d38dcddeSDavid Karoly 				if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
3231819aa71SIthamar R. Adema 					// Note, that we only need to invalidate the address, if the
3241819aa71SIthamar R. Adema 					// accessed flags was set, since only then the entry could
3251819aa71SIthamar R. Adema 					// have been in any TLB.
3261819aa71SIthamar R. Adema 					InvalidatePage(start);
3271819aa71SIthamar R. Adema 				}
3281819aa71SIthamar R. Adema 			}
3291819aa71SIthamar R. Adema 		}
3301819aa71SIthamar R. Adema 	} while (start != 0 && start < end);
3311819aa71SIthamar R. Adema #endif
3321819aa71SIthamar R. Adema 	return B_OK;
3331819aa71SIthamar R. Adema }
3341819aa71SIthamar R. Adema 
3351819aa71SIthamar R. Adema 
336c917cd62SIthamar R. Adema /*!	Caller must have locked the cache of the page to be unmapped.
337c917cd62SIthamar R. Adema 	This object shouldn't be locked.
338c917cd62SIthamar R. Adema */
339c917cd62SIthamar R. Adema status_t
UnmapPage(VMArea * area,addr_t address,bool updatePageQueue)340c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::UnmapPage(VMArea* area, addr_t address,
341c917cd62SIthamar R. Adema 	bool updatePageQueue)
342c917cd62SIthamar R. Adema {
343c917cd62SIthamar R. Adema 	ASSERT(address % B_PAGE_SIZE == 0);
344c917cd62SIthamar R. Adema 
345c917cd62SIthamar R. Adema 	page_directory_entry* pd = fPagingStructures->pgdir_virt;
346c917cd62SIthamar R. Adema 
347c917cd62SIthamar R. Adema 	TRACE("ARMVMTranslationMap32Bit::UnmapPage(%#" B_PRIxADDR ")\n", address);
348c917cd62SIthamar R. Adema 
349c917cd62SIthamar R. Adema 	RecursiveLocker locker(fLock);
350c917cd62SIthamar R. Adema 
351c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(address);
352c917cd62SIthamar R. Adema 	if ((pd[index] & ARM_PDE_TYPE_MASK) == 0)
353c917cd62SIthamar R. Adema 		return B_ENTRY_NOT_FOUND;
354c917cd62SIthamar R. Adema 
355c917cd62SIthamar R. Adema 	ThreadCPUPinner pinner(thread_get_current_thread());
356c917cd62SIthamar R. Adema 
357c917cd62SIthamar R. Adema 	page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
358c917cd62SIthamar R. Adema 		pd[index] & ARM_PDE_ADDRESS_MASK);
359c917cd62SIthamar R. Adema 
360c917cd62SIthamar R. Adema 	index = VADDR_TO_PTENT(address);
361c917cd62SIthamar R. Adema 	page_table_entry oldEntry = ARMPagingMethod32Bit::ClearPageTableEntry(
362c917cd62SIthamar R. Adema 		&pt[index]);
363c917cd62SIthamar R. Adema 
364c917cd62SIthamar R. Adema 	pinner.Unlock();
365c917cd62SIthamar R. Adema 
366c917cd62SIthamar R. Adema 	if ((oldEntry & ARM_PTE_TYPE_MASK) == 0) {
367c917cd62SIthamar R. Adema 		// page mapping not valid
368c917cd62SIthamar R. Adema 		return B_ENTRY_NOT_FOUND;
369c917cd62SIthamar R. Adema 	}
370c917cd62SIthamar R. Adema 
371c917cd62SIthamar R. Adema 	fMapCount--;
372c917cd62SIthamar R. Adema 
373f86b5828SIthamar R. Adema 
374d38dcddeSDavid Karoly 	if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
375c917cd62SIthamar R. Adema 		// Note, that we only need to invalidate the address, if the
376c917cd62SIthamar R. Adema 		// accessed flags was set, since only then the entry could have been
377c917cd62SIthamar R. Adema 		// in any TLB.
378c917cd62SIthamar R. Adema 		InvalidatePage(address);
379c917cd62SIthamar R. Adema 		Flush();
380c917cd62SIthamar R. Adema 
381c917cd62SIthamar R. Adema 		// NOTE: Between clearing the page table entry and Flush() other
382c917cd62SIthamar R. Adema 		// processors (actually even this processor with another thread of the
383c917cd62SIthamar R. Adema 		// same team) could still access the page in question via their cached
384c917cd62SIthamar R. Adema 		// entry. We can obviously lose a modified flag in this case, with the
385c917cd62SIthamar R. Adema 		// effect that the page looks unmodified (and might thus be recycled),
386c917cd62SIthamar R. Adema 		// but is actually modified.
387c917cd62SIthamar R. Adema 		// In most cases this is harmless, but for vm_remove_all_page_mappings()
388c917cd62SIthamar R. Adema 		// this is actually a problem.
389c917cd62SIthamar R. Adema 		// Interestingly FreeBSD seems to ignore this problem as well
390c917cd62SIthamar R. Adema 		// (cf. pmap_remove_all()), unless I've missed something.
391c917cd62SIthamar R. Adema 	}
392f86b5828SIthamar R. Adema 
393c917cd62SIthamar R. Adema 	locker.Detach();
394c917cd62SIthamar R. Adema 		// PageUnmapped() will unlock for us
395f86b5828SIthamar R. Adema 
396c917cd62SIthamar R. Adema 	PageUnmapped(area, (oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE,
397d38dcddeSDavid Karoly 		(oldEntry & ARM_MMU_L2_FLAG_AP0) != 0, false /*(oldEntry & ARM_PTE_DIRTY) != 0*/,
398c917cd62SIthamar R. Adema 		updatePageQueue);
399f86b5828SIthamar R. Adema 
400c917cd62SIthamar R. Adema 	return B_OK;
401c917cd62SIthamar R. Adema }
402c917cd62SIthamar R. Adema 
403c917cd62SIthamar R. Adema 
404c917cd62SIthamar R. Adema void
UnmapPages(VMArea * area,addr_t base,size_t size,bool updatePageQueue)405c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
406c917cd62SIthamar R. Adema 	bool updatePageQueue)
407c917cd62SIthamar R. Adema {
408c917cd62SIthamar R. Adema 	if (size == 0)
409c917cd62SIthamar R. Adema 		return;
410c917cd62SIthamar R. Adema 
411c917cd62SIthamar R. Adema 	addr_t start = base;
412c917cd62SIthamar R. Adema 	addr_t end = base + size - 1;
413c917cd62SIthamar R. Adema 
414c917cd62SIthamar R. Adema 	TRACE("ARMVMTranslationMap32Bit::UnmapPages(%p, %#" B_PRIxADDR ", %#"
415c917cd62SIthamar R. Adema 		B_PRIxADDR ")\n", area, start, end);
416c917cd62SIthamar R. Adema 
417c917cd62SIthamar R. Adema 	page_directory_entry* pd = fPagingStructures->pgdir_virt;
418c917cd62SIthamar R. Adema 
419c917cd62SIthamar R. Adema 	VMAreaMappings queue;
420c917cd62SIthamar R. Adema 
421c917cd62SIthamar R. Adema 	RecursiveLocker locker(fLock);
422c917cd62SIthamar R. Adema 
423c917cd62SIthamar R. Adema 	do {
424c917cd62SIthamar R. Adema 		int index = VADDR_TO_PDENT(start);
425c917cd62SIthamar R. Adema 		if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
426c917cd62SIthamar R. Adema 			// no page table here, move the start up to access the next page
427c917cd62SIthamar R. Adema 			// table
428c917cd62SIthamar R. Adema 			start = ROUNDUP(start + 1, kPageTableAlignment);
429c917cd62SIthamar R. Adema 			continue;
430c917cd62SIthamar R. Adema 		}
431c917cd62SIthamar R. Adema 
4324535495dSIngo Weinhold 		Thread* thread = thread_get_current_thread();
433c917cd62SIthamar R. Adema 		ThreadCPUPinner pinner(thread);
434c917cd62SIthamar R. Adema 
435c917cd62SIthamar R. Adema 		page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
436c917cd62SIthamar R. Adema 			pd[index] & ARM_PDE_ADDRESS_MASK);
437c917cd62SIthamar R. Adema 
438fed8bb7dSMichael Lotz 		for (index = VADDR_TO_PTENT(start); (index < 256) && (start < end);
439c917cd62SIthamar R. Adema 				index++, start += B_PAGE_SIZE) {
440c917cd62SIthamar R. Adema 			page_table_entry oldEntry
441c917cd62SIthamar R. Adema 				= ARMPagingMethod32Bit::ClearPageTableEntry(&pt[index]);
442c917cd62SIthamar R. Adema 			if ((oldEntry & ARM_PTE_TYPE_MASK) == 0)
443c917cd62SIthamar R. Adema 				continue;
444c917cd62SIthamar R. Adema 
445c917cd62SIthamar R. Adema 			fMapCount--;
446c917cd62SIthamar R. Adema 
447d38dcddeSDavid Karoly 			if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
448c917cd62SIthamar R. Adema 				// Note, that we only need to invalidate the address, if the
449c917cd62SIthamar R. Adema 				// accessed flags was set, since only then the entry could have
450c917cd62SIthamar R. Adema 				// been in any TLB.
451c917cd62SIthamar R. Adema 				InvalidatePage(start);
452c917cd62SIthamar R. Adema 			}
453f86b5828SIthamar R. Adema 
454c917cd62SIthamar R. Adema 			if (area->cache_type != CACHE_TYPE_DEVICE) {
455c917cd62SIthamar R. Adema 				// get the page
456c917cd62SIthamar R. Adema 				vm_page* page = vm_lookup_page(
457c917cd62SIthamar R. Adema 					(oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE);
458c917cd62SIthamar R. Adema 				ASSERT(page != NULL);
459c917cd62SIthamar R. Adema 
460c917cd62SIthamar R. Adema 				DEBUG_PAGE_ACCESS_START(page);
461f86b5828SIthamar R. Adema 
462c917cd62SIthamar R. Adema 				// transfer the accessed/dirty flags to the page
463d38dcddeSDavid Karoly 				if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0)
464c917cd62SIthamar R. Adema 					page->accessed = true;
465b799d160SDavid Karoly 				if ((oldEntry & ARM_MMU_L2_FLAG_AP2) == 0)
466c917cd62SIthamar R. Adema 					page->modified = true;
467f86b5828SIthamar R. Adema 
468c917cd62SIthamar R. Adema 				// remove the mapping object/decrement the wired_count of the
469c917cd62SIthamar R. Adema 				// page
470c917cd62SIthamar R. Adema 				if (area->wiring == B_NO_LOCK) {
471c917cd62SIthamar R. Adema 					vm_page_mapping* mapping = NULL;
472c917cd62SIthamar R. Adema 					vm_page_mappings::Iterator iterator
473c917cd62SIthamar R. Adema 						= page->mappings.GetIterator();
474c917cd62SIthamar R. Adema 					while ((mapping = iterator.Next()) != NULL) {
475c917cd62SIthamar R. Adema 						if (mapping->area == area)
476c917cd62SIthamar R. Adema 							break;
477c917cd62SIthamar R. Adema 					}
478c917cd62SIthamar R. Adema 
479c917cd62SIthamar R. Adema 					ASSERT(mapping != NULL);
480c917cd62SIthamar R. Adema 
481c917cd62SIthamar R. Adema 					area->mappings.Remove(mapping);
482c917cd62SIthamar R. Adema 					page->mappings.Remove(mapping);
483c917cd62SIthamar R. Adema 					queue.Add(mapping);
484c917cd62SIthamar R. Adema 				} else
485c917cd62SIthamar R. Adema 					page->DecrementWiredCount();
486c917cd62SIthamar R. Adema 
487c917cd62SIthamar R. Adema 				if (!page->IsMapped()) {
488c917cd62SIthamar R. Adema 					atomic_add(&gMappedPagesCount, -1);
489c917cd62SIthamar R. Adema 
490c917cd62SIthamar R. Adema 					if (updatePageQueue) {
491c917cd62SIthamar R. Adema 						if (page->Cache()->temporary)
492c917cd62SIthamar R. Adema 							vm_page_set_state(page, PAGE_STATE_INACTIVE);
493c917cd62SIthamar R. Adema 						else if (page->modified)
494c917cd62SIthamar R. Adema 							vm_page_set_state(page, PAGE_STATE_MODIFIED);
495c917cd62SIthamar R. Adema 						else
496c917cd62SIthamar R. Adema 							vm_page_set_state(page, PAGE_STATE_CACHED);
497c917cd62SIthamar R. Adema 					}
498c917cd62SIthamar R. Adema 				}
499c917cd62SIthamar R. Adema 
500c917cd62SIthamar R. Adema 				DEBUG_PAGE_ACCESS_END(page);
501c917cd62SIthamar R. Adema 			}
502c917cd62SIthamar R. Adema 		}
503c917cd62SIthamar R. Adema 
504c917cd62SIthamar R. Adema 		Flush();
505c917cd62SIthamar R. Adema 			// flush explicitly, since we directly use the lock
506c917cd62SIthamar R. Adema 	} while (start != 0 && start < end);
507c917cd62SIthamar R. Adema 
508c917cd62SIthamar R. Adema 	// TODO: As in UnmapPage() we can lose page dirty flags here. ATM it's not
509c917cd62SIthamar R. Adema 	// really critical here, as in all cases this method is used, the unmapped
510c917cd62SIthamar R. Adema 	// area range is unmapped for good (resized/cut) and the pages will likely
511c917cd62SIthamar R. Adema 	// be freed.
512c917cd62SIthamar R. Adema 
513c917cd62SIthamar R. Adema 	locker.Unlock();
514c917cd62SIthamar R. Adema 
515c917cd62SIthamar R. Adema 	// free removed mappings
516c917cd62SIthamar R. Adema 	bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
517c917cd62SIthamar R. Adema 	uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY
518c917cd62SIthamar R. Adema 		| (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0);
519c917cd62SIthamar R. Adema 	while (vm_page_mapping* mapping = queue.RemoveHead())
520*08c53ca9SAugustin Cavalier 		vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
521c917cd62SIthamar R. Adema }
522c917cd62SIthamar R. Adema 
523c917cd62SIthamar R. Adema 
524c917cd62SIthamar R. Adema void
UnmapArea(VMArea * area,bool deletingAddressSpace,bool ignoreTopCachePageFlags)525c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::UnmapArea(VMArea* area, bool deletingAddressSpace,
526c917cd62SIthamar R. Adema 	bool ignoreTopCachePageFlags)
527c917cd62SIthamar R. Adema {
528c917cd62SIthamar R. Adema 	if (area->cache_type == CACHE_TYPE_DEVICE || area->wiring != B_NO_LOCK) {
529c917cd62SIthamar R. Adema 		ARMVMTranslationMap32Bit::UnmapPages(area, area->Base(), area->Size(),
530c917cd62SIthamar R. Adema 			true);
531c917cd62SIthamar R. Adema 		return;
532c917cd62SIthamar R. Adema 	}
533c917cd62SIthamar R. Adema 
534c917cd62SIthamar R. Adema 	bool unmapPages = !deletingAddressSpace || !ignoreTopCachePageFlags;
535c917cd62SIthamar R. Adema 
536c917cd62SIthamar R. Adema 	page_directory_entry* pd = fPagingStructures->pgdir_virt;
537c917cd62SIthamar R. Adema 
538c917cd62SIthamar R. Adema 	RecursiveLocker locker(fLock);
539c917cd62SIthamar R. Adema 
540c917cd62SIthamar R. Adema 	VMAreaMappings mappings;
541c917cd62SIthamar R. Adema 	mappings.MoveFrom(&area->mappings);
542c917cd62SIthamar R. Adema 
543c917cd62SIthamar R. Adema 	for (VMAreaMappings::Iterator it = mappings.GetIterator();
544c917cd62SIthamar R. Adema 			vm_page_mapping* mapping = it.Next();) {
545c917cd62SIthamar R. Adema 		vm_page* page = mapping->page;
546c917cd62SIthamar R. Adema 		page->mappings.Remove(mapping);
547c917cd62SIthamar R. Adema 
548c917cd62SIthamar R. Adema 		VMCache* cache = page->Cache();
549c917cd62SIthamar R. Adema 
550c917cd62SIthamar R. Adema 		bool pageFullyUnmapped = false;
551c917cd62SIthamar R. Adema 		if (!page->IsMapped()) {
552c917cd62SIthamar R. Adema 			atomic_add(&gMappedPagesCount, -1);
553c917cd62SIthamar R. Adema 			pageFullyUnmapped = true;
554c917cd62SIthamar R. Adema 		}
555c917cd62SIthamar R. Adema 
556c917cd62SIthamar R. Adema 		if (unmapPages || cache != area->cache) {
557c917cd62SIthamar R. Adema 			addr_t address = area->Base()
558c917cd62SIthamar R. Adema 				+ ((page->cache_offset * B_PAGE_SIZE) - area->cache_offset);
559c917cd62SIthamar R. Adema 
560c917cd62SIthamar R. Adema 			int index = VADDR_TO_PDENT(address);
561c917cd62SIthamar R. Adema 			if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
562c917cd62SIthamar R. Adema 				panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
563c917cd62SIthamar R. Adema 					"has no page dir entry", page, area, address);
564c917cd62SIthamar R. Adema 				continue;
565c917cd62SIthamar R. Adema 			}
566c917cd62SIthamar R. Adema 
567c917cd62SIthamar R. Adema 			ThreadCPUPinner pinner(thread_get_current_thread());
568c917cd62SIthamar R. Adema 
569c917cd62SIthamar R. Adema 			page_table_entry* pt
570c917cd62SIthamar R. Adema 				= (page_table_entry*)fPageMapper->GetPageTableAt(
571c917cd62SIthamar R. Adema 					pd[index] & ARM_PDE_ADDRESS_MASK);
572c917cd62SIthamar R. Adema 			page_table_entry oldEntry
573c917cd62SIthamar R. Adema 				= ARMPagingMethod32Bit::ClearPageTableEntry(
574c917cd62SIthamar R. Adema 					&pt[VADDR_TO_PTENT(address)]);
575c917cd62SIthamar R. Adema 
576c917cd62SIthamar R. Adema 			pinner.Unlock();
577c917cd62SIthamar R. Adema 
578c917cd62SIthamar R. Adema 			if ((oldEntry & ARM_PTE_TYPE_MASK) == 0) {
579c917cd62SIthamar R. Adema 				panic("page %p has mapping for area %p (%#" B_PRIxADDR "), but "
580c917cd62SIthamar R. Adema 					"has no page table entry", page, area, address);
581c917cd62SIthamar R. Adema 				continue;
582c917cd62SIthamar R. Adema 			}
583f86b5828SIthamar R. Adema 
584c917cd62SIthamar R. Adema 			// transfer the accessed/dirty flags to the page and invalidate
585c917cd62SIthamar R. Adema 			// the mapping, if necessary
586d38dcddeSDavid Karoly 			if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
587c917cd62SIthamar R. Adema 				page->accessed = true;
588c917cd62SIthamar R. Adema 
589c917cd62SIthamar R. Adema 				if (!deletingAddressSpace)
590c917cd62SIthamar R. Adema 					InvalidatePage(address);
591c917cd62SIthamar R. Adema 			}
592c917cd62SIthamar R. Adema 
593772df0f6SDavid Karoly 			if (false /*(oldEntry & ARM_PTE_DIRTY) != 0*/)
594c917cd62SIthamar R. Adema 				page->modified = true;
595f86b5828SIthamar R. Adema 
596c917cd62SIthamar R. Adema 			if (pageFullyUnmapped) {
597c917cd62SIthamar R. Adema 				DEBUG_PAGE_ACCESS_START(page);
598c917cd62SIthamar R. Adema 
599c917cd62SIthamar R. Adema 				if (cache->temporary)
600c917cd62SIthamar R. Adema 					vm_page_set_state(page, PAGE_STATE_INACTIVE);
601c917cd62SIthamar R. Adema 				else if (page->modified)
602c917cd62SIthamar R. Adema 					vm_page_set_state(page, PAGE_STATE_MODIFIED);
603c917cd62SIthamar R. Adema 				else
604c917cd62SIthamar R. Adema 					vm_page_set_state(page, PAGE_STATE_CACHED);
605c917cd62SIthamar R. Adema 
606c917cd62SIthamar R. Adema 				DEBUG_PAGE_ACCESS_END(page);
607c917cd62SIthamar R. Adema 			}
608c917cd62SIthamar R. Adema 		}
609c917cd62SIthamar R. Adema 
610c917cd62SIthamar R. Adema 		fMapCount--;
611c917cd62SIthamar R. Adema 	}
612c917cd62SIthamar R. Adema 
613c917cd62SIthamar R. Adema 	Flush();
614c917cd62SIthamar R. Adema 		// flush explicitely, since we directly use the lock
615c917cd62SIthamar R. Adema 
616c917cd62SIthamar R. Adema 	locker.Unlock();
617c917cd62SIthamar R. Adema 
618c917cd62SIthamar R. Adema 	bool isKernelSpace = area->address_space == VMAddressSpace::Kernel();
619c917cd62SIthamar R. Adema 	uint32 freeFlags = CACHE_DONT_WAIT_FOR_MEMORY
620c917cd62SIthamar R. Adema 		| (isKernelSpace ? CACHE_DONT_LOCK_KERNEL_SPACE : 0);
621c917cd62SIthamar R. Adema 	while (vm_page_mapping* mapping = mappings.RemoveHead())
622*08c53ca9SAugustin Cavalier 		vm_free_page_mapping(mapping->page->physical_page_number, mapping, freeFlags);
623c917cd62SIthamar R. Adema }
624c917cd62SIthamar R. Adema 
625c917cd62SIthamar R. Adema 
626c917cd62SIthamar R. Adema status_t
Query(addr_t va,phys_addr_t * _physical,uint32 * _flags)627c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::Query(addr_t va, phys_addr_t *_physical,
628c917cd62SIthamar R. Adema 	uint32 *_flags)
629c917cd62SIthamar R. Adema {
630c917cd62SIthamar R. Adema 	// default the flags to not present
631c917cd62SIthamar R. Adema 	*_flags = 0;
632c917cd62SIthamar R. Adema 	*_physical = 0;
633c917cd62SIthamar R. Adema 
634c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(va);
635c917cd62SIthamar R. Adema 	page_directory_entry *pd = fPagingStructures->pgdir_virt;
636c917cd62SIthamar R. Adema 	if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
637c917cd62SIthamar R. Adema 		// no pagetable here
638c917cd62SIthamar R. Adema 		return B_OK;
639c917cd62SIthamar R. Adema 	}
640c917cd62SIthamar R. Adema 
6414535495dSIngo Weinhold 	Thread* thread = thread_get_current_thread();
642c917cd62SIthamar R. Adema 	ThreadCPUPinner pinner(thread);
643c917cd62SIthamar R. Adema 
644c917cd62SIthamar R. Adema 	page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
645c917cd62SIthamar R. Adema 		pd[index] & ARM_PDE_ADDRESS_MASK);
646c917cd62SIthamar R. Adema 	page_table_entry entry = pt[VADDR_TO_PTENT(va)];
647c917cd62SIthamar R. Adema 
648f0422c6fSMichael Lotz 	if ((entry & ARM_PTE_TYPE_MASK) != 0)
649286a9c99SDavid Karoly 		*_physical = (entry & ARM_PTE_ADDRESS_MASK);
650c917cd62SIthamar R. Adema 
651745a40d7SDavid Karoly 	*_flags = ARMPagingMethod32Bit::PageTableEntryFlagsToAttributes(entry);
652d09e7b5bSIthamar R. Adema 	if (*_physical != 0)
653d09e7b5bSIthamar R. Adema 		*_flags |= PAGE_PRESENT;
654745a40d7SDavid Karoly 
655c917cd62SIthamar R. Adema 	pinner.Unlock();
656c917cd62SIthamar R. Adema 
657c917cd62SIthamar R. Adema 	TRACE("query_tmap: returning pa 0x%lx for va 0x%lx\n", *_physical, va);
658c917cd62SIthamar R. Adema 
659c917cd62SIthamar R. Adema 	return B_OK;
660c917cd62SIthamar R. Adema }
661c917cd62SIthamar R. Adema 
662c917cd62SIthamar R. Adema 
663c917cd62SIthamar R. Adema status_t
QueryInterrupt(addr_t va,phys_addr_t * _physical,uint32 * _flags)664c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::QueryInterrupt(addr_t va, phys_addr_t *_physical,
665c917cd62SIthamar R. Adema 	uint32 *_flags)
666c917cd62SIthamar R. Adema {
667c917cd62SIthamar R. Adema 	*_flags = 0;
668c917cd62SIthamar R. Adema 	*_physical = 0;
669c917cd62SIthamar R. Adema 
670c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(va);
671c917cd62SIthamar R. Adema 	page_directory_entry* pd = fPagingStructures->pgdir_virt;
672c917cd62SIthamar R. Adema 	if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
673c917cd62SIthamar R. Adema 		// no pagetable here
674c917cd62SIthamar R. Adema 		return B_OK;
675c917cd62SIthamar R. Adema 	}
676c917cd62SIthamar R. Adema 
677c917cd62SIthamar R. Adema 	// map page table entry
678c917cd62SIthamar R. Adema 	page_table_entry* pt = (page_table_entry*)ARMPagingMethod32Bit::Method()
679c917cd62SIthamar R. Adema 		->PhysicalPageMapper()->InterruptGetPageTableAt(
680c917cd62SIthamar R. Adema 			pd[index] & ARM_PDE_ADDRESS_MASK);
681c917cd62SIthamar R. Adema 	page_table_entry entry = pt[VADDR_TO_PTENT(va)];
682c917cd62SIthamar R. Adema 
683f0422c6fSMichael Lotz 	if ((entry & ARM_PTE_TYPE_MASK) != 0)
684c8e72ef9SDavid Karoly 		*_physical = (entry & ARM_PTE_ADDRESS_MASK);
685926d1024SMichael Lotz 
686745a40d7SDavid Karoly 	*_flags = ARMPagingMethod32Bit::PageTableEntryFlagsToAttributes(entry);
687f0422c6fSMichael Lotz 	if (*_physical != 0)
688f0422c6fSMichael Lotz 		*_flags |= PAGE_PRESENT;
689745a40d7SDavid Karoly 
690c917cd62SIthamar R. Adema 	return B_OK;
691c917cd62SIthamar R. Adema }
692c917cd62SIthamar R. Adema 
693c917cd62SIthamar R. Adema 
694c917cd62SIthamar R. Adema status_t
Protect(addr_t start,addr_t end,uint32 attributes,uint32 memoryType)695c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::Protect(addr_t start, addr_t end, uint32 attributes,
696c917cd62SIthamar R. Adema 	uint32 memoryType)
697c917cd62SIthamar R. Adema {
698c917cd62SIthamar R. Adema 	start = ROUNDDOWN(start, B_PAGE_SIZE);
699c917cd62SIthamar R. Adema 	if (start >= end)
700c917cd62SIthamar R. Adema 		return B_OK;
701c917cd62SIthamar R. Adema 
702c917cd62SIthamar R. Adema 	TRACE("protect_tmap: pages 0x%lx to 0x%lx, attributes %lx\n", start, end,
703c917cd62SIthamar R. Adema 		attributes);
704745a40d7SDavid Karoly 
705745a40d7SDavid Karoly 	uint32 newProtectionFlags = ARMPagingMethod32Bit::AttributesToPageTableEntryFlags(attributes);
706745a40d7SDavid Karoly 	uint32 newMemoryTypeFlags = ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags(memoryType);
707c917cd62SIthamar R. Adema 
708c917cd62SIthamar R. Adema 	page_directory_entry *pd = fPagingStructures->pgdir_virt;
709c917cd62SIthamar R. Adema 
710c917cd62SIthamar R. Adema 	do {
711c917cd62SIthamar R. Adema 		int index = VADDR_TO_PDENT(start);
712c917cd62SIthamar R. Adema 		if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
713c917cd62SIthamar R. Adema 			// no page table here, move the start up to access the next page
714c917cd62SIthamar R. Adema 			// table
715c917cd62SIthamar R. Adema 			start = ROUNDUP(start + 1, kPageTableAlignment);
716c917cd62SIthamar R. Adema 			continue;
717c917cd62SIthamar R. Adema 		}
718c917cd62SIthamar R. Adema 
7194535495dSIngo Weinhold 		Thread* thread = thread_get_current_thread();
720c917cd62SIthamar R. Adema 		ThreadCPUPinner pinner(thread);
721c917cd62SIthamar R. Adema 
722c917cd62SIthamar R. Adema 		page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
723c917cd62SIthamar R. Adema 			pd[index] & ARM_PDE_ADDRESS_MASK);
724c917cd62SIthamar R. Adema 
725fed8bb7dSMichael Lotz 		for (index = VADDR_TO_PTENT(start); index < 256 && start < end;
726c917cd62SIthamar R. Adema 				index++, start += B_PAGE_SIZE) {
727c917cd62SIthamar R. Adema 			page_table_entry entry = pt[index];
728745a40d7SDavid Karoly 			if ((entry & ARM_PTE_TYPE_MASK) == 0) {
729c917cd62SIthamar R. Adema 				// page mapping not valid
730c917cd62SIthamar R. Adema 				continue;
731c917cd62SIthamar R. Adema 			}
732c917cd62SIthamar R. Adema 
733c917cd62SIthamar R. Adema 			TRACE("protect_tmap: protect page 0x%lx\n", start);
734c917cd62SIthamar R. Adema 
735c917cd62SIthamar R. Adema 			// set the new protection flags -- we want to do that atomically,
736c917cd62SIthamar R. Adema 			// without changing the accessed or dirty flag
737c917cd62SIthamar R. Adema 			page_table_entry oldEntry;
738c917cd62SIthamar R. Adema 			while (true) {
739c917cd62SIthamar R. Adema 				oldEntry = ARMPagingMethod32Bit::TestAndSetPageTableEntry(
740c917cd62SIthamar R. Adema 					&pt[index],
741c917cd62SIthamar R. Adema 					(entry & ~(ARM_PTE_PROTECTION_MASK
742c917cd62SIthamar R. Adema 							| ARM_PTE_MEMORY_TYPE_MASK))
743745a40d7SDavid Karoly 						| newProtectionFlags | newMemoryTypeFlags,
744c917cd62SIthamar R. Adema 					entry);
745c917cd62SIthamar R. Adema 				if (oldEntry == entry)
746c917cd62SIthamar R. Adema 					break;
747c917cd62SIthamar R. Adema 				entry = oldEntry;
748c917cd62SIthamar R. Adema 			}
749c917cd62SIthamar R. Adema 
750d38dcddeSDavid Karoly 			if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
751d38dcddeSDavid Karoly 				// Note, that we only need to invalidate the address, if the
752d38dcddeSDavid Karoly 				// accessed flag was set, since only then the entry could have
753d38dcddeSDavid Karoly 				// been in any TLB.
754c917cd62SIthamar R. Adema 				InvalidatePage(start);
755c917cd62SIthamar R. Adema 			}
756d38dcddeSDavid Karoly 		}
757c917cd62SIthamar R. Adema 	} while (start != 0 && start < end);
758745a40d7SDavid Karoly 
759c917cd62SIthamar R. Adema 	return B_OK;
760c917cd62SIthamar R. Adema }
761c917cd62SIthamar R. Adema 
762c917cd62SIthamar R. Adema 
763c917cd62SIthamar R. Adema status_t
SetFlags(addr_t virtualAddress,uint32 flags)764cce0386aSDavid Karoly ARMVMTranslationMap32Bit::SetFlags(addr_t virtualAddress, uint32 flags)
765cce0386aSDavid Karoly {
766cce0386aSDavid Karoly 	int index = VADDR_TO_PDENT(virtualAddress);
767cce0386aSDavid Karoly 	page_directory_entry* pd = fPagingStructures->pgdir_virt;
768cce0386aSDavid Karoly 	if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
769cce0386aSDavid Karoly 		// no pagetable here
770cce0386aSDavid Karoly 		return B_OK;
771cce0386aSDavid Karoly 	}
772cce0386aSDavid Karoly 
773cce0386aSDavid Karoly 	uint32 flagsToSet = (flags & PAGE_ACCESSED) ? ARM_MMU_L2_FLAG_AP0 : 0;
774b799d160SDavid Karoly 	uint32 flagsToClear = (flags & PAGE_MODIFIED) ? ARM_MMU_L2_FLAG_AP2 : 0;
775cce0386aSDavid Karoly 
776cce0386aSDavid Karoly 	page_table_entry* pt = (page_table_entry*)ARMPagingMethod32Bit::Method()
777cce0386aSDavid Karoly 		->PhysicalPageMapper()->InterruptGetPageTableAt(
778cce0386aSDavid Karoly 			pd[index] & ARM_PDE_ADDRESS_MASK);
779cce0386aSDavid Karoly 	index = VADDR_TO_PTENT(virtualAddress);
780cce0386aSDavid Karoly 
781b799d160SDavid Karoly 	ARMPagingMethod32Bit::SetAndClearPageTableEntryFlags(&pt[index], flagsToSet, flagsToClear);
782cce0386aSDavid Karoly 
783b799d160SDavid Karoly 	// normally we would call InvalidatePage() here and then Flush() later when all updates are done
784b799d160SDavid Karoly 	// however, as this scenario happens only in case of Modified flag handling,
785b799d160SDavid Karoly 	// we can directly call TLBIMVAIS from here as we need to update only a single TLB entry
786b799d160SDavid Karoly 	if (flagsToClear)
787b799d160SDavid Karoly 		arch_cpu_invalidate_TLB_page(virtualAddress);
788cce0386aSDavid Karoly 
789cce0386aSDavid Karoly 	return B_OK;
790cce0386aSDavid Karoly }
791cce0386aSDavid Karoly 
792cce0386aSDavid Karoly 
793cce0386aSDavid Karoly status_t
ClearFlags(addr_t va,uint32 flags)794c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::ClearFlags(addr_t va, uint32 flags)
795c917cd62SIthamar R. Adema {
796c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(va);
797c917cd62SIthamar R. Adema 	page_directory_entry* pd = fPagingStructures->pgdir_virt;
798c917cd62SIthamar R. Adema 	if ((pd[index] & ARM_PDE_TYPE_MASK) == 0) {
799c917cd62SIthamar R. Adema 		// no pagetable here
800c917cd62SIthamar R. Adema 		return B_OK;
801c917cd62SIthamar R. Adema 	}
802b799d160SDavid Karoly 
803d38dcddeSDavid Karoly 	uint32 flagsToClear = (flags & PAGE_ACCESSED) ? ARM_MMU_L2_FLAG_AP0 : 0;
804b799d160SDavid Karoly 	uint32 flagsToSet = (flags & PAGE_MODIFIED) ? ARM_MMU_L2_FLAG_AP2 : 0;
805b799d160SDavid Karoly 
8064535495dSIngo Weinhold 	Thread* thread = thread_get_current_thread();
807c917cd62SIthamar R. Adema 	ThreadCPUPinner pinner(thread);
808c917cd62SIthamar R. Adema 
809c917cd62SIthamar R. Adema 	page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
810c917cd62SIthamar R. Adema 		pd[index] & ARM_PDE_ADDRESS_MASK);
811c917cd62SIthamar R. Adema 	index = VADDR_TO_PTENT(va);
812c917cd62SIthamar R. Adema 
813b799d160SDavid Karoly 	// adjust the flags we've been requested to set/clear
814c917cd62SIthamar R. Adema 	page_table_entry oldEntry
815b799d160SDavid Karoly 		= ARMPagingMethod32Bit::SetAndClearPageTableEntryFlags(&pt[index],
816b799d160SDavid Karoly 			flagsToSet, flagsToClear);
817c917cd62SIthamar R. Adema 
818c917cd62SIthamar R. Adema 	pinner.Unlock();
819c917cd62SIthamar R. Adema 
820b799d160SDavid Karoly 	if (((oldEntry & flagsToClear) != 0) || ((oldEntry & flagsToSet) == 0))
821c917cd62SIthamar R. Adema 		InvalidatePage(va);
822c917cd62SIthamar R. Adema 
823c917cd62SIthamar R. Adema 	return B_OK;
824c917cd62SIthamar R. Adema }
825c917cd62SIthamar R. Adema 
826c917cd62SIthamar R. Adema 
827c917cd62SIthamar R. Adema bool
ClearAccessedAndModified(VMArea * area,addr_t address,bool unmapIfUnaccessed,bool & _modified)828c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::ClearAccessedAndModified(VMArea* area, addr_t address,
829c917cd62SIthamar R. Adema 	bool unmapIfUnaccessed, bool& _modified)
830c917cd62SIthamar R. Adema {
831c917cd62SIthamar R. Adema 	ASSERT(address % B_PAGE_SIZE == 0);
832c917cd62SIthamar R. Adema 
833c917cd62SIthamar R. Adema 	page_directory_entry* pd = fPagingStructures->pgdir_virt;
834c917cd62SIthamar R. Adema 
835c917cd62SIthamar R. Adema 	TRACE("ARMVMTranslationMap32Bit::ClearAccessedAndModified(%#" B_PRIxADDR
836c917cd62SIthamar R. Adema 		")\n", address);
837c917cd62SIthamar R. Adema 
838c917cd62SIthamar R. Adema 	RecursiveLocker locker(fLock);
839c917cd62SIthamar R. Adema 
840c917cd62SIthamar R. Adema 	int index = VADDR_TO_PDENT(address);
841c917cd62SIthamar R. Adema 	if ((pd[index] & ARM_PDE_TYPE_MASK) == 0)
842c917cd62SIthamar R. Adema 		return false;
843c917cd62SIthamar R. Adema 
844c917cd62SIthamar R. Adema 	ThreadCPUPinner pinner(thread_get_current_thread());
845c917cd62SIthamar R. Adema 
846c917cd62SIthamar R. Adema 	page_table_entry* pt = (page_table_entry*)fPageMapper->GetPageTableAt(
847c917cd62SIthamar R. Adema 		pd[index] & ARM_PDE_ADDRESS_MASK);
848c917cd62SIthamar R. Adema 
849c917cd62SIthamar R. Adema 	index = VADDR_TO_PTENT(address);
850c917cd62SIthamar R. Adema 
851c917cd62SIthamar R. Adema 	// perform the deed
852c917cd62SIthamar R. Adema 	page_table_entry oldEntry;
853c917cd62SIthamar R. Adema 
854c917cd62SIthamar R. Adema 	if (unmapIfUnaccessed) {
855c917cd62SIthamar R. Adema 		while (true) {
856c917cd62SIthamar R. Adema 			oldEntry = pt[index];
857c917cd62SIthamar R. Adema 			if ((oldEntry & ARM_PTE_TYPE_MASK) == 0) {
858c917cd62SIthamar R. Adema 				// page mapping not valid
859c917cd62SIthamar R. Adema 				return false;
860c917cd62SIthamar R. Adema 			}
861d38dcddeSDavid Karoly 			if (oldEntry & ARM_MMU_L2_FLAG_AP0) {
862c917cd62SIthamar R. Adema 				// page was accessed -- just clear the flags
863b799d160SDavid Karoly 				oldEntry = ARMPagingMethod32Bit::SetAndClearPageTableEntryFlags(
864b799d160SDavid Karoly 					&pt[index], ARM_MMU_L2_FLAG_AP2, ARM_MMU_L2_FLAG_AP0);
865c917cd62SIthamar R. Adema 				break;
866c917cd62SIthamar R. Adema 			}
867d38dcddeSDavid Karoly 
868c917cd62SIthamar R. Adema 			// page hasn't been accessed -- unmap it
869c917cd62SIthamar R. Adema 			if (ARMPagingMethod32Bit::TestAndSetPageTableEntry(&pt[index], 0,
870c917cd62SIthamar R. Adema 					oldEntry) == oldEntry) {
871c917cd62SIthamar R. Adema 				break;
872c917cd62SIthamar R. Adema 			}
873c917cd62SIthamar R. Adema 
874c917cd62SIthamar R. Adema 			// something changed -- check again
875c917cd62SIthamar R. Adema 		}
876c917cd62SIthamar R. Adema 	} else {
877b799d160SDavid Karoly 		oldEntry = ARMPagingMethod32Bit::SetAndClearPageTableEntryFlags(&pt[index],
878b799d160SDavid Karoly 			ARM_MMU_L2_FLAG_AP2, ARM_MMU_L2_FLAG_AP0);
879c917cd62SIthamar R. Adema 	}
880c917cd62SIthamar R. Adema 
881c917cd62SIthamar R. Adema 	pinner.Unlock();
882c917cd62SIthamar R. Adema 
883b799d160SDavid Karoly 	_modified = (oldEntry & ARM_MMU_L2_FLAG_AP2) == 0;
884c917cd62SIthamar R. Adema 
885d38dcddeSDavid Karoly 	if ((oldEntry & ARM_MMU_L2_FLAG_AP0) != 0) {
886c917cd62SIthamar R. Adema 		// Note, that we only need to invalidate the address, if the
887c917cd62SIthamar R. Adema 		// accessed flags was set, since only then the entry could have been
888c917cd62SIthamar R. Adema 		// in any TLB.
889c917cd62SIthamar R. Adema 		InvalidatePage(address);
890c917cd62SIthamar R. Adema 
891c917cd62SIthamar R. Adema 		Flush();
892c917cd62SIthamar R. Adema 
893c917cd62SIthamar R. Adema 		return true;
894c917cd62SIthamar R. Adema 	}
895c917cd62SIthamar R. Adema 
896c917cd62SIthamar R. Adema 	if (!unmapIfUnaccessed)
897c917cd62SIthamar R. Adema 		return false;
898c917cd62SIthamar R. Adema 
899c917cd62SIthamar R. Adema 	// We have unmapped the address. Do the "high level" stuff.
900c917cd62SIthamar R. Adema 
901c917cd62SIthamar R. Adema 	fMapCount--;
902c917cd62SIthamar R. Adema 
903c917cd62SIthamar R. Adema 	locker.Detach();
904c917cd62SIthamar R. Adema 		// UnaccessedPageUnmapped() will unlock for us
905c917cd62SIthamar R. Adema 
906c917cd62SIthamar R. Adema 	UnaccessedPageUnmapped(area,
907c917cd62SIthamar R. Adema 		(oldEntry & ARM_PTE_ADDRESS_MASK) / B_PAGE_SIZE);
908c917cd62SIthamar R. Adema 
909c917cd62SIthamar R. Adema 	return false;
910c917cd62SIthamar R. Adema }
911c917cd62SIthamar R. Adema 
912c917cd62SIthamar R. Adema 
913c917cd62SIthamar R. Adema ARMPagingStructures*
PagingStructures() const914c917cd62SIthamar R. Adema ARMVMTranslationMap32Bit::PagingStructures() const
915c917cd62SIthamar R. Adema {
916c917cd62SIthamar R. Adema 	return fPagingStructures;
917c917cd62SIthamar R. Adema }
918