1#include "PhysicalMemoryManager.h"
2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/Metrics.h"
4#include "pedigree/kernel/panic.h"
5#include "pedigree/kernel/processor/MemoryRegion.h"
6#include "pedigree/kernel/processor/Processor.h"
7#include "pedigree/kernel/processor/VirtualAddressSpace.h"
11#include "AddressLayout.h"
14EXPORTED_PUBLIC
size_t g_AllocedPages = 0;
17constexpr uint64_t MaximumPhysicalAddress = 0x80000000ULL;
20Armv7PhysicalMemoryManager::Armv7PhysicalMemoryManager()
21 : m_References(nullptr),
22 m_FreeBitmap(nullptr),
27 m_NextRegion(KERNEL_VIRTUAL_MEMORYREGION_ADDRESS) {}
35 return Armv7PhysicalMemoryManager::instance();
40 for (
void* entry = info.getMemoryMap(); entry; entry = info.nextMemoryMapEntry(entry)) {
41 if (info.getMemoryMapEntryType(entry) != 1) {
44 uint64_t start = info.getMemoryMapEntryAddress(entry);
45 uint64_t length = info.getMemoryMapEntryLength(entry);
46 if (start >= MaximumPhysicalAddress || length > MaximumPhysicalAddress - start) {
47 length = start < MaximumPhysicalAddress ? MaximumPhysicalAddress - start : 0;
49 if (start + length > highest) {
50 highest = start + length;
53 m_MaxPage = highest / PAGE_SIZE;
55 panic(
"ARMv7: no usable RAM");
58 const size_t referenceBytes = m_MaxPage *
sizeof(uint16_t);
59 const size_t bitmapBytes = (m_MaxPage + 7) / 8;
60 const size_t metadataBytes = (referenceBytes + bitmapBytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
61 physical_uintptr_t metadata = 0;
62 for (
void* entry = info.getMemoryMap(); entry; entry = info.nextMemoryMapEntry(entry)) {
63 if (info.getMemoryMapEntryType(entry) != 1) {
66 uint64_t start = (info.getMemoryMapEntryAddress(entry) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
67 uint64_t end = info.getMemoryMapEntryAddress(entry) + info.getMemoryMapEntryLength(entry);
68 if (end > MaximumPhysicalAddress) {
69 end = MaximumPhysicalAddress;
71 if (start < end && end - start >= metadataBytes) {
77 panic(
"ARMv7: cannot reserve page metadata");
80 m_References =
reinterpret_cast<uint16_t*
>(ARMV7_DIRECT_MAP_BASE + metadata);
81 m_FreeBitmap =
reinterpret_cast<uint8_t*
>(m_References + m_MaxPage);
82 memset(m_References, 0, metadataBytes);
84 for (
void* entry = info.getMemoryMap(); entry; entry = info.nextMemoryMapEntry(entry)) {
85 if (info.getMemoryMapEntryType(entry) != 1) {
88 uint64_t start = info.getMemoryMapEntryAddress(entry);
89 uint64_t end = start + info.getMemoryMapEntryLength(entry);
90 if (end > MaximumPhysicalAddress) {
91 end = MaximumPhysicalAddress;
93 start = (start + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
94 end &= ~(PAGE_SIZE - 1);
95 for (uint64_t address = start; address < end; address += PAGE_SIZE) {
96 if (address >= metadata && address < metadata + metadataBytes) {
99 markPage(address / PAGE_SIZE,
true);
104 m_NextPage = metadata / PAGE_SIZE + metadataBytes / PAGE_SIZE;
105 g_FreePages = m_FreePages;
109bool Armv7PhysicalMemoryManager::pageAvailable(
size_t page)
const {
110 return page < m_MaxPage && (m_FreeBitmap[page / 8] & (1U << (page % 8)));
113void Armv7PhysicalMemoryManager::markPage(
size_t page,
bool available) {
114 uint8_t& bits = m_FreeBitmap[page / 8];
116 bits |= 1U << (page % 8);
118 bits &= ~(1U << (page % 8));
122size_t Armv7PhysicalMemoryManager::pageLimit(
size_t constraints)
const {
123 size_t limit = m_MaxPage;
125 limit = limit < (1U << 8) ? limit : (1U << 8);
127 limit = limit < (1U << 12) ? limit : (1U << 12);
128 }
else if (constraints &
below4GB) {
129 limit = limit < (1U << 20) ? limit : (1U << 20);
134physical_uintptr_t Armv7PhysicalMemoryManager::allocatePageUnlocked(
size_t constraints) {
135 const size_t limit = pageLimit(constraints);
140 size_t first = m_NextPage < limit ? m_NextPage : 0;
141 for (
size_t pass = 0; pass < 2; ++pass) {
142 const size_t end = pass ? first : limit;
143 for (
size_t page = pass ? 0 : first; page < end; ++page) {
144 if (!pageAvailable(page)) {
147 markPage(page,
false);
148 m_References[page] = 1;
152 m_NextPage = page + 1;
153 return page * PAGE_SIZE;
159physical_uintptr_t Armv7PhysicalMemoryManager::allocateContinuousPagesUnlocked(
size_t pages,
160 size_t constraints) {
161 const size_t limit = pageLimit(constraints);
162 if (!pages || pages > limit) {
165 for (
size_t first = 1; first <= limit - pages; ++first) {
167 while (count < pages && pageAvailable(first + count)) {
170 if (count != pages) {
174 for (
size_t page = first; page < first + pages; ++page) {
175 markPage(page,
false);
176 m_References[page] = 1;
178 m_FreePages -= pages;
179 g_FreePages -= pages;
180 g_AllocedPages += pages;
181 m_NextPage = first + pages;
182 return first * PAGE_SIZE;
189 physical_uintptr_t page = allocatePageUnlocked(constraints);
192 Metrics::increment(Metrics::PhysicalPageAllocFailure);
194 panic(
"ARMv7: out of physical pages");
197 Metrics::increment(Metrics::PhysicalPageAlloc);
202physical_uintptr_t Armv7PhysicalMemoryManager::tryAllocatePage() {
204 physical_uintptr_t page = allocatePageUnlocked(0);
206 Metrics::increment(page ? Metrics::PhysicalPageAlloc : Metrics::PhysicalPageAllocFailure);
211physical_uintptr_t Armv7PhysicalMemoryManager::allocateAlignedPages(
size_t pages) {
212 if (!pages || pages > m_MaxPage) {
216 const size_t startingPage = ((m_NextPage + pages - 1) / pages) * pages;
217 for (
size_t pass = 0; pass < 2; ++pass) {
218 const size_t begin = pass ? pages : startingPage;
219 const size_t end = pass ? startingPage : m_MaxPage - pages + 1;
220 for (
size_t first = begin; first < end; first += pages) {
222 while (count < pages && pageAvailable(first + count)) {
225 if (count != pages) {
228 for (
size_t page = first; page < first + pages; ++page) {
229 markPage(page,
false);
230 m_References[page] = 1;
232 m_FreePages -= pages;
233 g_FreePages -= pages;
234 g_AllocedPages += pages;
235 m_NextPage = first + pages;
236 return first * PAGE_SIZE;
243 const size_t index = page / PAGE_SIZE;
244 if (!page || (page & (PAGE_SIZE - 1)) || index >= m_MaxPage || !m_References[index]) {
245 panic(
"ARMv7: invalid physical page free");
247 if (--m_References[index]) {
250 markPage(index,
true);
255 Metrics::increment(Metrics::PhysicalPageFree);
257 if (index < m_NextPage) {
269 const size_t index = page / PAGE_SIZE;
270 if (index >= m_MaxPage || !m_References[index] || m_References[index] == 0xffff) {
271 panic(
"ARMv7: invalid physical page pin");
273 ++m_References[index];
276bool Armv7PhysicalMemoryManager::copyPhysicalPageToBuffer(physical_uintptr_t page,
void* buffer) {
277 if (!page || page >= MaximumPhysicalAddress || (page & (PAGE_SIZE - 1)) || !buffer) {
280 memcpy(buffer,
reinterpret_cast<const void*
>(ARMV7_DIRECT_MAP_BASE + page), PAGE_SIZE);
284bool Armv7PhysicalMemoryManager::copyPhysicalPageFromBuffer(physical_uintptr_t page,
285 const void* buffer) {
286 if (!page || page >= MaximumPhysicalAddress || (page & (PAGE_SIZE - 1)) || !buffer) {
289 memcpy(
reinterpret_cast<void*
>(ARMV7_DIRECT_MAP_BASE + page), buffer, PAGE_SIZE);
295 return {m_TotalPages, m_FreePages, m_MaxPage != 0};
304 size_t constraints,
size_t flags,
305 physical_uintptr_t start) {
306 if (!pages || pages > (~
size_t(0) / PAGE_SIZE)) {
310 const size_t bytes = pages * PAGE_SIZE;
311 const uintptr_t address = (m_NextRegion + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
312 if (address + bytes < address || address + bytes > KERNEL_VIRTUAL_MEMORYREGION_END) {
315 m_NextRegion = address + bytes;
317 const bool explicitPhysical = start !=
static_cast<physical_uintptr_t
>(-1);
318 const bool virtualOnlyRegion = constraints &
virtualOnly;
319 if (explicitPhysical && (start & (PAGE_SIZE - 1))) {
322 physical_uintptr_t continuousBase = 0;
323 if (!explicitPhysical && !virtualOnlyRegion && (constraints &
continuous)) {
325 continuousBase = allocateContinuousPagesUnlocked(pages, constraints);
326 if (!continuousBase) {
331 for (
size_t i = 0; i < pages && !virtualOnlyRegion; ++i) {
332 physical_uintptr_t physical = 0;
333 if (explicitPhysical) {
334 physical = start + i * PAGE_SIZE;
335 }
else if (continuousBase) {
336 physical = continuousBase + i * PAGE_SIZE;
339 physical = allocatePageUnlocked(constraints);
342 !space.
map(physical,
reinterpret_cast<void*
>(address + i * PAGE_SIZE),
345 if (!explicitPhysical && !continuousBase && physical) {
348 for (
size_t mapped = 0; mapped < i; ++mapped) {
349 void* virtualPage =
reinterpret_cast<void*
>(address + mapped * PAGE_SIZE);
350 physical_uintptr_t old = 0;
352 if (space.
getMapping(virtualPage, old, oldFlags)) {
353 space.
unmap(virtualPage);
354 if (!explicitPhysical && !continuousBase) {
359 if (continuousBase) {
360 for (
size_t page = 0; page < pages; ++page) {
361 freePage(continuousBase + page * PAGE_SIZE);
371 region.m_bPageBacked = !explicitPhysical;
372 region.m_bNonRamMemory = explicitPhysical;
373 region.m_bForced = explicitPhysical;
374 region.m_bAnonymous = constraints &
anonymous;
380 if (!region || !region->
m_Size) {
385 for (
size_t i = 0; i < region->
m_Size; i += PAGE_SIZE) {
387 reinterpret_cast<void*
>(
reinterpret_cast<uintptr_t
>(region->
m_VirtualAddress) + i);
388 physical_uintptr_t physical = 0;
390 if (!space.
getMapping(address, physical, flags)) {
393 space.
unmap(address);
394 if (region->m_bPageBacked) {
void freePage(physical_uintptr_t page) override
void unmapRegion(MemoryRegion *region) override
void freePageUnlocked(physical_uintptr_t page) override
bool allocateRegion(MemoryRegion ®ion, size_t pages, size_t constraints, size_t flags, physical_uintptr_t start=-1) override
size_t freePageCount() const override
void pin(physical_uintptr_t page) override
physical_uintptr_t allocatePage(size_t constraints=0) override
Special memory entity in the kernel's virtual address space.
physical_uintptr_t m_PhysicalAddress
static const size_t continuous
static PhysicalMemoryManager & instance()
static const size_t below1MB
static const size_t virtualOnly
static const size_t anonymous
Vector< MemoryRegion * > m_MemoryRegions
static const size_t nonRamMemory
static const size_t below16MB
static const size_t below4GB
static size_t m_Initialised
static const size_t CacheDisable
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
static const size_t KernelMode
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual void unmap(void *virtualAddress)=0
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
EXPORTED_PUBLIC size_t g_FreePages
void pushBack(const T &value)