FreeNOS
ARM64Paging.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 Ivan Tan
3 * Copyright (C) 2015 Niek Linnenbank
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <FreeNOS/System.h>
20#include <SplitAllocator.h>
21#include <MemoryBlock.h>
22#include <Log.h>
23#include "CoreInfo.h"
24#include "ARM64Paging.h"
25#include "ARM64FirstTable.h"
26#include "ARM64Control.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(ARM64FirstTable); i += PAGESIZE)
42 }
43}
44
46 Address firstTableAddress,
47 Address kernelBaseAddress)
48 : MemoryContext(map, ZERO)
49 , m_firstTable((ARM64FirstTable *) firstTableAddress)
50 , m_firstTableAddr(firstTableAddress)
51 , m_kernelBaseAddr(kernelBaseAddress)
52{
53}
54
56{
57 phys.address = 0;
58 phys.size = sizeof(ARM64FirstTable);
59 phys.alignment = PAGESIZE;
60
61 // Allocate page directory
62 if (m_alloc->allocate(phys, virt) != Allocator::Success)
63 {
65 }
66
68}
69
71{
72 // Allocate first page table if needed
73 if (!m_firstTable) {
74 Allocator::Range phys, virt;
75 // Allocate page directory
76 if (allocPageTable(phys, virt) != MemoryContext::Success)
77 {
79 }
82 }
83
84 // Initialize the page directory
87
88 // Map the kernel. The kernel has permanently mapped 1GB of
89 // physical memory. This 1GiB memory region starts at its physical
90 // base address offset which varies per core.
92 kernelRange.phys = m_kernelBaseAddr;
93 m_firstTable->mapLarge(kernelRange, m_alloc);
94
95 // Temporary stack is used for kernel initialization code
96 // and for SMP the temporary stack is shared between cores.
97 // This is needed in order to perform early-MMU enable.
98 m_firstTable->unmap(TMPSTACKADDR, m_alloc);
99 const Memory::Range tmpStackRange = {
100 TMPSTACKADDR, TMPSTACKADDR, MegaByte(2), Memory::Readable|Memory::Writable
101 };
102 m_firstTable->mapLarge(tmpStackRange, m_alloc);
103
104 // Unmap I/O zone
105 for (Size i = 0; i < IO_SIZE; i += MegaByte(2))
106 m_firstTable->unmap(IO_BASE + i, m_alloc);
107
108 // Map the I/O zone as Device / Uncached memory.
109 Memory::Range io;
110 io.phys = IO_BASE;
111 io.virt = IO_BASE;
112 io.size = IO_SIZE;
115
117}
118
120{
121 u64 r, b, level;
122
123 level = 25LL;
124
126 b = PA_RANGE(r);
127 if(TGRAN4(r)/*4k*/ || b<1/*36 bits*/) {
129 }
130
131 // first, set Memory Attributes array, indexed by PT_MEM, PT_DEV, PT_NC in our example
135
137
138 // next, specify mapping characteristics in translate control register
139 r= (0b00LL << 37) | // TBI=0, no tagging
140 (b << 32) | // IPS=autodetected
141 (0b10LL << 30) | // TG1=4k
142 (0b11LL << 28) | // SH1=3 inner
143 (0b00LL << 26) | // ORGN1=1 write back
144 (0b00LL << 24) | // IRGN1=1 write back
145 (0b0LL << 23) | // EPD1 enable higher half
146 (level << 16) | // T1SZ=25, 3 levels (512G); 34, 2 levels (1G) FIXME: is it necessary?
147 (0b00LL << 14) | // TG0=4k
148 (0b11LL << 12) | // SH0=3 inner
149 (0b00LL << 10) | // ORGN0=1 write back
150 (0b00LL << 8) | // IRGN0=1 write back
151 (0b0LL << 7) | // EPD0 enable lower half
152 (level << 0); // T0SZ=25, 3 levels (512G); 34, 2 levels (1G)
154
155
156 // tell the MMU where our translation tables are. TTBR_CNP bit not documented, but required
157 u64 tbl = m_firstTableAddr;
158 tbl += 0x1UL;
159
161 //ARM64Control::write(ARM64Control::TranslationTable1, tbl);
162
163 // finally, toggle some bits in system control register to enable page translation
164 dsb(ish);
165 isb();
167 r |= 0xC00800; // set mandatory reserved bits
168 r &= ~(SystemControlFlags::EE | // clear EE, little endian translation tables
169 SystemControlFlags::E0E | // clear E0E
170 SystemControlFlags::WXN | // clear WXN
171 SystemControlFlags::InstrCache | // clear I, no instruction cache
172 SystemControlFlags::SA0 | // clear SA0
173 SystemControlFlags::SA | // clear SA
174 SystemControlFlags::Stage1Cache | // clear C, no cache at all
175 SystemControlFlags::AlignCheckEnabled);// clear A, no aligment check
176 r |= SystemControlFlags::MMUEnabled; // set M, enable MMU
178 isb();
179
181}
183{
184 // Do we need to (re)enable the MMU?
185 if (initializeMMU)
186 {
187 enableMMU();
188 } else {
189 //m_cache.cleanInvalidate(Cache::Unified);
190
191 u64 tbl = m_firstTableAddr;
192 tbl += 0x1UL;
194
195 // Flush TLB caches
196 //tlb_flush_all();
197 //FIXME: check it again
198 asm volatile ("dsb ishst\ntlbi vmalle1is\n");
199
200 // Synchronize execution stream
201 dsb(ish);
202 isb();
203 }
204
205 // Done. Update currently active context pointer
206 m_current = this;
208}
209
211{
212 // Modify page tables
213 Result r = m_firstTable->map(virt, phys, acc, m_alloc);
214
215 // Flush the TLB to refresh the mapping
216 if (m_current == this)
217 tlb_invalidate(virt);
218
219 // Synchronize execution stream.
220 isb();
221 return r;
222}
223
225{
226 // Modify page tables
227 Result r = m_firstTable->unmap(virt, m_alloc);
228 // Flush the TLB to refresh the mapping
229 if (m_current == this)
230 tlb_invalidate(virt);
231 isb();
232 return r;
233}
234
236{
237 return m_firstTable->translate(virt, phys, m_alloc);
238}
239
244
246 const bool tablesOnly)
247{
248 return m_firstTable->releaseSection(range, m_alloc, tablesOnly);
249}
250
#define isb()
Instruction Synchronisation Barrier (ARMv7 and above)
#define dsb(type)
Data Memory Barrier.
#define TGRAN4(r)
#define PA_RANGE(r)
#define MAIR_FIELD(val, idx)
Definition ARM64Paging.h:34
#define MEM_ATTR_DEV
Definition ARM64Paging.h:32
#define MEM_ATTR_NORMAL
Definition ARM64Paging.h:31
#define MEM_ATTR_NC
Definition ARM64Paging.h:33
ARM64 first level page table.
MemoryContext::Result translate(Address virt, Address *phys, SplitAllocator *alloc) const
Translate virtual address to physical address.
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 access(Address virt, Memory::Access *access, SplitAllocator *alloc) const
Get Access flags for a virtual address.
static void initialize(ARM64FirstTable *firstTable)
MemoryContext::Result releaseRange(const Memory::Range range, SplitAllocator *alloc)
Release range of memory.
MemoryContext::Result releaseSection(const Memory::Range range, SplitAllocator *alloc, const bool tablesOnly)
Release memory sections.
MemoryContext::Result mapLarge(Memory::Range range, SplitAllocator *alloc)
Map a contigous range of virtual memory to physical memory.
Address m_kernelBaseAddr
Kernel base address.
virtual Result lookup(Address virt, Address *phys) const
Translate virtual address to physical address.
ARM64FirstTable * m_firstTable
Pointer to the first level page table.
ARM64Paging(MemoryMap *map, SplitAllocator *alloc)
Constructor.
virtual ~ARM64Paging()
Destructor.
Address m_firstTableAddr
Physical address of the first level page table.
virtual Result unmap(Address virt)
Unmap a virtual address.
virtual Result releaseSection(const Memory::Range &range, const bool tablesOnly=false)
Release memory sections.
MemoryContext::Result allocPageTable(Allocator::Range &phys, Allocator::Range &virt)
virtual Result activate(bool initializeMMU=false)
Activate the MemoryContext.
virtual Result releaseRange(Memory::Range *range)
Release range of memory.
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.
virtual Result initialize()
Initialize the MemoryContext.
Result enableMMU()
Enable the MMU.
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
CoreInfo coreInfo
Local CoreInfo instance.
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
unsigned long long u64
Unsigned 64-bit number.
Definition Types.h:50
u64 read(Register reg)
Read a register from the CP15.
void write(Register reg, u64 value)
Write register to the CP15.
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