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 
109  return MemoryContext::Success;
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
130  tlb_flush_all();
132 
133  // Disable caches.
136 
137  // Enable the MMU. This re-enables instruction and data cache too.
139  tlb_flush_all();
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
156  tlb_flush_all();
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
191  tlb_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
227  tlb_flush_all();
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 
275 {
276  return m_firstTable->access(virt, access, m_alloc);
277 }
278 
280  const bool tablesOnly)
281 {
282  return m_firstTable->releaseSection(range, m_alloc, tablesOnly);
283 }
284 
286 {
287  return m_firstTable->releaseRange(*range, m_alloc);
288 }
ARMPaging::activate
virtual Result activate(bool initializeMMU=false)
Activate the MemoryContext.
Definition: ARMPaging.cpp:198
ARMCacheV6::cleanInvalidate
virtual Result cleanInvalidate(Type type)
Clean and invalidate entire cache.
Definition: ARMCacheV6.cpp:41
isb
void isb()
Instruction Synchronisation Barrier (ARMv7 and above)
Definition: ARMCore.h:218
ARMControl::unset
void unset(SystemControlFlags flags)
Unset system control flags in CP15.
Definition: ARMControl.cpp:93
SplitAllocator::allocate
virtual Result allocate(Range &args)
Allocate physical memory.
Definition: SplitAllocator.cpp:35
ARMControl::AlignmentFaults
@ AlignmentFaults
Definition: ARMControl.h:91
Memory::Range
Memory range.
Definition: Memory.h:55
SplitAllocator.h
ARMControl::AccessPermissions
@ AccessPermissions
Definition: ARMControl.h:88
MemoryContext
Virtual memory abstract interface.
Definition: MemoryContext.h:42
ARMPaging::m_cache
Arch::Cache m_cache
Caching implementation.
Definition: ARMPaging.h:184
ARMFirstTable::map
MemoryContext::Result map(Address virt, Address phys, Memory::Access access, SplitAllocator *alloc)
Map a virtual address to a physical address.
Definition: ARMFirstTable.cpp:124
ARMFirstTable::translate
MemoryContext::Result translate(Address virt, Address *phys, SplitAllocator *alloc) const
Translate virtual address to physical address.
Definition: ARMFirstTable.cpp:200
MemoryBlock::set
static void * set(void *dest, int ch, unsigned count)
Fill memory with a constant byte.
Definition: MemoryBlock.cpp:25
ARMControl::write
void write(Register reg, u32 value)
Write register to the CP15.
Definition: ARMControl.cpp:52
ARMPaging::ARMPaging
ARMPaging(MemoryMap *map, SplitAllocator *alloc)
Constructor.
Definition: ARMPaging.cpp:28
mcr
#define mcr(coproc, opcode1, opcode2, reg, subReg, value)
Move to CoProcessor from ARM (MCR).
Definition: ARMCore.h:63
ARMControl::DataCache
@ DataCache
Definition: ARMControl.h:86
dsb
void dsb()
Data Synchronisation Barrier.
Definition: ARMCore.h:198
ARMPaging::releaseRange
virtual Result releaseRange(Memory::Range *range)
Release range of memory.
Definition: ARMPaging.cpp:285
Memory::Writable
@ Writable
Definition: Memory.h:42
ARMControl::TranslationTableCtrl
@ TranslationTableCtrl
Definition: ARMControl.h:63
PAGESIZE
#define PAGESIZE
ARM uses 4K pages.
Definition: ARMConstant.h:97
ARMPaging.h
Cache::Data
@ Data
Definition: Cache.h:56
ARMCore.h
tlb_flush_all
void tlb_flush_all()
Flush the entire Translation Lookaside Buffer.
Definition: ARMCore.h:161
ARMFirstTable
ARM first level page table.
Definition: ARMFirstTable.h:43
Memory::Device
@ Device
Definition: Memory.h:48
Address
unsigned long Address
A memory address.
Definition: Types.h:131
ARMFirstTable.h
ARMFirstTable::mapLarge
MemoryContext::Result mapLarge(Memory::Range range, SplitAllocator *alloc)
Map a contigous range of virtual memory to physical memory.
Definition: ARMFirstTable.cpp:158
ARMPaging::initialize
virtual Result initialize()
Initialize the MemoryContext.
Definition: ARMPaging.cpp:55
Allocator::Range::address
Address address
Starting address of the memory range.
Definition: Allocator.h:67
MemoryBlock.h
Allocator::Range::alignment
Size alignment
Alignment in bytes or ZERO for default alignment.
Definition: Allocator.h:69
ARMPaging::~ARMPaging
virtual ~ARMPaging()
Destructor.
Definition: ARMPaging.cpp:36
ARMPaging::m_firstTable
ARMFirstTable * m_firstTable
Pointer to the first level page table.
Definition: ARMPaging.h:175
ARMControl::MMUEnabled
@ MMUEnabled
Definition: ARMControl.h:84
Memory::Readable
@ Readable
Definition: Memory.h:41
Log.h
ARMPaging::m_kernelBaseAddr
Address m_kernelBaseAddr
Kernel base address.
Definition: ARMPaging.h:181
Allocator::Range::size
Size size
Amount of memory in bytes.
Definition: Allocator.h:68
SplitAllocator
Allocator which separates kernel mapped memory at virtual and physical addresses.
Definition: SplitAllocator.h:37
MegaByte
#define MegaByte(v)
Convert megabytes to bytes.
Definition: Macros.h:57
ARMControl::TranslationTable0
@ TranslationTable0
Definition: ARMControl.h:61
ARMPaging::lookup
virtual Result lookup(Address virt, Address *phys) const
Translate virtual address to physical address.
Definition: ARMPaging.cpp:269
ARMCacheV6::cleanInvalidateAddress
virtual Result cleanInvalidateAddress(Type type, Address addr)
Clean and invalidate one memory page.
Definition: ARMCacheV6.cpp:78
ARMControl
ARM System Control Coprocessor (CP15).
Definition: ARMControl.h:47
Allocator::Success
@ Success
Definition: Allocator.h:55
Memory::Range::phys
Address phys
Physical address.
Definition: Memory.h:58
MemoryContext::Result
Result
Result codes.
Definition: MemoryContext.h:49
MemoryMap::range
Memory::Range range(Region region) const
Get memory range for the given region.
Definition: MemoryMap.cpp:36
tlb_invalidate
#define tlb_invalidate(page)
Definition: ARMCore.h:167
ARMControl::BranchPrediction
@ BranchPrediction
Definition: ARMControl.h:89
u32
unsigned int u32
Unsigned 32-bit number.
Definition: Types.h:53
ARMFirstTable::access
MemoryContext::Result access(Address virt, Memory::Access *access, SplitAllocator *alloc) const
Get Access flags for a virtual address.
Definition: ARMFirstTable.cpp:221
MemoryContext::Success
@ Success
Definition: MemoryContext.h:51
MemoryMap
Describes virtual memory map layout.
Definition: MemoryMap.h:38
Size
unsigned int Size
Any sane size indicator cannot go negative.
Definition: Types.h:128
ARMPaging::access
virtual Result access(Address virt, Memory::Access *access) const
Get Access flags for a virtual address.
Definition: ARMPaging.cpp:274
ARMFirstTable::releaseRange
MemoryContext::Result releaseRange(const Memory::Range range, SplitAllocator *alloc)
Release range of memory.
Definition: ARMFirstTable.cpp:269
Memory::Access
Access
Memory access flags.
Definition: Memory.h:38
MemoryContext::OutOfMemory
@ OutOfMemory
Definition: MemoryContext.h:55
coreInfo
CoreInfo coreInfo
Local CoreInfo instance.
ARMFirstTable::releaseSection
MemoryContext::Result releaseSection(const Memory::Range range, SplitAllocator *alloc, const bool tablesOnly)
Release memory sections.
Definition: ARMFirstTable.cpp:295
ARMControl::DomainControl
@ DomainControl
Definition: ARMControl.h:60
Allocator::Range
Describes a range of memory.
Definition: Allocator.h:65
ARMPaging::m_firstTableAddr
Address m_firstTableAddr
Physical address of the first level page table.
Definition: ARMPaging.h:178
ARMPaging::map
virtual Result map(Address virt, Address phys, Memory::Access access)
Map a physical page to a virtual address.
Definition: ARMPaging.cpp:237
ARMPaging::releaseSection
virtual Result releaseSection(const Memory::Range &range, const bool tablesOnly=false)
Release memory sections.
Definition: ARMPaging.cpp:279
ARMControl::InstructionCache
@ InstructionCache
Definition: ARMControl.h:85
SplitAllocator::release
virtual Result release(const Address addr)
Release memory page.
Definition: SplitAllocator.cpp:89
ARMControl::DisablePageColoring
@ DisablePageColoring
Definition: ARMControl.h:104
ARMControl::set
void set(SystemControlFlags flags)
Set system control flags in CP15.
Definition: ARMControl.cpp:88
MemoryContext::m_current
static MemoryContext * m_current
The currently active MemoryContext.
Definition: MemoryContext.h:233
ARMPaging::enableMMU
Result enableMMU()
Enable the MMU.
Memory::Range::virt
Address virt
Virtual address.
Definition: Memory.h:57
ARMControl.h
CoreInfo.h
Cache::Unified
@ Unified
Definition: Cache.h:57
ARMControl::SystemControl
@ SystemControl
Definition: ARMControl.h:58
Memory::Range::size
Size size
Size in number of bytes.
Definition: Memory.h:59
Memory::Range::access
Access access
Page access flags.
Definition: Memory.h:60
ZERO
#define ZERO
Zero value.
Definition: Macros.h:43
ARMControl::TranslationTable1
@ TranslationTable1
Definition: ARMControl.h:62
ARMControl::ExtendedPaging
@ ExtendedPaging
Definition: ARMControl.h:87
ARMPaging::unmap
virtual Result unmap(Address virt)
Unmap a virtual address.
Definition: ARMPaging.cpp:251
ARMControl::DomainClient
@ DomainClient
Definition: ARMControl.h:113
MemoryMap::KernelData
@ KernelData
< Kernel program data from libexec, e.g.
Definition: MemoryMap.h:54
MemoryContext::m_alloc
SplitAllocator * m_alloc
Physical memory allocator.
Definition: MemoryContext.h:227
MemoryContext::m_map
MemoryMap * m_map
Virtual memory layout.
Definition: MemoryContext.h:230
ARMControl::read
u32 read(Register reg) const
Read a register from the CP15.
Definition: ARMControl.cpp:29
ARMFirstTable::unmap
MemoryContext::Result unmap(Address virt, SplitAllocator *alloc)
Remove virtual address mapping.
Definition: ARMFirstTable.cpp:180