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