FreeNOS
ARMPaging.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 <Log.h>
22#include "CoreInfo.h"
23#include "ARMCore.h"
24#include "ARMControl.h"
25#include "ARMPaging.h"
26#include "ARMFirstTable.h"
27
29 : MemoryContext(map, alloc)
30 , m_firstTable(0)
31 , m_firstTableAddr(0)
32 , m_kernelBaseAddr(coreInfo.memory.phys)
33{
34}
35
37{
38 if (m_firstTableAddr != 0)
39 {
40 for (Size i = 0; i < sizeof(ARMFirstTable); i += PAGESIZE)
42 }
43}
44
46 Address firstTableAddress,
47 Address kernelBaseAddress)
48 : MemoryContext(map, ZERO)
49 , m_firstTable((ARMFirstTable *) firstTableAddress)
50 , m_firstTableAddr(firstTableAddress)
51 , m_kernelBaseAddr(kernelBaseAddress)
52{
53}
54
56{
57 // Allocate first page table if needed
58 if (m_firstTable == 0)
59 {
60 Allocator::Range phys, virt;
61 phys.address = 0;
62 phys.size = sizeof(ARMFirstTable);
63 phys.alignment = sizeof(ARMFirstTable);
64
65 // Allocate page directory
66 if (m_alloc->allocate(phys, virt) != Allocator::Success)
67 {
69 }
70
73 }
74
75 // Initialize the page directory
77
78 // Map the kernel. The kernel has permanently mapped 1GB of
79 // physical memory. This 1GiB memory region starts at its physical
80 // base address offset which varies per core.
82 kernelRange.phys = m_kernelBaseAddr;
83 m_firstTable->mapLarge(kernelRange, m_alloc);
84
85#ifndef BCM2835
86 // Temporary stack is used for kernel initialization code
87 // and for SMP the temporary stack is shared between cores.
88 // This is needed in order to perform early-MMU enable.
89 m_firstTable->unmap(TMPSTACKADDR, m_alloc);
90
91 const Memory::Range tmpStackRange = {
92 TMPSTACKADDR, TMPSTACKADDR, MegaByte(1), Memory::Readable|Memory::Writable
93 };
94 m_firstTable->mapLarge(tmpStackRange, m_alloc);
95#endif /* BCM2835 */
96
97 // Unmap I/O zone
98 for (Size i = 0; i < IO_SIZE; i += MegaByte(1))
99 m_firstTable->unmap(IO_BASE + i, m_alloc);
100
101 // Map the I/O zone as Device / Uncached memory.
102 Memory::Range io;
103 io.phys = IO_BASE;
104 io.virt = IO_BASE;
105 io.size = IO_SIZE;
108
110}
111
112#ifdef ARMV6
114{
115 ARMControl ctrl;
116
117 // Program first level table. Enable L2 cache for page walking.
121
122 // Set Control flags
128
129 // Flush TLB's and caches
132
133 // Disable caches.
136
137 // Enable the MMU. This re-enables instruction and data cache too.
140
141 // Reactivate both caches and branch prediction
145
146 return Success;
147}
148
149#elif defined(ARMV7)
150
152{
153 ARMControl ctrl;
154
155 // Flush TLB's
157 dsb();
158 isb();
159
160 // Enable branch prediction
162
163 // Program first level table
165 (1 << 3) | // outer write-back, write-allocate
166 (1 << 6) // inner write-back, write-allocate
167 ));
170 dsb();
171 isb();
172
173 // Set as client for all domains
174 ctrl.write(ARMControl::DomainControl, 0x55555555);
175
176 // Enable the MMU.
177 u32 nControl = ctrl.read(ARMControl::SystemControl);
178
179 // Raise all caching, MMU and branch prediction flags.
180 nControl |= (1 << 11) | (1 << 2) | (1 << 12) | (1 << 0) | (1 << 5);
181
182 // Write back to set.
183 ctrl.write(ARMControl::SystemControl, nControl);
184 isb();
185
186 // Need to enable alignment faults separately of the MMU,
187 // otherwise QEMU will hard reset the CPU
189
190 // Flush all
192 dsb();
193 isb();
194 return Success;
195}
196#endif /* ARMV7 */
197
199{
200 ARMControl ctrl;
201
202 // Do we need to (re)enable the MMU?
203 if (initializeMMU)
204 {
205 enableMMU();
206 }
207 // MMU already enabled, we only need to change first level table and flush caches.
208 else
209 {
210#ifdef ARMV6
211 mcr(p15, 0, 0, c7, c5, 0); // flush entire instruction cache
212 mcr(p15, 0, 0, c7, c10, 0); // flush entire data cache
213 mcr(p15, 0, 0, c7, c7, 0); // flush entire cache
214 mcr(p15, 0, 5, c7, c10, 0); // data memory barrier
215 mcr(p15, 0, 4, c7, c10, 0); // memory sync barrier
216#else
218#endif /* ARMV6 */
219
220 // Switch first page table and re-enable L1 caching
222 (1 << 3) | /* outer write-back, write-allocate */
223 (1 << 6) /* inner write-back, write-allocate */
224 ));
225
226 // Flush TLB caches
228
229 // Synchronize execution stream
230 isb();
231 }
232 // Done. Update currently active context pointer
233 m_current = this;
234 return Success;
235}
236
238{
239 // Modify page tables
240 Result r = m_firstTable->map(virt, phys, acc, m_alloc);
241
242 // Flush the TLB to refresh the mapping
243 if (m_current == this)
244 tlb_invalidate(virt);
245
246 // Synchronize execution stream.
247 isb();
248 return r;
249}
250
252{
253 // Clean the given data page in cache
254 if (m_current == this)
256
257 // Modify page tables
258 Result r = m_firstTable->unmap(virt, m_alloc);
259
260 // Flush TLB to refresh the mapping
261 if (m_current == this)
262 tlb_invalidate(virt);
263
264 // Synchronize execution stream
265 isb();
266 return r;
267}
268
270{
271 return m_firstTable->translate(virt, phys, m_alloc);
272}
273
278
280 const bool tablesOnly)
281{
282 return m_firstTable->releaseSection(range, m_alloc, tablesOnly);
283}
284
#define isb()
Instruction Synchronisation Barrier (ARMv7 and above)
#define dsb(type)
Data Memory Barrier.
virtual Result cleanInvalidateAddress(Type type, Address addr)
Clean and invalidate one memory page.
virtual Result cleanInvalidate(Type type)
Clean and invalidate entire cache.
ARM System Control Coprocessor (CP15).
Definition ARMControl.h:48
void set(SystemControlFlags flags)
Set system control flags in CP15.
void write(Register reg, u32 value)
Write register to the CP15.
u32 read(Register reg) const
Read a register from the CP15.
@ DisablePageColoring
Definition ARMControl.h:104
@ TranslationTable0
Definition ARMControl.h:61
@ TranslationTable1
Definition ARMControl.h:62
@ TranslationTableCtrl
Definition ARMControl.h:63
void unset(SystemControlFlags flags)
Unset system control flags in CP15.
@ AccessPermissions
Definition ARMControl.h:88
@ BranchPrediction
Definition ARMControl.h:89
@ AlignmentFaults
Definition ARMControl.h:91
@ InstructionCache
Definition ARMControl.h:85
ARM first level page table.
MemoryContext::Result unmap(Address virt, SplitAllocator *alloc)
Remove virtual address mapping.
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.
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.
Address m_firstTableAddr
Physical address of the first level page table.
Definition ARMPaging.h:178
virtual Result releaseRange(Memory::Range *range)
Release range of memory.
virtual Result activate(bool initializeMMU=false)
Activate the MemoryContext.
Result enableMMU()
Enable the MMU.
Arch::Cache m_cache
Caching implementation.
Definition ARMPaging.h:184
virtual Result lookup(Address virt, Address *phys) const
Translate virtual address to physical address.
ARMPaging(MemoryMap *map, SplitAllocator *alloc)
Constructor.
Definition ARMPaging.cpp:28
Address m_kernelBaseAddr
Kernel base address.
Definition ARMPaging.h:181
virtual ~ARMPaging()
Destructor.
Definition ARMPaging.cpp:36
virtual Result initialize()
Initialize the MemoryContext.
Definition ARMPaging.cpp:55
virtual Result unmap(Address virt)
Unmap a virtual address.
ARMFirstTable * m_firstTable
Pointer to the first level page table.
Definition ARMPaging.h:175
virtual Result releaseSection(const Memory::Range &range, const bool tablesOnly=false)
Release memory sections.
virtual Result map(Address virt, Address phys, Memory::Access access)
Map a physical page to a virtual address.
virtual Result access(Address virt, Memory::Access *access) const
Get Access flags for a virtual address.
@ Unified
Definition Cache.h:57
@ Data
Definition Cache.h:56
static void * set(void *dest, int ch, unsigned count)
Fill memory with a constant byte.
Virtual memory abstract interface.
Result
Result codes.
MemoryMap * m_map
Virtual memory layout.
SplitAllocator * m_alloc
Physical memory allocator.
static MemoryContext * m_current
The currently active MemoryContext.
Describes virtual memory map layout.
Definition MemoryMap.h:39
@ KernelData
< Kernel program data from libexec, e.g.
Definition MemoryMap.h:54
Memory::Range range(Region region) const
Get memory range for the given region.
Definition MemoryMap.cpp:36
Allocator which separates kernel mapped memory at virtual and physical addresses.
virtual Result allocate(Range &args)
Allocate physical memory.
virtual Result release(const Address addr)
Release memory page.
#define PAGESIZE
ARM uses 4K pages.
Definition ARMConstant.h:97
#define tlb_invalidate(page)
Definition ARMCore.h:167
#define mcr(coproc, opcode1, opcode2, reg, subReg, value)
Move to CoProcessor from ARM (MCR).
Definition ARMCore.h:63
#define tlb_flush_all()
Flushes all Translation Lookaside Buffers (TLB).
Definition IntelCore.h:98
CoreInfo coreInfo
Local CoreInfo instance.
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
@ Readable
Definition Memory.h:41
@ Device
Definition Memory.h:48
@ 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