2#include "pedigree/kernel/process/Process.h"
3#include "pedigree/kernel/process/Scheduler.h"
4#include "pedigree/kernel/process/Thread.h"
5#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
6#include "pedigree/kernel/processor/Processor.h"
7#include "pedigree/kernel/processor/ProcessorInformation.h"
8#include "pedigree/kernel/utilities/utility.h"
18 if (permissions & MemoryMappedObject::Exec)
20 if (!(permissions & MemoryMappedObject::Write))
28 owner->getAddressSpace() == &space;
30void accountPages(
Process& owner, ssize_t virtualPages, ssize_t physicalPages) {
35 auto* caller = thread ? thread->getParent() :
nullptr;
36 if (caller != &owner) {
38 caller->trackPages(0, -physicalPages, 0);
39 owner.trackPages(virtualPages, physicalPages, 0);
41 owner.trackPages(virtualPages, 0, 0);
44PopulationStatus populationStatus(SwapStatus status) {
45 return status == SwapStatus::Success ? PopulationStatus::Success
46 : status == SwapStatus::NoMemory ? PopulationStatus::NoMemory
47 : PopulationStatus::IoError;
51#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
53ssize_t anonymousCloneFailure = -1;
55void AnonymousMemoryMap::setCloneFailureForTest(ssize_t after) {
57 anonymousCloneFailure = after;
60AnonymousMemoryMap::~AnonymousMemoryMap() {
66 while (m_Mappings.lowerBound(cursor,
address, page)) {
67 SwapStore::instance().release(page.slot);
76 result->m_OwnerProcess = m_OwnerProcess;
77 result->m_MaximumPermissions = m_MaximumPermissions;
80 while (m_Mappings.lowerBound(cursor,
address, page)) {
81#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
82 if (!anonymousCloneFailure) {
86 if (anonymousCloneFailure > 0)
87 --anonymousCloneFailure;
89 if (!result->m_Mappings.tryInsert(page.address, page)) {
93 if (page.slot && !SwapStore::instance().retain(page.slot)) {
94 result->m_Mappings.remove(page.address);
103 uintptr_t destination,
104 size_t destinationLength) {
109 result->m_OwnerProcess = m_OwnerProcess;
110 result->m_OwnsMappings =
false;
111 result->m_LockMode = m_LockMode;
116 result->m_MaximumPermissions = m_MaximumPermissions;
117 result->m_Attachment = m_Attachment;
118 const size_t preserved = sourceLength < destinationLength ? sourceLength : destinationLength;
119 uintptr_t cursor = source,
address;
121 while (m_Mappings.lowerBound(cursor,
address, page) &&
address - source < preserved) {
123 moved.address = destination + page.address - source;
124 if (!result->m_Mappings.tryInsert(moved.address, moved)) {
142 while (m_Mappings.lowerBound(at,
address, page))
145 result->m_OwnsMappings = m_OwnsMappings;
148void AnonymousMemoryMap::releaseDetachedPage(uintptr_t oldAddress,
151 Page* tracked = m_Mappings.find(oldAddress);
153 SwapStore::instance().release(tracked->slot);
154 m_Mappings.remove(oldAddress);
159void AnonymousMemoryMap::discardRange(
VirtualAddressSpace& space, uintptr_t base,
size_t length) {
160#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
161 size_t trackedPages = 0, mappedPages = 0;
166#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
171#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
175 SwapStore::instance().release(tracked.slot);
180#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
182 process->recordBenchmarkVmCounter(Process::VmDiscardTrackedPages, trackedPages);
183 process->recordBenchmarkVmCounter(Process::VmDiscardMappedPages, mappedPages);
205 while (m_Mappings.lowerBound(cursor,
address, tracked)) {
208 if (page.slot || !space.
isMapped(
reinterpret_cast<void*
>(page.address)))
210 physical_uintptr_t physical;
212 space.
getMapping(
reinterpret_cast<void*
>(page.address), physical, flags);
214 page.pagingBlocked =
false;
222void AnonymousMemoryMap::unmapUnlocked() {
228 auto*
address =
reinterpret_cast<void*
>(page.address);
229 if (!page.slot && !page.pagingBlocked)
230 return SwapStatus::Success;
232 if (!admitOwner(m_OwnerProcess, space, owner))
233 return SwapStatus::Busy;
235 physical_uintptr_t physical;
238 return SwapStatus::Invalid;
241 return SwapStatus::IoError;
242 page.pagingBlocked =
false;
243 return SwapStatus::Success;
246 const auto physical = memory.tryAllocatePage();
248 return SwapStatus::NoMemory;
249 SwapStatus status = SwapStore::instance().readPage(page.slot, physical);
250 size_t committedTables = 0;
251 if (status == SwapStatus::Success &&
253 status = SwapStatus::NoMemory;
254 if (status != SwapStatus::Success) {
255 memory.freePage(physical);
258 accountPages(*owner.get(), 1, 1 +
static_cast<ssize_t
>(committedTables));
259 SwapStore::instance().release(page.slot);
260 page.pagingBlocked =
false;
261 return SwapStatus::Success;
264 PopulationStatus* population) {
267 *population = PopulationStatus::NoMemory;
273 if (entry && (entry->slot || entry->pagingBlocked)) {
274 const auto status = restorePage(space, *entry);
276 *population = populationStatus(status);
277 return status == SwapStatus::Success;
280 if (!admitOwner(m_OwnerProcess, space, owner))
282 auto* virtualAddress =
reinterpret_cast<void*
>(
address);
290 memory.freePage(m_Zero);
293 if (!entry && !m_Mappings.tryInsert(
address,
Page{address, {},
false})) {
294 space.
unmap(virtualAddress);
295 memory.freePage(m_Zero);
300 const auto physical = memory.tryAllocatePage();
302 const auto physical = memory.allocatePage();
306 if (!initialisePhysicalPage(physical)) {
307 memory.freePage(physical);
312 if (!entry && !m_Mappings.tryInsert(address, Page{address, {},
false})) {
313 memory.freePage(physical);
316 if (space.
isMapped(virtualAddress)) {
317 physical_uintptr_t old;
321 memory.freePage(physical);
324 space.
unmap(virtualAddress);
325 memory.freePage(old);
328 size_t committedTables = 0;
329 const bool mapped = space.tryMapUserPage(
335 memory.freePage(physical);
340 accountPages(*owner.get(), 1, 1 +
static_cast<ssize_t
>(committedTables));
344 *population = PopulationStatus::Success;
348 if (!m_OwnerProcess || !m_OwnsMappings || m_LockMode != MemoryLockMode::None || !
m_bCopyOnWrite ||
355 if (page->pagingBlocked)
357 auto* at =
reinterpret_cast<void*
>(
address);
360 physical_uintptr_t physical;
363 if (physical == m_Zero)
377 return SwapStatus::Unsupported;
379 if (!admitOwner(m_OwnerProcess, space, owner))
380 return SwapStatus::Busy;
381 Page* page = m_Mappings.find(
address);
382 auto* at =
reinterpret_cast<void*
>(
address);
383 if (page && !page->slot && space.
isMapped(at)) {
384 physical_uintptr_t physical;
388 return SwapStatus::IoError;
389 page->pagingBlocked =
true;
391 const bool zero = physical == m_Zero;
393 zero ? SwapStatus::Success : SwapStore::instance().writePage(physical, slot);
394 if (status == SwapStatus::Success && space.tryDetachUserPage(at, physical)) {
396 page->pagingBlocked =
false;
398 accountPages(*owner.get(), -1, zero ? 0 : -1);
400 return SwapStatus::Success;
402 SwapStore::instance().release(slot);
404 page->pagingBlocked =
false;
405 return status == SwapStatus::Success ? SwapStatus::IoError : status;
407 return SwapStatus::Success;
411 !SwapStore::instance().snapshot().active)
415 while (m_Mappings.lowerBound(cursor,
address, page)) {
419 bool released =
false;
420 if (pageOutAt(space,
address, released) != SwapStatus::Success)
430 while (m_Mappings.lowerBound(cursor,
address, page)) {
431 const auto status = restorePage(space, *m_Mappings.find(
address));
432 if (status != SwapStatus::Success)
436 return SwapStatus::Success;
441 auto restoreResidentPage = [&]() {
442 Page* page = m_Mappings.find(
address);
443 if (page && page->pagingBlocked)
444 return populationStatus(restorePage(space, *page));
445 return PopulationStatus::Success;
450 return restoreResidentPage();
453 return restoreResidentPage();
Memory-mapped file interface.
virtual void unmap() override
virtual void setPermissions(MemoryMappedObject::Permissions perms) override
bool supportsPageOut(VirtualAddressSpace &space, uintptr_t address) override
virtual bool remove(size_t length) override
virtual bool trap(VirtualAddressSpace &space, uintptr_t address, bool bWrite, PopulationStatus *population=nullptr) override
virtual MemoryMappedObject * split(uintptr_t at) override
virtual MemoryMappedObject * clone() override
MemoryMappedObject * stageSlice(uintptr_t source, size_t sourceLength, uintptr_t destination, size_t destinationLength) override
static MemoryMapManager & instance()
uintptr_t address() const
Permissions m_Permissions
Permissions permissions() const
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
virtual void freePage(physical_uintptr_t page)=0
static ProcessorInformation & information()
static Scheduler & instance()
MUST_USE_RESULT bool acquireProcess(ProcessLease &lease, size_t n)
virtual void setFlags(void *virtualAddress, size_t newFlags)=0
static const size_t CopyOnWrite
static const size_t Borrowed
static const size_t RuntimeMapping
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
static const size_t Shared
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 const size_t NoAccess
static const size_t Write
virtual bool detachMapping(void *virtualAddress, physical_uintptr_t &physical, size_t &flags, size_t requiredFlags=0)
static const size_t WriteProtected
static const size_t Execute
virtual MUST_USE_RESULT bool trySetFlags(void *virtualAddress, size_t newFlags)
virtual void unmap(void *virtualAddress)=0