FreeNOS
ARMFirstTable.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <FreeNOS/System.h>
19#include <SplitAllocator.h>
20#include <MemoryBlock.h>
21#include "ARMCore.h"
22#include "ARMConstant.h"
23#include "ARMFirstTable.h"
24
32#define PAGE1_NONE 0
33#define PAGE1_TABLE (1 << 0)
34#define PAGE1_SECTION (1 << 1)
35
55#define PAGE1_UNCACHED (PAGE1_TEX)
56
58#define PAGE1_CACHE_WRITEBACK (PAGE1_TEX | PAGE1_CACHE | PAGE1_BUFFER)
59
61#define PAGE1_CACHE_WRITETHROUGH (PAGE1_CACHE)
62
64#define PAGE1_DEVICE_PRIV ((1 << 13))
65
67#define PAGE1_DEVICE_SHARED (PAGE1_BUFFER)
68
69#define PAGE1_TEX (1 << 12)
70#define PAGE1_CACHE (1 << 3)
71#define PAGE1_BUFFER (1 << 2)
72#define PAGE1_SHARED (1 << 16)
73
84#define PAGE1_NOEXEC (1 << 4)
85
86/* Read-only flag */
87#ifdef ARMV7
88#define PAGE1_APX (1 << 15)
89#else
90#define PAGE1_APX (1 << 9)
91#endif
92
93/* User access permissions flag */
94#define PAGE1_AP_USER (1 << 11)
95
96/* System access permissions flag */
97#define PAGE1_AP_SYS (1 << 10)
98
110#define DIRENTRY(vaddr) \
111 ((vaddr) >> DIRSHIFT)
112
114{
115 u32 entry = m_tables[ DIRENTRY(virt) ];
116
117 // Check if the page table is present.
118 if (!(entry & PAGE1_TABLE))
119 return ZERO;
120 else
121 return (ARMSecondTable *) alloc->toVirtual(entry & PAGEMASK);
122}
123
125 Address phys,
126 Memory::Access access,
127 SplitAllocator *alloc)
128{
129 ARMSecondTable *table = getSecondTable(virt, alloc);
130 Arch::Cache cache;
131 Allocator::Range allocPhys, allocVirt;
132
133 // Check if the page table is present.
134 if (!table)
135 {
136 // Reject if already mapped as a (super)section
137 if (m_tables[ DIRENTRY(virt) ] & PAGE1_SECTION)
139
140 // Allocate a new page table
141 allocPhys.address = 0;
142 allocPhys.size = sizeof(ARMSecondTable);
143 allocPhys.alignment = PAGESIZE;
144
145 if (alloc->allocate(allocPhys, allocVirt) != Allocator::Success)
147
148 MemoryBlock::set((void *)allocVirt.address, 0, PAGESIZE);
149
150 // Assign to the page directory. Do not assign permission flags (only for direct sections).
151 m_tables[ DIRENTRY(virt) ] = allocPhys.address | PAGE1_TABLE;
152 cache.cleanData(&m_tables[DIRENTRY(virt)]);
153 table = getSecondTable(virt, alloc);
154 }
155 return table->map(virt, phys, access);
156}
157
159 SplitAllocator *alloc)
160{
161 Arch::Cache cache;
162
163 if (range.size & 0xfffff)
165
166 if ((range.phys & ~PAGEMASK) || (range.virt & ~PAGEMASK))
168
169 for (Size i = 0; i < range.size; i += MegaByte(1))
170 {
171 if (m_tables[ DIRENTRY(range.virt + i) ] & (PAGE1_TABLE | PAGE1_SECTION))
173
174 m_tables[ DIRENTRY(range.virt + i) ] = (range.phys + i) | PAGE1_SECTION | flags(range.access);
175 cache.cleanData(&m_tables[DIRENTRY(range.virt + i)]);
176 }
178}
179
181{
182 ARMSecondTable *table = getSecondTable(virt, alloc);
183 Arch::Cache cache;
184
185 if (!table)
186 {
187 if (m_tables[DIRENTRY(virt)] & PAGE1_SECTION)
188 {
190 cache.cleanData(&m_tables[DIRENTRY(virt)]);
192 }
193 else
195 }
196 else
197 return table->unmap(virt);
198}
199
201 Address *phys,
202 SplitAllocator *alloc) const
203{
204 ARMSecondTable *table = getSecondTable(virt, alloc);
205 if (!table)
206 {
207 if (m_tables[DIRENTRY(virt)] & PAGE1_SECTION)
208 {
209 const Address offsetInSection = virt % MegaByte(1);
210
211 *phys = (m_tables[DIRENTRY(virt)] & SECTIONMASK) +
212 ((offsetInSection / PAGESIZE) * PAGESIZE);
214 }
216 }
217 else
218 return table->translate(virt, phys);
219}
220
222 Memory::Access *access,
223 SplitAllocator *alloc) const
224{
225 ARMSecondTable *table = getSecondTable(virt, alloc);
226 if (!table)
228 else
229 return table->access(virt, access);
230}
231
233{
234 u32 f = PAGE1_AP_SYS;
235
236 // Permissions
238 if ((access & Memory::User)) f |= PAGE1_AP_USER;
239 if (!(access & Memory::Writable)) f |= PAGE1_APX;
240
241 // Caching
243 else if (access & Memory::Uncached) f |= PAGE1_UNCACHED;
244 else f |= PAGE1_CACHE_WRITEBACK;
245
246 return f;
247}
248
250 const Address phys)
251{
252 // Some pages that are part of the boot core's memory region
253 // are mapped on secondary cores. They can't be released there.
254 const Address allocBase = alloc->base();
255 const Size allocSize = alloc->size();
256 if (phys < allocBase || phys > allocBase + allocSize)
257 {
258 return;
259 }
260
261 // Note that some pages may have double mappings.
262 // Avoid attempting to release the same page twice or more.
263 if (alloc->isAllocated(phys))
264 {
265 alloc->release(phys);
266 }
267}
268
270 SplitAllocator *alloc)
271{
272 Address phys;
273
274 // Walk the full range of memory specified
275 for (Size addr = range.virt; addr < range.virt + range.size; addr += PAGESIZE)
276 {
277 ARMSecondTable *table = getSecondTable(addr, alloc);
278 if (table == ZERO)
279 {
281 }
282
283 if (table->translate(addr, &phys) != MemoryContext::Success)
284 {
286 }
287
288 releasePhysical(alloc, phys);
289 table->unmap(addr);
290 }
291
293}
294
296 SplitAllocator *alloc,
297 const bool tablesOnly)
298{
299 Address phys;
300
301 // Input must be aligned to section address
302 if (range.virt & ~SECTIONMASK)
303 {
305 }
306
307 // Walk the page directory
308 for (Size addr = range.virt; addr < range.virt + range.size; addr += MegaByte(1))
309 {
310 ARMSecondTable *table = getSecondTable(addr, alloc);
311 if (!table)
312 {
313 continue;
314 }
315
316 // Release mapped pages, if requested
317 if (!tablesOnly)
318 {
319 for (Size i = 0; i < MegaByte(1); i += PAGESIZE)
320 {
321 if (table->translate(i, &phys) == MemoryContext::Success)
322 {
323 releasePhysical(alloc, phys);
324 }
325 }
326 }
327 // Release page table
328 alloc->release(m_tables[ DIRENTRY(addr) ] & PAGEMASK);
329 m_tables[ DIRENTRY(addr) ] = 0;
330 }
331
333}
#define PAGE1_AP_USER
#define PAGE1_NONE
#define DIRENTRY(vaddr)
Entry inside the page directory of a given virtual address.
#define PAGE1_APX
#define PAGE1_CACHE_WRITEBACK
Outer and Inner Write-Back.
#define PAGE1_TABLE
#define PAGE1_UNCACHED
Disable all caching.
#define PAGE1_NOEXEC
No-execution flag.
#define PAGE1_AP_SYS
#define PAGE1_DEVICE_SHARED
Memory Mapped Device (Shared)
#define PAGE1_SECTION
u32 entry[]
Definition IntelACPI.h:1
u32 flags
Definition IntelACPI.h:3
ARMv6 cache management implementation.
Definition ARMCacheV6.h:43
MemoryContext::Result unmap(Address virt, SplitAllocator *alloc)
Remove virtual address mapping.
ARMSecondTable * getSecondTable(Address virt, SplitAllocator *alloc) const
Retrieve second level page table.
MemoryContext::Result map(Address virt, Address phys, Memory::Access access, SplitAllocator *alloc)
Map a virtual address to a physical address.
MemoryContext::Result releaseSection(const Memory::Range range, SplitAllocator *alloc, const bool tablesOnly)
Release memory sections.
MemoryContext::Result translate(Address virt, Address *phys, SplitAllocator *alloc) const
Translate virtual address to physical address.
MemoryContext::Result releaseRange(const Memory::Range range, SplitAllocator *alloc)
Release range of memory.
u32 flags(Memory::Access access) const
Convert Memory::Access to first level page table flags.
MemoryContext::Result access(Address virt, Memory::Access *access, SplitAllocator *alloc) const
Get Access flags for a virtual address.
MemoryContext::Result mapLarge(Memory::Range range, SplitAllocator *alloc)
Map a contigous range of virtual memory to physical memory.
void releasePhysical(SplitAllocator *alloc, const Address phys)
Release a single physical page.
u32 m_tables[4096]
Array of page table entries.
ARM second level page table implementation.
MemoryContext::Result map(Address virt, Address phys, Memory::Access)
Map a virtual address to a physical address.
MemoryContext::Result access(Address virt, Memory::Access *access) const
Get Access flags for a virtual address.
MemoryContext::Result translate(Address virt, Address *phys) const
Translate virtual address to physical address.
MemoryContext::Result unmap(Address virt)
Remove virtual address mapping.
Address base() const
Get memory base address for allocations.
Definition Allocator.cpp:69
virtual Size size() const
Get memory size.
Definition Allocator.cpp:64
virtual Result cleanData(Address addr)
Clean one data page.
Definition Cache.cpp:20
static void * set(void *dest, int ch, unsigned count)
Fill memory with a constant byte.
Result
Result codes.
Allocator which separates kernel mapped memory at virtual and physical addresses.
virtual Result allocate(Range &args)
Allocate physical memory.
bool isAllocated(const Address page) const
Check if a physical page is allocated.
Address toVirtual(const Address phys) const
Convert Address to virtual pointer.
virtual Result release(const Address addr)
Release memory page.
#define PAGESIZE
ARM uses 4K pages.
Definition ARMConstant.h:97
#define PAGEMASK
Mask to find the page.
#define SECTIONMASK
Mask for large 1MiB section mappings.
unsigned int u32
Unsigned 32-bit number.
Definition Types.h:53
unsigned long Address
A memory address.
Definition Types.h:131
#define MegaByte(v)
Convert megabytes to bytes.
Definition Macros.h:57
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define ZERO
Zero value.
Definition Macros.h:43
Access
Memory access flags.
Definition Memory.h:39
@ Executable
Definition Memory.h:43
@ User
Definition Memory.h:44
@ Device
Definition Memory.h:48
@ Uncached
Definition Memory.h:45
@ Writable
Definition Memory.h:42
Describes a range of memory.
Definition Allocator.h:66
Size alignment
Alignment in bytes or ZERO for default alignment.
Definition Allocator.h:69
Address address
Starting address of the memory range.
Definition Allocator.h:67
Size size
Amount of memory in bytes.
Definition Allocator.h:68
Memory range.
Definition Memory.h:56
Size size
Size in number of bytes.
Definition Memory.h:59
Address phys
Physical address.
Definition Memory.h:58
Address virt
Virtual address.
Definition Memory.h:57
Access access
Page access flags.
Definition Memory.h:60