xref: /haiku/src/system/kernel/arch/arm/paging/32bit/ARMPagingMethod32Bit.h (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
1 /*
2  * Copyright 2010, Ithamar R. Adema, ithamar.adema@team-embedded.nl
3  * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
4  * Distributed under the terms of the MIT License.
5  */
6 #ifndef KERNEL_ARCH_ARM_PAGING_32_BIT_ARM_PAGING_METHOD_32_BIT_H
7 #define KERNEL_ARCH_ARM_PAGING_32_BIT_ARM_PAGING_METHOD_32_BIT_H
8 
9 
10 #include "paging/32bit/paging.h"
11 #include "paging/ARMPagingMethod.h"
12 #include "paging/ARMPagingStructures.h"
13 
14 #include <vm/VMAddressSpace.h>
15 
16 
17 class TranslationMapPhysicalPageMapper;
18 class ARMPhysicalPageMapper;
19 
20 
21 class ARMPagingMethod32Bit : public ARMPagingMethod {
22 public:
23 								ARMPagingMethod32Bit();
24 	virtual						~ARMPagingMethod32Bit();
25 
26 	virtual	status_t			Init(kernel_args* args,
27 									VMPhysicalPageMapper** _physicalPageMapper);
28 	virtual	status_t			InitPostArea(kernel_args* args);
29 
30 	virtual	status_t			CreateTranslationMap(bool kernel,
31 									VMTranslationMap** _map);
32 
33 	virtual	status_t			MapEarly(kernel_args* args,
34 									addr_t virtualAddress,
35 									phys_addr_t physicalAddress,
36 									uint8 attributes,
37 									page_num_t (*get_free_page)(kernel_args*));
38 
39 	virtual	bool				IsKernelPageAccessible(addr_t virtualAddress,
40 									uint32 protection);
41 
42 	inline	uint32				KernelPhysicalPageDirectory() const
43 									{ return fKernelPhysicalPageDirectory; }
44 	inline	page_directory_entry* KernelVirtualPageDirectory() const
45 									{ return fKernelVirtualPageDirectory; }
46 	inline	ARMPhysicalPageMapper* PhysicalPageMapper() const
47 									{ return fPhysicalPageMapper; }
48 	inline	TranslationMapPhysicalPageMapper* KernelPhysicalPageMapper() const
49 									{ return fKernelPhysicalPageMapper; }
50 
51 	static	ARMPagingMethod32Bit* Method();
52 
53 	static	void				PutPageTableInPageDir(
54 									page_directory_entry* entry,
55 									phys_addr_t pgtablePhysical,
56 									uint32 attributes);
57 	static	void				PutPageTableEntryInTable(
58 									page_table_entry* entry,
59 									phys_addr_t physicalAddress,
60 									uint32 attributes, uint32 memoryType,
61 									bool globalPage);
62 	static	page_table_entry	SetPageTableEntry(page_table_entry* entry,
63 									page_table_entry newEntry);
64 	static	page_table_entry	SetPageTableEntryFlags(page_table_entry* entry,
65 									uint32 flags);
66 	static	page_table_entry	TestAndSetPageTableEntry(
67 									page_table_entry* entry,
68 									page_table_entry newEntry,
69 									page_table_entry oldEntry);
70 	static	page_table_entry	ClearPageTableEntry(page_table_entry* entry);
71 	static	page_table_entry	ClearPageTableEntryFlags(
72 									page_table_entry* entry, uint32 flags);
73 	static	page_table_entry	SetAndClearPageTableEntryFlags(page_table_entry* entry,
74 									uint32 flagsToSet, uint32 flagsToClear);
75 
76 	static	uint32				AttributesToPageTableEntryFlags(
77 									uint32 attributes);
78 	static	uint32				PageTableEntryFlagsToAttributes(
79 									uint32 pageTableEntry);
80 	static	uint32				MemoryTypeToPageTableEntryFlags(
81 									uint32 memoryType);
82 
83 private:
84 			struct PhysicalPageSlotPool;
85 			friend struct PhysicalPageSlotPool;
86 
87 private:
88 	inline	int32				_GetInitialPoolCount();
89 
90 	static	void				_EarlyPreparePageTables(
91 									page_table_entry* pageTables,
92 									addr_t address, size_t size);
93 	static	status_t			_EarlyQuery(addr_t virtualAddress,
94 									phys_addr_t *_physicalAddress);
95 
96 private:
97 			uint32				fKernelPhysicalPageDirectory;
98 			page_directory_entry* fKernelVirtualPageDirectory;
99 
100 			ARMPhysicalPageMapper* fPhysicalPageMapper;
101 			TranslationMapPhysicalPageMapper* fKernelPhysicalPageMapper;
102 };
103 
104 
105 /*static*/ inline ARMPagingMethod32Bit*
106 ARMPagingMethod32Bit::Method()
107 {
108 	return static_cast<ARMPagingMethod32Bit*>(gARMPagingMethod);
109 }
110 
111 
112 /*static*/ inline page_table_entry
113 ARMPagingMethod32Bit::SetPageTableEntry(page_table_entry* entry,
114 	page_table_entry newEntry)
115 {
116 	return atomic_get_and_set((int32*)entry, newEntry);
117 }
118 
119 
120 /*static*/ inline page_table_entry
121 ARMPagingMethod32Bit::SetPageTableEntryFlags(page_table_entry* entry,
122 	uint32 flags)
123 {
124 	return atomic_or((int32*)entry, flags);
125 }
126 
127 
128 /*static*/ inline page_table_entry
129 ARMPagingMethod32Bit::TestAndSetPageTableEntry(page_table_entry* entry,
130 	page_table_entry newEntry, page_table_entry oldEntry)
131 {
132 	return atomic_test_and_set((int32*)entry, newEntry, oldEntry);
133 }
134 
135 
136 /*static*/ inline page_table_entry
137 ARMPagingMethod32Bit::ClearPageTableEntry(page_table_entry* entry)
138 {
139 	return SetPageTableEntry(entry, 0);
140 }
141 
142 
143 /*static*/ inline page_table_entry
144 ARMPagingMethod32Bit::ClearPageTableEntryFlags(page_table_entry* entry, uint32 flags)
145 {
146 	return atomic_and((int32*)entry, ~flags);
147 }
148 
149 
150 /*static*/ inline page_table_entry
151 ARMPagingMethod32Bit::SetAndClearPageTableEntryFlags(page_table_entry* entry, uint32 flagsToSet, uint32 flagsToClear)
152 {
153 	page_table_entry originalValue = *entry;
154 
155 	while (true) {
156 		page_table_entry oldEntry = atomic_test_and_set((int32*)entry,
157 			(originalValue & ~flagsToClear) | flagsToSet, originalValue);
158 		if (oldEntry == originalValue)
159 			break;
160 		originalValue = oldEntry;
161 	}
162 
163 	return originalValue;
164 }
165 
166 
167 /*static*/ inline uint32
168 ARMPagingMethod32Bit::AttributesToPageTableEntryFlags(uint32 attributes)
169 {
170 	int apFlags;
171 
172 	if ((attributes & B_READ_AREA) != 0) {
173 		// user accessible
174 		apFlags = ARM_MMU_L2_FLAG_AP1;
175 		if ((attributes & B_WRITE_AREA) == 0)
176 			apFlags |= ARM_MMU_L2_FLAG_AP2;
177 		else
178 			apFlags |= ARM_MMU_L2_FLAG_HAIKU_SWDBM;
179 	} else if ((attributes & B_KERNEL_WRITE_AREA) == 0) {
180 		// kernel ro
181 		apFlags = ARM_MMU_L2_FLAG_AP2;
182 	} else {
183 		// kernel rw
184 		apFlags = ARM_MMU_L2_FLAG_HAIKU_SWDBM;
185 	}
186 
187 	if (((attributes & B_KERNEL_EXECUTE_AREA) == 0) &&
188 			((attributes & B_EXECUTE_AREA) == 0)) {
189 		apFlags |= ARM_MMU_L2_FLAG_XN;
190 	}
191 
192 	if ((attributes & PAGE_ACCESSED) != 0)
193 		apFlags |= ARM_MMU_L2_FLAG_AP0;
194 
195 	if ((attributes & PAGE_MODIFIED) == 0)
196 		apFlags |= ARM_MMU_L2_FLAG_AP2;
197 
198 	return apFlags;
199 }
200 
201 
202 /*static*/ inline uint32
203 ARMPagingMethod32Bit::PageTableEntryFlagsToAttributes(uint32 pageTableEntry)
204 {
205 	uint32 attributes;
206 
207 	if ((pageTableEntry & ARM_MMU_L2_FLAG_HAIKU_SWDBM) != 0) {
208 		if ((pageTableEntry & ARM_MMU_L2_FLAG_AP1) != 0) {
209 			attributes = B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA;
210 		} else {
211 			attributes = B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA;
212 		}
213 	} else {
214 		if ((pageTableEntry & ARM_MMU_L2_FLAG_AP1) != 0)
215 			attributes = B_KERNEL_READ_AREA | B_READ_AREA;
216 		else
217 			attributes = B_KERNEL_READ_AREA;
218 	}
219 
220 	if ((pageTableEntry & ARM_MMU_L2_FLAG_AP0) != 0)
221 		attributes |= PAGE_ACCESSED;
222 
223 	if ((pageTableEntry & ARM_MMU_L2_FLAG_AP2) == 0)
224 		attributes |= PAGE_MODIFIED;
225 
226 	if ((pageTableEntry & ARM_MMU_L2_FLAG_XN) == 0) {
227 		if ((attributes & B_KERNEL_READ_AREA) != 0)
228 			attributes |= B_KERNEL_EXECUTE_AREA;
229 		if ((attributes & B_READ_AREA) != 0)
230 			attributes |= B_EXECUTE_AREA;
231 	}
232 
233 	return attributes;
234 }
235 
236 
237 /*static*/ inline uint32
238 ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags(uint32 memoryType)
239 {
240 	switch (memoryType) {
241 		case B_UNCACHED_MEMORY:
242 			// Strongly Ordered
243 			return 0;
244 		case B_WRITE_COMBINING_MEMORY:
245 			// Shareable Device Memory
246 			return ARM_MMU_L2_FLAG_B;
247 		case B_WRITE_THROUGH_MEMORY:
248 			// Outer and Inner Write-Through, no Write-Allocate
249 			return ARM_MMU_L2_FLAG_C;
250 		case B_WRITE_PROTECTED_MEMORY:
251 		case B_WRITE_BACK_MEMORY:
252 		default:
253 			// Outer and Inner Write-Back, no Write-Allocate
254 			return ARM_MMU_L2_FLAG_B | ARM_MMU_L2_FLAG_C;
255 	}
256 }
257 
258 
259 #endif	// KERNEL_ARCH_ARM_PAGING_32_BIT_ARM_PAGING_METHOD_32_BIT_H
260