The Pedigree Project 0.1
MemoryMappedFile.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef MEMORY_MAPPED_FILE_H
21#define MEMORY_MAPPED_FILE_H
22#include "pedigree/kernel/Spinlock.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/process/FilesystemContext.h"
25#include "pedigree/kernel/process/MemoryPressureManager.h"
26#include "pedigree/kernel/process/Mutex.h"
27#include "pedigree/kernel/process/TerminationDeferral.h"
28#include "pedigree/kernel/process/Uninterruptible.h"
29#include "pedigree/kernel/processor/PageFaultHandler.h"
30#include "pedigree/kernel/processor/UserMemoryPolicy.h"
31#include "pedigree/kernel/processor/VirtualAddressSpace.h"
32#include "pedigree/kernel/processor/state_forward.h"
33#include "pedigree/kernel/processor/types.h"
34#include "pedigree/kernel/utilities/Cache.h"
35#include "pedigree/kernel/utilities/List.h"
36#include "pedigree/kernel/utilities/SharedPointer.h"
37#include "pedigree/kernel/utilities/String.h"
38#include "pedigree/kernel/utilities/Tree.h"
39#include "pedigree/kernel/utilities/new"
40
41#include <config.h>
42
43#include "MappingList.h"
44#include "SwapStore.h"
45
46class File;
47class Process;
50using FileResidencyAccess = bool (*)(File*, void*);
51
52struct EXPORTED_PUBLIC FileMappingOrigin {
53 uint64_t openIdentity = 0;
54 bool writableOpen = false;
55 FilesystemPathRef openingPath{};
57};
58
61 public:
62 virtual ~MappingAttachment() {}
63 virtual uintptr_t baseAddress() const = 0;
64 virtual void relocate(uintptr_t newBase) = 0;
65 virtual SharedPointer<MappingAttachment> clone(Process* target) = 0;
66};
67
139 friend class MemoryMapManager;
140
141 private:
144
145 public:
147 typedef int Permissions;
148
149 static const int None = 0x0;
150 static const int Read = 0x1;
151 static const int Write = 0x2;
152 static const int Exec = 0x4;
153
155 MemoryMappedObject(uintptr_t address, bool bCopyOnWrite, size_t length, Permissions perms,
156 Permissions maximumPerms = Read | Write | Exec)
157 : m_bCopyOnWrite(bCopyOnWrite),
160 m_Permissions(perms),
161 m_MaximumPermissions(maximumPerms),
162 m_Attachment(),
163 m_OwnerProcess(nullptr),
164 m_OwnsMappings(true),
165 m_LockMode(MemoryLockMode::None) {}
166
167 virtual ~MemoryMappedObject();
168
179 virtual MemoryMappedObject* clone() = 0;
180
186 virtual MemoryMappedObject* split(uintptr_t at) = 0;
187
189 virtual MemoryMappedObject* stageSlice(uintptr_t source, size_t sourceLength,
190 uintptr_t destination, size_t destinationLength) = 0;
191 void setMappingOwnership(bool ownsMappings) {
192 m_OwnsMappings = ownsMappings;
193 }
194 virtual void releaseDetachedPage(uintptr_t oldAddress,
195 const VirtualAddressSpace::DetachedPage& page) = 0;
196 virtual void discardRange(VirtualAddressSpace& space, uintptr_t base, size_t length) = 0;
197 virtual File* backingFile() const {
198 return nullptr;
199 }
200 virtual bool backingRangeValid(uintptr_t source, size_t length) const {
201 return true;
202 }
203 virtual bool resident(VirtualAddressSpace& space, uintptr_t address, FileResidencyAccess access,
204 void* credentials);
205
215 virtual bool remove(size_t length) = 0;
216
222 virtual void setPermissions(Permissions perms) = 0;
223
224 virtual bool preparePermissions(uintptr_t base, size_t length, Permissions perms) {
225 return true;
226 }
227
231 virtual bool sync(uintptr_t at, bool async) {
232 return true;
233 }
234
236 virtual bool syncRange(uintptr_t at, size_t length, bool async);
237
239 virtual void invalidate(uintptr_t at) {}
240
241 virtual bool sharedBacking(uintptr_t at, uintptr_t& identity, size_t& offset) const {
242 return false;
243 }
244
245 virtual bool usesBacking(uintptr_t identity) const {
246 return false;
247 }
248 virtual bool beyondBackingEnd(uintptr_t at) const {
249 return false;
250 }
251 virtual void discardFilePages(VirtualAddressSpace& space, size_t end) {}
252
259 virtual void unmap() = 0;
260
268 virtual bool trap(VirtualAddressSpace& space, uintptr_t address, bool bWrite,
269 PopulationStatus* population = nullptr) = 0;
270 virtual PopulationStatus prepareResidentAccess(VirtualAddressSpace& space, uintptr_t address) {
271 return PopulationStatus::Success;
272 }
273 PopulationStatus populatePage(VirtualAddressSpace& space, uintptr_t address);
274 MemoryLockMode lockMode() const {
275 return m_LockMode;
276 }
277
283 virtual bool supportsPageOut(VirtualAddressSpace& space, uintptr_t address) {
284 return false;
285 }
286 virtual SwapStatus pageOutAt(VirtualAddressSpace& space, uintptr_t address, bool& released) {
287 return SwapStatus::Unsupported;
288 }
289 virtual bool reclaimAnonymousPage(VirtualAddressSpace& space) {
290 return false;
291 }
292 virtual SwapStatus restoreSwapPages(VirtualAddressSpace& space) {
293 return SwapStatus::Success;
294 }
295 virtual bool compact() {
296 return false;
297 }
298
302 bool matches(uintptr_t address) {
303 return (m_Address <= address) && (address < (m_Address + m_Length));
304 }
305
309 uintptr_t address() const {
310 return m_Address;
311 }
312
316 size_t length() const {
317 return m_Length;
318 }
319
322 return m_Permissions;
323 }
324
325 Permissions maximumPermissions() const {
326 return m_MaximumPermissions;
327 }
328
329 protected:
338
345 uintptr_t m_Address;
346
353 size_t m_Length;
354
365 Permissions m_MaximumPermissions;
367 // The mapping gate protects registration; paging additionally admits a
368 // short scheduler lease before dereferencing this process identity.
369 Process* m_OwnerProcess;
370 bool m_OwnsMappings;
371 MemoryLockMode m_LockMode;
372};
373
382class EXPORTED_PUBLIC AnonymousMemoryMap : public MemoryMappedObject {
383 public:
384 AnonymousMemoryMap(uintptr_t address, size_t length, Permissions perms);
385
386 virtual ~AnonymousMemoryMap() override;
387#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
388 static void setCloneFailureForTest(ssize_t after);
389#endif
390
391 virtual MemoryMappedObject* clone() override;
392 virtual MemoryMappedObject* split(uintptr_t at) override;
393 MemoryMappedObject* stageSlice(uintptr_t source, size_t sourceLength, uintptr_t destination,
394 size_t destinationLength) override;
395 void releaseDetachedPage(uintptr_t oldAddress,
396 const VirtualAddressSpace::DetachedPage& page) override;
397 void discardRange(VirtualAddressSpace& space, uintptr_t base, size_t length) override;
398 virtual bool remove(size_t length) override;
399
400 virtual void setPermissions(MemoryMappedObject::Permissions perms) override;
401
402 virtual void unmap() override;
403
404 virtual bool trap(VirtualAddressSpace& space, uintptr_t address, bool bWrite,
405 PopulationStatus* population = nullptr) override;
406 bool supportsPageOut(VirtualAddressSpace& space, uintptr_t address) override;
407 SwapStatus pageOutAt(VirtualAddressSpace& space, uintptr_t address, bool& released) override;
408 bool reclaimAnonymousPage(VirtualAddressSpace& space) override {
409 return pageOut(space);
410 }
411 SwapStatus restoreSwapPages(VirtualAddressSpace& space) override {
412 return restoreAll(space);
413 }
414 PopulationStatus prepareResidentAccess(VirtualAddressSpace& space, uintptr_t address) override;
415
416 private:
417 friend class MemoryMapManager;
418 struct Page {
419 uintptr_t address = 0;
420 SwapReference slot;
421 bool pagingBlocked = false;
422 };
423 bool pageOut(VirtualAddressSpace& space);
424 SwapStatus restorePage(VirtualAddressSpace& space, Page& page);
425 SwapStatus restoreAll(VirtualAddressSpace& space);
426 static physical_uintptr_t m_Zero;
427 static bool initialisePhysicalPage(physical_uintptr_t physical);
428
429 void unmapUnlocked();
430
431 // Faults must not scan every previously populated page in a large mapping.
432 Tree<uintptr_t, Page> m_Mappings;
433};
434
444 friend class MemoryMapManager;
445
446 public:
448 uintptr_t address, size_t length, size_t offset, File* backing, bool bCopyOnWrite,
449 Permissions perms, Permissions maximumPerms = Read | Write | Exec,
451 const FileMappingOrigin& origin = {}, bool executableUse = false);
452
453 virtual ~MemoryMappedFile() override;
454
455 virtual MemoryMappedObject* clone() override;
456 virtual MemoryMappedObject* split(uintptr_t at) override;
457 MemoryMappedObject* stageSlice(uintptr_t source, size_t sourceLength, uintptr_t destination,
458 size_t destinationLength) override;
459 void releaseDetachedPage(uintptr_t oldAddress,
460 const VirtualAddressSpace::DetachedPage& page) override;
461 void discardRange(VirtualAddressSpace& space, uintptr_t base, size_t length) override;
462 File* backingFile() const override {
463 return m_pBacking;
464 }
465 bool backingRangeValid(uintptr_t source, size_t length) const override;
466 bool resident(VirtualAddressSpace& space, uintptr_t address, FileResidencyAccess access,
467 void* credentials) override;
468 virtual bool remove(size_t length) override;
469
470 virtual void setPermissions(MemoryMappedObject::Permissions perms) override;
471
472 virtual bool sync(uintptr_t at, bool async) override;
473 bool syncRange(uintptr_t at, size_t length, bool async) override;
474 virtual void invalidate(uintptr_t at) override;
475 virtual bool sharedBacking(uintptr_t at, uintptr_t& identity, size_t& offset) const override;
476 virtual bool usesBacking(uintptr_t identity) const override;
477 virtual bool beyondBackingEnd(uintptr_t at) const override;
478 virtual void discardFilePages(VirtualAddressSpace& space, size_t end) override;
479 virtual bool preparePermissions(uintptr_t base, size_t length, Permissions perms) override;
480
481 virtual void unmap() override;
482
483 virtual bool trap(VirtualAddressSpace& space, uintptr_t address, bool bWrite,
484 PopulationStatus* population = nullptr) override;
485
501 virtual bool compact() override;
502
503 private:
504 void unmapUnlocked();
505
506 physical_uintptr_t getBackingPage(size_t fileOffset, size_t mappingBytes);
507
508 void releaseDetachedPageUnlocked(uintptr_t oldAddress,
510
512 void trackMapping(uintptr_t, physical_uintptr_t);
513
515 void untrackMapping(uintptr_t);
516
518 physical_uintptr_t getMapping(uintptr_t);
519
521 size_t getMappingCount();
522
524 void clearMappings();
525
528
530 size_t m_Offset;
531
532 size_t m_ReadAheadEnd = ~size_t{0};
533 size_t m_ReadAheadPages = 4;
534
537 FileMappingOrigin m_Origin;
538
546
549 bool m_ExecutableUse;
550 bool m_SharedWriteUse;
551 bool m_UseAdmitted;
552 bool m_MountAdmitted;
553};
554
559class EXPORTED_PUBLIC MemoryMapManager : public MemoryTrapHandler, public MemoryPressureHandler {
560 friend class PosixSubsystem;
561 friend class VfsUserMemoryPolicy;
562
563 public:
564 enum class Placement {
565 Hint,
566 FixedReplace,
567 FixedNoReplace,
568 };
569
570 enum class MapStatus {
571 Success,
572 NoMemory,
573 AddressInUse,
574 PolicyDenied,
575 TextBusy,
576 LockLimit,
577 };
578
579 enum class VmStatus { Success, InvalidRange, Unmapped, Unsupported, NoMemory, LockLimit };
580 enum class FileRemapStatus {
581 Success,
582 InvalidRange,
583 Unsupported,
584 NoMemory,
585 PolicyDenied,
586 LockLimit,
587 PermissionDenied
588 };
589 FileRemapStatus remapFilePages(uintptr_t base, size_t length, size_t byteOffset, bool nonblock);
591 uintptr_t source, destination;
592 size_t oldLength, newLength;
593 bool mayMove, fixed;
594 };
595 VmStatus remap(const RemapRequest& request, uintptr_t& result);
596 VmStatus residency(uintptr_t base, size_t length, unsigned char* kernelVector,
597 FileResidencyAccess access, void* credentials);
598 VmStatus discard(uintptr_t base, size_t length);
599
600 enum class UserPageCopyStatus { Success, Inaccessible, NoMemory, IoError, Unsupported };
601 UserPageCopyStatus copyUserPage(VirtualAddressSpace& space, uintptr_t userAddress,
602 void* kernelBuffer, size_t bytes, bool write);
603
604 PopulationStatus populateMemory(VirtualAddressSpace& space, uintptr_t base, size_t length);
605 void bindMemoryLockPolicy(VirtualAddressSpace& space);
606 MemoryLockStatus lockMemory(VirtualAddressSpace& space, uintptr_t base, size_t length,
607 MemoryLockMode mode, bool privileged);
608 MemoryLockStatus lockAllMemory(VirtualAddressSpace& space, bool current,
609 MemoryLockMode currentMode, MemoryLockMode futureMode,
610 bool privileged);
611 bool hasLockedMemory(VirtualAddressSpace& space, uintptr_t base, size_t length);
612
615 return m_Instance;
616 }
617
618#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
620 void acquireLifecycleGateForHostedTest();
621 void releaseLifecycleGateForHostedTest();
622 bool trapForHostedTest(uintptr_t address, bool bIsWrite, bool bWasPresent);
623 const void* lifecycleGateAddressForHostedTest() const {
624 return static_cast<const Semaphore*>(&m_LifecycleLock);
625 }
626#endif
627
631 MemoryMappedObject* mapFile(File* pFile, uintptr_t& address, size_t length,
632 MemoryMappedObject::Permissions perms, size_t offset = 0,
633 bool bCopyOnWrite = true);
634
636 bool hasSharedWriteCapability(File* backing);
637
638 MemoryMappedObject* mapFile(
639 File* pFile, uintptr_t& address, size_t length, MemoryMappedObject::Permissions perms,
640 size_t offset, bool bCopyOnWrite, Placement placement, MapStatus* status,
641 MemoryMappedObject::Permissions maximumPerms = MemoryMappedObject::Read |
642 MemoryMappedObject::Write |
643 MemoryMappedObject::Exec,
645 MemoryLockMode requestedLock = MemoryLockMode::None, const FileMappingOrigin& origin = {});
646
650 MemoryMappedObject* mapAnon(uintptr_t& address, size_t length,
652
653 MemoryMappedObject* mapAnon(uintptr_t& address, size_t length,
654 MemoryMappedObject::Permissions perms, Placement placement,
655 MapStatus* status,
656 MemoryLockMode requestedLock = MemoryLockMode::None);
657
663 bool clone(Process* pTarget);
664 SwapStatus pageOutRange(uintptr_t base, size_t length);
665 SwapStatus activateSwap(uint32_t endpoint);
666 SwapStatus deactivateSwap(uint32_t endpoint);
667 SwapSnapshot swapSnapshot();
668 bool operationOwnedByCurrentExecution();
669
679 size_t remove(uintptr_t base, size_t length);
680
688 size_t removeAndRelease(uintptr_t base, size_t length, VmStatus* status = nullptr);
689
691 SharedPointer<MappingAttachment> findAttachment(uintptr_t base);
692
694 size_t removeAttachment(const SharedPointer<MappingAttachment>& attachment);
695
702 enum class ProtectStatus {
703 Success,
704 Unmapped,
705 AccessDenied,
706 InvalidRange,
707 Unsupported,
708 NoMemory,
709 TextBusy
710 };
711
712 size_t setPermissions(uintptr_t base, size_t length, MemoryMappedObject::Permissions perms,
713 ProtectStatus* status = nullptr);
714
719 bool contains(uintptr_t base, size_t length);
720
725 bool allows(uintptr_t base, size_t length, MemoryMappedObject::Permissions permissions);
726
727 bool sharedBacking(Process* process, uintptr_t address, uintptr_t& identity, size_t& offset);
728
729 bool faultIn(uintptr_t address, bool write);
731 bool faultInRange(uintptr_t address, size_t length, bool write);
735 bool writableAnonymousRange(uintptr_t address, size_t length);
736
737 enum class FaultResolution { Unhandled, Resolved, BackingFault };
738 FaultResolution resolveUserFault(uintptr_t address, bool write, bool wasPresent, bool execute);
739
740 enum class ResizeStatus { Ready, NoMemory, Unsupported, Invalid };
742 public:
744 const Cache::DiscardReference* loans() const;
745 size_t loanCount() const;
746 size_t totalLoans() const;
747 void commit();
748
749 private:
750 friend class MemoryMapManager;
751 struct Data;
752 explicit PreparedFileResize(Data* data);
753 NOT_COPYABLE_OR_ASSIGNABLE(PreparedFileResize);
754 UniquePointer<Data> m_Data;
755 };
756
759 ResizeStatus prepareFileResize(File* file, size_t oldSize, size_t newSize,
761
766 bool sync(uintptr_t base, size_t length, bool async, int* error = nullptr);
767
769 void invalidate(uintptr_t base, size_t length);
770
774 void unmap(MemoryMappedObject* pObj);
775
779 void unmapAll();
780
784 virtual bool trap(InterruptState& state, uintptr_t address, bool bIsWrite, bool bWasPresent);
785
791 virtual bool compact();
792
793 virtual const char* getMemoryPressureDescription() {
794 return "Unmap safe pages from memory mapped files.";
795 }
796
797 protected:
803 void unmapAllUnlocked();
804
812 void acquireLock();
813
817 void releaseLock();
818
819 public:
828 public:
829 explicit OperationGuard(MemoryMapManager& manager, bool tryOnly = false);
831
832 explicit operator bool() const {
833 return m_Acquired;
834 }
835
836 private:
837 NOT_COPYABLE_OR_ASSIGNABLE(OperationGuard);
838
839 Uninterruptible m_EventDeferral;
840 MemoryMapManager& m_Manager;
841 bool m_Acquired;
842 };
843
844 private:
848
849 class LockPlan;
850 MemoryLockStatus prepareManagedLocks(VirtualAddressSpace& space, uintptr_t base, size_t length,
851 MemoryLockMode mode, bool all,
853 MemoryMappedObject* publishMapping(File* file, uintptr_t& address, size_t length,
854 MemoryMappedObject::Permissions perms, size_t offset,
855 bool copyOnWrite, Placement placement, MapStatus* status,
857 const SharedPointer<MappingAttachment>& attachment,
858 MemoryLockMode requestedLock,
859 const FileMappingOrigin& origin = {});
860 void retireLockedPages(VirtualAddressSpace& space, size_t pages);
861
862 void enterOperation();
863 bool tryEnterOperation();
864 void leaveOperation();
865
866 size_t removeInternal(uintptr_t base, size_t length, bool releaseReservations,
867 VmStatus* status = nullptr);
868 void releaseReservation(Process* process, VirtualAddressSpace& addressSpace, uintptr_t base,
869 size_t length);
870 bool faultInUnlocked(uintptr_t address, bool write, MemoryMappedObject*& selected,
871 bool residentAnonymousOnly = false);
872 bool accessRange(uintptr_t address, size_t length, bool write, bool residentAnonymousOnly);
873 bool handleTrapUnlocked(uintptr_t address, bool bIsWrite, bool bWasPresent, bool execute,
874 MemoryMappedObject* selected);
875 bool handleTrap(uintptr_t address, bool bIsWrite, bool bWasPresent, bool execute = false,
876 MemoryMappedObject* selected = nullptr);
877
878 enum Ops {
879 Sync,
880 Invalidate,
881 };
882
883 bool op(Ops what, uintptr_t base, size_t length, bool async);
884
887
889
892
895
901
904
905 void* m_pLifecycleOwner;
906 size_t m_LifecycleDepth;
907};
908
911#endif
Definition File.h:75
Tree< VirtualAddressSpace *, MmObjectList * > m_MmObjectLists
static MemoryMapManager m_Instance
Spinlock m_LifecycleStateLock
virtual const char * getMemoryPressureDescription()
static MemoryMapManager & instance()
virtual bool sync(uintptr_t at, bool async) override
virtual bool remove(size_t length) override
virtual void setPermissions(MemoryMappedObject::Permissions perms) override
virtual void invalidate(uintptr_t at) override
Tree< uintptr_t, physical_uintptr_t > m_Mappings
virtual MemoryMappedObject * split(uintptr_t at) override
MemoryMappedObject * stageSlice(uintptr_t source, size_t sourceLength, uintptr_t destination, size_t destinationLength) override
void untrackMapping(uintptr_t)
physical_uintptr_t getMapping(uintptr_t)
virtual MemoryMappedObject * clone() override
virtual void unmap() override
bool syncRange(uintptr_t at, size_t length, bool async) override
virtual bool trap(VirtualAddressSpace &space, uintptr_t address, bool bWrite, PopulationStatus *population=nullptr) override
void trackMapping(uintptr_t, physical_uintptr_t)
virtual bool compact() override
size_t length() const
uintptr_t address() const
virtual void unmap()=0
virtual bool sync(uintptr_t at, bool async)
virtual MemoryMappedObject * stageSlice(uintptr_t source, size_t sourceLength, uintptr_t destination, size_t destinationLength)=0
virtual MemoryMappedObject * split(uintptr_t at)=0
MemoryMappedObject(uintptr_t address, bool bCopyOnWrite, size_t length, Permissions perms, Permissions maximumPerms=Read|Write|Exec)
virtual void setPermissions(Permissions perms)=0
virtual bool syncRange(uintptr_t at, size_t length, bool async)
virtual bool remove(size_t length)=0
virtual bool supportsPageOut(VirtualAddressSpace &space, uintptr_t address)
virtual void invalidate(uintptr_t at)
bool matches(uintptr_t address)
virtual bool trap(VirtualAddressSpace &space, uintptr_t address, bool bWrite, PopulationStatus *population=nullptr)=0
virtual MemoryMappedObject * clone()=0
Permissions permissions() const
Definition Mutex.h:56
A key/value dictionary.
Definition Tree.h:33