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
17class TranslationMapPhysicalPageMapper;
18class ARMPhysicalPageMapper;
19
20
21class ARMPagingMethod32Bit : public ARMPagingMethod {
22public:
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
83private:
84			struct PhysicalPageSlotPool;
85			friend struct PhysicalPageSlotPool;
86
87private:
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
96private:
97			uint32				fKernelPhysicalPageDirectory;
98			page_directory_entry* fKernelVirtualPageDirectory;
99
100			ARMPhysicalPageMapper* fPhysicalPageMapper;
101			TranslationMapPhysicalPageMapper* fKernelPhysicalPageMapper;
102};
103
104
105/*static*/ inline ARMPagingMethod32Bit*
106ARMPagingMethod32Bit::Method()
107{
108	return static_cast<ARMPagingMethod32Bit*>(gARMPagingMethod);
109}
110
111
112/*static*/ inline page_table_entry
113ARMPagingMethod32Bit::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
121ARMPagingMethod32Bit::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
129ARMPagingMethod32Bit::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
137ARMPagingMethod32Bit::ClearPageTableEntry(page_table_entry* entry)
138{
139	return SetPageTableEntry(entry, 0);
140}
141
142
143/*static*/ inline page_table_entry
144ARMPagingMethod32Bit::ClearPageTableEntryFlags(page_table_entry* entry, uint32 flags)
145{
146	return atomic_and((int32*)entry, ~flags);
147}
148
149
150/*static*/ inline page_table_entry
151ARMPagingMethod32Bit::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
168ARMPagingMethod32Bit::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
203ARMPagingMethod32Bit::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
238ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags(uint32 memoryType)
239{
240	switch (memoryType) {
241		case B_MTR_UC:
242			// Strongly Ordered
243			return 0;
244		case B_MTR_WC:
245			// Shareable Device Memory
246			return ARM_MMU_L2_FLAG_B;
247		case B_MTR_WT:
248			// Outer and Inner Write-Through, no Write-Allocate
249			return ARM_MMU_L2_FLAG_C;
250		case B_MTR_WP:
251		case B_MTR_WB:
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