1#include "VirtualAddressSpace.h"
2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/panic.h"
4#include "pedigree/kernel/processor/Processor.h"
8#include "PhysicalMemoryManager.h"
10extern "C" char armv7_boot_l1;
13constexpr uint32_t PageTable = 1;
14constexpr uint32_t Section = 2;
15constexpr uint32_t SmallPage = 2;
16constexpr uint32_t AddressMask = 0xfffff000;
17constexpr uint32_t TableMask = 0xfffffc00;
19uint32_t* tableAt(physical_uintptr_t physical) {
20 return reinterpret_cast<uint32_t*
>(ARMV7_DIRECT_MAP_BASE + physical);
23uint32_t* shadowAt(uint32_t* table) {
32 return Armv7VirtualAddressSpace::m_KernelSpace;
37 if (!space || !space->root()) {
44Armv7VirtualAddressSpace::Armv7VirtualAddressSpace(
bool kernel)
46 reinterpret_cast<void*>(kernel ? KERNEL_VIRTUAL_HEAP : USERSPACE_VIRTUAL_HEAP)),
47 m_Root(kernel ? reinterpret_cast<uintptr_t>(&armv7_boot_l1)
49 m_StackTop(kernel ? KERNEL_VIRTUAL_STACK : USERSPACE_VIRTUAL_STACK) {
50 if (!kernel && m_Root) {
51 memset(tableAt(m_Root), 0, 2 * PAGE_SIZE);
55Armv7VirtualAddressSpace::~Armv7VirtualAddressSpace() {
56 if (
this != &m_KernelSpace && m_Root) {
58 Armv7PhysicalMemoryManager::instance().
freePage(m_Root);
59 Armv7PhysicalMemoryManager::instance().
freePage(m_Root + PAGE_SIZE);
67uint32_t* Armv7VirtualAddressSpace::findExistingEntry(uintptr_t address,
bool* isSection)
const {
68 const physical_uintptr_t root = address >= ARMV7_DIRECT_MAP_BASE ? m_KernelSpace.m_Root : m_Root;
69 uint32_t* first = &tableAt(root)[address >> 20];
71 *isSection = (*first & 3) == Section;
73 if ((*first & 3) != PageTable) {
76 return &tableAt(*first & TableMask)[(address >> 12) & 255];
79uint32_t* Armv7VirtualAddressSpace::findEntry(uintptr_t address,
bool create,
size_t* newTables) {
80 const physical_uintptr_t root = address >= ARMV7_DIRECT_MAP_BASE ? m_KernelSpace.m_Root : m_Root;
81 uint32_t* first = &tableAt(root)[address >> 20];
82 if (!*first && create) {
83 physical_uintptr_t page = Armv7PhysicalMemoryManager::instance().tryAllocatePage();
87 memset(tableAt(page), 0, PAGE_SIZE);
88 *first = page | PageTable;
93 if ((*first & 3) != PageTable) {
96 return &tableAt(*first & TableMask)[(address >> 12) & 255];
99uint32_t Armv7VirtualAddressSpace::pageDescriptor(physical_uintptr_t physical,
size_t flags) {
101 uint32_t entry = (physical & AddressMask) | SmallPage | (1U << 4);
122 const uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
125 bool section =
false;
126 uint32_t* entry = owner.findExistingEntry(value, §ion);
127 if (!entry || !*entry) {
133 const unsigned int index = (value >> 12) & 255;
134 return !(shadowAt(entry - index)[index] &
Swapped);
138 const uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
139 if ((value & (PAGE_SIZE - 1)) || (physical & (PAGE_SIZE - 1)) ||
140 (value < ARMV7_DIRECT_MAP_BASE && (flags &
KernelMode))) {
145 uint32_t* entry = owner.findEntry(value,
true);
146 if (!entry || *entry) {
149 shadowAt(entry - ((value >> 12) & 255))[(value >> 12) & 255] = flags;
150 *entry = pageDescriptor(physical, flags);
155bool Armv7VirtualAddressSpace::tryMapUserPage(physical_uintptr_t physical,
void* address,
156 size_t flags,
size_t* committedTablePages) {
157 if (committedTablePages) {
158 *committedTablePages = 0;
160 const uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
161 if ((flags &
KernelMode) || value >= ARMV7_DIRECT_MAP_BASE || (value & (PAGE_SIZE - 1)) ||
162 (physical & (PAGE_SIZE - 1))) {
166 size_t newTables = 0;
167 uint32_t* entry = findEntry(value,
true, &newTables);
168 if (!entry || *entry) {
171 const unsigned int index = (value >> 12) & 255;
172 shadowAt(entry - index)[index] = flags;
173 *entry = pageDescriptor(physical, flags);
175 if (committedTablePages) {
176 *committedTablePages = newTables;
183 const uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
186 bool section =
false;
187 uint32_t* entry = owner.findExistingEntry(value, §ion);
188 if (!entry || !*entry) {
192 physical = (*entry & 0xfff00000) | (value & 0xfffff);
195 uint32_t* table = entry - ((value >> 12) & 255);
196 physical = (*entry & AddressMask) | (value & (PAGE_SIZE - 1));
197 flags = shadowAt(table)[(value >> 12) & 255];
203 const uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
206 uint32_t* entry = owner.findEntry(value,
false);
207 if (!entry || !*entry) {
210 const unsigned int index = (value >> 12) & 255;
211 shadowAt(entry - index)[index] = flags;
212 *entry = pageDescriptor(*entry & AddressMask, flags);
219 panic(
"ARMv7: setFlags on absent mapping");
224 size_t& flags,
size_t requiredFlags) {
225 const uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
228 uint32_t* entry = owner.findEntry(value,
false);
229 if (!entry || !*entry) {
232 const unsigned int index = (value >> 12) & 255;
233 uint32_t* shadow = shadowAt(entry - index);
234 flags = shadow[index];
235 if ((flags & requiredFlags) != requiredFlags) {
238 physical = *entry & AddressMask;
245bool Armv7VirtualAddressSpace::tryDetachUserPage(
void* address, physical_uintptr_t expected) {
246 physical_uintptr_t physical = 0;
255 physical_uintptr_t physical = 0;
258 panic(
"ARMv7: unmap on absent mapping");
263 physical_uintptr_t old = 0;
269 physical_uintptr_t fresh = Armv7PhysicalMemoryManager::instance().tryAllocatePage();
273 memcpy(
reinterpret_cast<void*
>(ARMV7_DIRECT_MAP_BASE + fresh),
274 reinterpret_cast<const void*
>(ARMV7_DIRECT_MAP_BASE + old), PAGE_SIZE);
275 physical_uintptr_t detached = 0;
276 size_t detachedFlags = 0;
277 if (!
detachMapping(address, detached, detachedFlags) || detached != old ||
279 Armv7PhysicalMemoryManager::instance().
freePage(fresh);
282 Armv7PhysicalMemoryManager::instance().
freePage(old);
287 return allocateStack(
this == &m_KernelSpace ? KERNEL_STACK_SIZE : USERSPACE_VIRTUAL_STACK_SIZE);
294 if (bytes > SIZE_MAX - PAGE_SIZE + 1) {
297 bytes = (bytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
301 if (m_StackTop < bytes + PAGE_SIZE) {
305 m_StackTop -= bytes + PAGE_SIZE;
308 for (
size_t offset = PAGE_SIZE; offset <= bytes; offset += PAGE_SIZE) {
309 physical_uintptr_t physical = Armv7PhysicalMemoryManager::instance().tryAllocatePage();
310 if (!physical || !
map(physical,
reinterpret_cast<void*
>(top - offset), flags)) {
312 Armv7PhysicalMemoryManager::instance().
freePage(physical);
314 for (
size_t mapped = PAGE_SIZE; mapped < offset; mapped += PAGE_SIZE) {
315 void* page =
reinterpret_cast<void*
>(top - mapped);
316 physical_uintptr_t old = 0;
319 Armv7PhysicalMemoryManager::instance().
freePage(old);
325 return new Stack(
reinterpret_cast<void*
>(top), bytes);
332 const uintptr_t base =
reinterpret_cast<uintptr_t
>(stack->getBase());
333 for (
size_t offset = 0; offset < stack->getSize(); offset += PAGE_SIZE) {
334 void* page =
reinterpret_cast<void*
>(base + offset);
335 physical_uintptr_t physical = 0;
338 Armv7PhysicalMemoryManager::instance().
freePage(physical);
346 uint32_t* sourceRoot = tableAt(m_Root);
347 uint32_t* targetRoot = tableAt(destination.m_Root);
348 for (
size_t first = 0; first < 2048; ++first) {
349 const uint32_t entry = sourceRoot[first];
353 if ((entry & 3) != PageTable) {
356 physical_uintptr_t child = Armv7PhysicalMemoryManager::instance().tryAllocatePage();
360 uint32_t* source = tableAt(entry & TableMask);
361 uint32_t* target = tableAt(child);
362 memset(target, 0, PAGE_SIZE);
363 targetRoot[first] = child | PageTable;
364 for (
size_t second = 0; second < 256; ++second) {
365 if (!source[second]) {
368 const physical_uintptr_t old = source[second] & AddressMask;
369 const size_t flags = shadowAt(source)[second];
371 physical_uintptr_t fresh = Armv7PhysicalMemoryManager::instance().tryAllocatePage();
375 memcpy(
reinterpret_cast<void*
>(ARMV7_DIRECT_MAP_BASE + fresh),
376 reinterpret_cast<const void*
>(ARMV7_DIRECT_MAP_BASE + old), PAGE_SIZE);
377 target[second] = pageDescriptor(fresh, flags);
378 shadowAt(target)[second] = flags;
381 Armv7PhysicalMemoryManager::instance().
pin(old);
383 target[second] = source[second];
384 shadowAt(target)[second] = flags;
391void Armv7VirtualAddressSpace::freeUserTables() {
392 uint32_t* root = tableAt(m_Root);
393 for (
size_t first = 0; first < 2048; ++first) {
394 const uint32_t entry = root[first];
395 if ((entry & 3) != PageTable) {
398 uint32_t* table = tableAt(entry & TableMask);
399 for (
size_t second = 0; second < 256; ++second) {
400 if (table[second] && !(shadowAt(table)[second] &
Borrowed)) {
401 Armv7PhysicalMemoryManager::instance().
freePage(table[second] & AddressMask);
405 Armv7PhysicalMemoryManager::instance().
freePage(entry & TableMask);
417 if (
this != &m_KernelSpace && !cloneUserTables(*
clone, copyOnWrite)) {
423 clone->m_StackTop = m_StackTop;
428 if (
this == &m_KernelSpace) {
433 m_Heap =
reinterpret_cast<void*
>(USERSPACE_VIRTUAL_HEAP);
435 m_StackTop = USERSPACE_VIRTUAL_STACK;
440 uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
441 return value >= KERNEL_VIRTUAL_HEAP && value < KERNEL_VIRTUAL_HEAP_END;
445 uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
446 return value >=
reinterpret_cast<uintptr_t
>(
m_Heap) &&
447 value <
reinterpret_cast<uintptr_t
>(
m_HeapEnd);
451 return reinterpret_cast<void*
>(
this == &m_KernelSpace ? KERNEL_VIRTUAL_HEAP_END
452 : USERSPACE_DYNAMIC_END);
void freePage(physical_uintptr_t page) override
void pin(physical_uintptr_t page) override
bool detachMapping(void *address, physical_uintptr_t &physical, size_t &flags, size_t requiredFlags=0) override
void unmap(void *address) override
bool memIsInKernelHeap(void *address) override
void setFlags(void *address, size_t flags) override
bool getMapping(void *address, physical_uintptr_t &physical, size_t &flags) override
VirtualAddressSpace * clone(bool copyOnWrite=true) override
bool trySetFlags(void *address, size_t flags) override
bool isMapped(void *address) override
void revertToKernelAddressSpace() override
bool map(physical_uintptr_t physical, void *address, size_t flags) override
bool memIsInHeap(void *address) override
void * getEndOfHeap() override
bool handleCopyOnWriteFault(void *address, bool userMode) override
void freeStack(Stack *stack) override
bool isAddressValid(void *address) override
Stack * allocateStack() override
static void invalidate(void *pAddress)
static const size_t CopyOnWrite
static VirtualAddressSpace * create()
static const size_t CacheDisable
static const size_t Borrowed
static const size_t Shared
static const size_t KernelMode
static const size_t NoAccess
static const size_t Write
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
static const size_t WriteProtected
static const size_t Execute
static const size_t Swapped
void EXPORTED_PUBLIC panic(const char *msg) NORETURN