20#include "PhysicalMemoryManager.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/Metrics.h"
24#include "pedigree/kernel/machine/Trace.h"
25#include "pedigree/kernel/panic.h"
26#include "pedigree/kernel/processor/MemoryRegion.h"
27#include "pedigree/kernel/processor/Processor.h"
28#include "pedigree/kernel/utilities/Cache.h"
29#include "pedigree/kernel/utilities/assert.h"
30#include "pedigree/kernel/utilities/utility.h"
32#if TRACK_PAGE_ALLOCATIONS
33#include "pedigree/kernel/debugger/commands/AllocationCommand.h"
36#include "pedigree/kernel/core/SlamAllocator.h"
37#include "pedigree/kernel/process/MemoryPressureManager.h"
39#include "VirtualAddressSpace.h"
41namespace __pedigree_hosted {};
42using namespace __pedigree_hosted;
48uint32_t g_PageBitmap[16384] = {0};
70 physical_uintptr_t ptr;
76 if (
m_PageStack.freePages() < MemoryPressureManager::getHighWatermark()) {
80 WARNING_NOLOCK(
"Memory pressure encountered, performing a compact...");
82 ERROR_NOLOCK(
"Compact did not alleviate any memory pressure.");
84 NOTICE_NOLOCK(
"Compact was successful.");
88 bDidHitWatermark.compareAndSwap(
false,
true);
89 }
else if (bDidHitWatermark.compareAndSwap(
true,
false)) {
90 ERROR_NOLOCK(
"<pressure was hit, but is no longer being hit>");
97 Metrics::increment(Metrics::PhysicalPageAllocFailure);
99 panic(
"Out of memory.");
101 physical_uintptr_t ptr_bitmap = ptr /
getPageSize();
102 size_t idx = ptr_bitmap / 32;
103 size_t bit = ptr_bitmap % 32;
104 if (g_PageBitmap[idx] & (1 << bit)) {
106 FATAL_NOLOCK(
"PhysicalMemoryManager allocate()d a page twice");
108 g_PageBitmap[idx] |= (1 << bit);
110 Metrics::increment(Metrics::PhysicalPageAlloc);
115#if TRACK_PAGE_ALLOCATIONS
117 if (!g_AllocationCommand.isMallocing()) {
118 g_AllocationCommand.allocatePage(ptr);
125#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
127ssize_t tryAllocationFailure = -1;
129void PhysicalMemoryManager::setTryAllocationFailureForTest(ssize_t after) {
132 tryAllocationFailure = after;
135physical_uintptr_t HostedPhysicalMemoryManager::tryAllocatePage() {
137#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
138 if (!tryAllocationFailure) {
141 Metrics::increment(Metrics::PhysicalPageAllocFailure);
145 if (tryAllocationFailure > 0)
146 --tryAllocationFailure;
148 physical_uintptr_t ptr;
153 Metrics::increment(Metrics::PhysicalPageAllocFailure);
157 physical_uintptr_t ptr_bitmap = ptr /
getPageSize();
158 size_t idx = ptr_bitmap / 32;
159 size_t bit = ptr_bitmap % 32;
160 if (g_PageBitmap[idx] & (1 << bit)) {
162 FATAL_NOLOCK(
"PhysicalMemoryManager allocate()d a page twice");
164 g_PageBitmap[idx] |= (1 << bit);
166 Metrics::increment(Metrics::PhysicalPageAlloc);
171#if TRACK_PAGE_ALLOCATIONS
173 if (!g_AllocationCommand.isMallocing()) {
174 g_AllocationCommand.allocatePage(ptr);
188bool HostedPhysicalMemoryManager::copyPhysicalPageToBuffer(physical_uintptr_t page,
void* buffer) {
189 return page && !(page & (
getPageSize() - 1)) && page < HOSTED_PHYSICAL_MEMORY_SIZE && buffer &&
192bool HostedPhysicalMemoryManager::copyPhysicalPageFromBuffer(physical_uintptr_t page,
193 const void* buffer) {
194 return page && !(page & (
getPageSize() - 1)) && page < HOSTED_PHYSICAL_MEMORY_SIZE && buffer &&
206 "HostedPhysicalMemoryManager::freePageUnlocked called without an "
212 if (result.hasValue()) {
213 struct page p = result.value();
228 size_t idx = ptr_bitmap / 32;
229 size_t bit = ptr_bitmap % 32;
230 if (!(g_PageBitmap[idx] & (1 << bit))) {
232 FATAL_NOLOCK(
"PhysicalMemoryManager DOUBLE FREE");
235 g_PageBitmap[idx] &= ~(1 << bit);
239 Metrics::increment(Metrics::PhysicalPageFree);
248 if (result.hasValue()) {
249 struct page p = result.value();
261#if PEDIGREE_HOSTED_SMOKE_TESTS
262size_t PhysicalMemoryManager::pageReferenceCountForTest(physical_uintptr_t page) {
266size_t HostedPhysicalMemoryManager::pageReferenceCountForTestImpl(physical_uintptr_t page) {
269 if (page >= HOSTED_PHYSICAL_MEMORY_SIZE) {
273 const PageHashable index(page);
274 const MetadataTable::LookupResult result =
m_PageMetadata.lookup(index);
275 if (result.hasValue() && result.value().active) {
276 return result.value().refcount;
279 const physical_uintptr_t bitmapPage = page /
getPageSize();
280 const size_t bitmapIndex = bitmapPage / 32;
281 const size_t bitmapBit = bitmapPage % 32;
282 return (g_PageBitmap[bitmapIndex] & (1U << bitmapBit)) ? 1 : 0;
287 size_t pageConstraints,
size_t Flags,
288 physical_uintptr_t start) {
292 if (start !=
static_cast<physical_uintptr_t
>(-1)) {
297 panic(
"PhysicalMemoryManager::allocateRegion(): function misused");
301 Region.setNonRamMemory(
true);
306 Region.setForced(
true);
310 Region.setNonRamMemory(
true);
311 Region.setForced(
true);
319 WARNING(
"AllocateRegion: MemoryRegion allocation failed.");
325 for (
size_t i = 0; i < cPages; i++)
326 if (virtualAddressSpace.
map(
331 WARNING(
"AllocateRegion: VirtualAddressSpace::map failed.");
339 Region.m_bPageBacked =
false;
349 WARNING(
"AllocateRegion: MemoryRegion allocation failed.");
353 const bool virtualOnlyRegion = pageConstraints &
virtualOnly;
354 if (!virtualOnlyRegion) {
358 for (
size_t i = 0; i < cPages; i++) {
360 if (virtualAddressSpace.
map(
page,
reinterpret_cast<void*
>(vAddress + i *
getPageSize()),
363 for (
size_t mapped = 0; mapped < i; ++mapped) {
364 void* mappedAddress =
reinterpret_cast<void*
>(vAddress + mapped *
getPageSize());
365 physical_uintptr_t mappedPage = 0;
366 size_t mappedFlags = 0;
367 virtualAddressSpace.
getMapping(mappedAddress, mappedPage, mappedFlags);
368 virtualAddressSpace.
unmap(mappedAddress);
372 WARNING(
"AllocateRegion: VirtualAddressSpace::map failed.");
382 Region.m_bPageBacked =
true;
393 TRACE(
"Hosted PMM: init");
395 NOTICE(
"memory-map:");
402 TRACE(
"Hosted PMM: page stack done");
411#if VERBOSE_MEMORY_MANAGER
412 NOTICE(
"physical memory ranges:");
423 KERNEL_VIRTUAL_MEMORYREGION_SIZE);
427#if PEDIGREE_HOSTED_SMOKE_TESTS
429 MemoryRegion first(
"Hosted anonymous-region regression");
432 FATAL(
"HOSTED-MEMORY-TEST: FAIL anonymous-region allocation");
438 !addressSpace.
isMapped(firstAddress)) {
439 FATAL(
"HOSTED-MEMORY-TEST: FAIL anonymous-region ownership");
444 addressSpace.
isMapped(firstAddress)) {
445 FATAL(
"HOSTED-MEMORY-TEST: FAIL anonymous-region release");
448 MemoryRegion second(
"Hosted anonymous-region reuse regression");
452 FATAL(
"HOSTED-MEMORY-TEST: FAIL anonymous-region reuse");
456 addressSpace.
isMapped(firstAddress)) {
457 FATAL(
"HOSTED-MEMORY-TEST: FAIL anonymous-region final release");
460 NOTICE(
"HOSTED-MEMORY-TEST: PASS anonymous-region-release");
462 NOTICE(
"PhysicalMemoryManager: kernel initialisation complete");
466 : m_PhysicalRanges(),
469 m_RegionLock(false, true),
474 m_BackingFile = open(
"physical.bin", O_RDWR | O_CREAT, 0644);
475 lseek(
m_BackingFile, HOSTED_PHYSICAL_MEMORY_SIZE - 1, SEEK_SET);
494 if (*it == pRegion) {
496 uintptr_t start =
reinterpret_cast<uintptr_t
>(pRegion->
virtualAddress());
500 if (pRegion->m_bPageBacked) {
503 }
else if (pRegion->getNonRamMemory()) {
504 if (!pRegion->getForced())
508 for (
size_t i = 0; i < cPages; i++) {
510 if (!virtualAddressSpace.
isMapped(vAddr))
512 physical_uintptr_t pAddr;
514 virtualAddressSpace.
getMapping(vAddr, pAddr, flags);
516 virtualAddressSpace.
unmap(vAddr);
517 if (!pRegion->getNonRamMemory() && pRegion->m_bPageBacked)
Implementation of the PhysicalMemoryManager for common x86.
RangeList< uint64_t > m_PhysicalRanges
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0) override
RangeList< uintptr_t > m_MemoryRegions
HashTable< PageHashable, struct page > m_PageMetadata
virtual void freePage(physical_uintptr_t page) override
void unmapRegion(MemoryRegion *pRegion) override
HostedPhysicalMemoryManager() INITIALISATION_ONLY
void initialisationDone()
static HostedPhysicalMemoryManager * m_Instance
static HostedPhysicalMemoryManager & instance()
virtual void pin(physical_uintptr_t page) override
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1) override
void initialise(const BootstrapStruct_t &Info) INITIALISATION_ONLY
virtual ~HostedPhysicalMemoryManager() override
virtual void freePageUnlocked(physical_uintptr_t page) override
bool compactingForCurrentExecution() const
Special memory entity in the kernel's virtual address space.
void * virtualAddress() const
physical_uintptr_t physicalAddress() const
physical_uintptr_t m_PhysicalAddress
static const size_t continuous
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
static const size_t force
static const size_t virtualOnly
static const size_t anonymous
Vector< MemoryRegion * > m_MemoryRegions
static const size_t nonRamMemory
static const size_t addressConstraints
static ProcessorInformation & information()
static size_t m_Initialised
bool getRange(size_t index, Range &range) const
bool allocate(T length, T &address)
void free(T address, T length, bool merge=true)
bool allocateSpecific(T address, T length)
bool acquire(bool recurse=false, bool safe=true)
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
virtual bool isMapped(void *virtualAddress)=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 free(uint64_t physicalAddress, size_t length, bool newMemory=false)
physical_uintptr_t allocate(size_t constraints, bool waitForReady=true)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
void pushBack(const T &value)
void clear(bool freeMem=false)