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{};
56};
57
60 public:
61 virtual ~MappingAttachment() {}
62 virtual uintptr_t baseAddress() const = 0;
63 virtual void relocate(uintptr_t newBase) = 0;
64 virtual SharedPointer<MappingAttachment> clone(Process* target) = 0;
65};
66
138 friend class MemoryMapManager;
139
140 private:
143
144 public:
146 typedef int Permissions;
147
148 static const int None = 0x0;
149 static const int Read = 0x1;
150 static const int Write = 0x2;
151 static const int Exec = 0x4;
152
154 MemoryMappedObject(uintptr_t address, bool bCopyOnWrite, size_t length, Permissions perms,
155 Permissions maximumPerms = Read | Write | Exec)
156 : m_bCopyOnWrite(bCopyOnWrite),
159 m_Permissions(perms),
160 m_MaximumPermissions(maximumPerms),
161 m_Attachment(),
162 m_OwnerProcess(nullptr),
163 m_OwnsMappings(true),
164 m_LockMode(MemoryLockMode::None) {}
165
166 virtual ~MemoryMappedObject();
167
178 virtual MemoryMappedObject* clone() = 0;
179
185 virtual MemoryMappedObject* split(uintptr_t at) = 0;
186
188 virtual MemoryMappedObject* stageSlice(uintptr_t source, size_t sourceLength,
189 uintptr_t destination, size_t destinationLength) = 0;
190 void setMappingOwnership(bool ownsMappings) {
191 m_OwnsMappings = ownsMappings;
192 }
193 virtual void releaseDetachedPage(uintptr_t oldAddress,
194 const VirtualAddressSpace::DetachedPage& page) = 0;
195 virtual void discardRange(VirtualAddressSpace& space, uintptr_t base, size_t length) = 0;
196 virtual File* backingFile() const {
197 return nullptr;
198 }
199 virtual bool backingRangeValid(uintptr_t source, size_t length) const {
200 return true;
201 }
202 virtual bool resident(VirtualAddressSpace& space, uintptr_t address, FileResidencyAccess access,
203 void* credentials);
204
214 virtual bool remove(size_t length) = 0;
215
221 virtual void setPermissions(Permissions perms) = 0;
222
223 virtual bool preparePermissions(uintptr_t base, size_t length, Permissions perms) {
224 return true;
225 }
226
230 virtual bool sync(uintptr_t at, bool async) {
231 return true;
232 }
233
235 virtual bool syncRange(uintptr_t at, size_t length, bool async);
236
238 virtual void invalidate(uintptr_t at) {}
239
240 virtual bool sharedBacking(uintptr_t at, uintptr_t& identity, size_t& offset) const {
241 return false;
242 }
243
244 virtual bool usesBacking(uintptr_t identity) const {
245 return false;
246 }
247 virtual bool beyondBackingEnd(uintptr_t at) const {
248 return false;
249 }
250 virtual void discardFilePages(VirtualAddressSpace& space, size_t end) {}
251
258 virtual void unmap() = 0;
259
267 virtual bool trap(VirtualAddressSpace& space, uintptr_t address, bool bWrite,
268 PopulationStatus* population = nullptr) = 0;
269 virtual PopulationStatus prepareResidentAccess(VirtualAddressSpace& space, uintptr_t address) {
270 return PopulationStatus::Success;
271 }
272 PopulationStatus populatePage(VirtualAddressSpace& space, uintptr_t address);
273 MemoryLockMode lockMode() const {
274 return m_LockMode;
275 }
276
282 virtual bool supportsPageOut(VirtualAddressSpace& space, uintptr_t address) {
283 return false;
284 }
285 virtual SwapStatus pageOutAt(VirtualAddressSpace& space, uintptr_t address, bool& released) {
286 return SwapStatus::Unsupported;
287 }
288 virtual bool reclaimAnonymousPage(VirtualAddressSpace& space) {
289 return false;
290 }
291 virtual SwapStatus restoreSwapPages(VirtualAddressSpace& space) {
292 return SwapStatus::Success;
293 }
294 virtual bool compact() {
295 return false;
296 }
297
301 bool matches(uintptr_t address) {
302 return (m_Address <= address) && (address < (m_Address + m_Length));
303 }
304
308 uintptr_t address() const {
309 return m_Address;
310 }
311
315 size_t length() const {
316 return m_Length;
317 }
318
321 return m_Permissions;
322 }
323
324 Permissions maximumPermissions() const {
325 return m_MaximumPermissions;
326 }
327
328 protected:
337
344 uintptr_t m_Address;
345
352 size_t m_Length;
353
364 Permissions m_MaximumPermissions;
366 // The mapping gate protects registration; paging additionally admits a
367 // short scheduler lease before dereferencing this process identity.
368 Process* m_OwnerProcess;
369 bool m_OwnsMappings;
370 MemoryLockMode m_LockMode;
371};
372
381class EXPORTED_PUBLIC AnonymousMemoryMap : public MemoryMappedObject {
382 public:
383 AnonymousMemoryMap(uintptr_t address, size_t length, Permissions perms);
384
385 virtual ~AnonymousMemoryMap() override;
386#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
387 static void setCloneFailureForTest(ssize_t after);
388#endif
389
390 virtual MemoryMappedObject* clone() override;
391 virtual MemoryMappedObject* split(uintptr_t at) override;
392 MemoryMappedObject* stageSlice(uintptr_t source, size_t sourceLength, uintptr_t destination,
393 size_t destinationLength) override;
394 void releaseDetachedPage(uintptr_t oldAddress,
395 const VirtualAddressSpace::DetachedPage& page) override;
396 void discardRange(VirtualAddressSpace& space, uintptr_t base, size_t length) override;
397 virtual bool remove(size_t length) override;
398
399 virtual void setPermissions(MemoryMappedObject::Permissions perms) override;
400
401 virtual void unmap() override;
402
403 virtual bool trap(VirtualAddressSpace& space, uintptr_t address, bool bWrite,
404 PopulationStatus* population = nullptr) override;
405 bool supportsPageOut(VirtualAddressSpace& space, uintptr_t address) override;
406 SwapStatus pageOutAt(VirtualAddressSpace& space, uintptr_t address, bool& released) override;
407 bool reclaimAnonymousPage(VirtualAddressSpace& space) override {
408 return pageOut(space);
409 }
410 SwapStatus restoreSwapPages(VirtualAddressSpace& space) override {
411 return restoreAll(space);
412 }
413 PopulationStatus prepareResidentAccess(VirtualAddressSpace& space, uintptr_t address) override;
414
415 private:
416 friend class MemoryMapManager;
417 struct Page {
418 uintptr_t address = 0;
419 SwapReference slot;
420 bool pagingBlocked = false;
421 };
422 bool pageOut(VirtualAddressSpace& space);
423 SwapStatus restorePage(VirtualAddressSpace& space, Page& page);
424 SwapStatus restoreAll(VirtualAddressSpace& space);
425 static physical_uintptr_t m_Zero;
426 static bool initialisePhysicalPage(physical_uintptr_t physical);
427
428 void unmapUnlocked();
429
430 // Faults must not scan every previously populated page in a large mapping.
431 Tree<uintptr_t, Page> m_Mappings;
432};
433
443 friend class MemoryMapManager;
444
445 public:
447 uintptr_t address, size_t length, size_t offset, File* backing, bool bCopyOnWrite,
448 Permissions perms, Permissions maximumPerms = Read | Write | Exec,
450 const FileMappingOrigin& origin = {}, bool executableUse = false);
451
452 virtual ~MemoryMappedFile() override;
453
454 virtual MemoryMappedObject* clone() override;
455 virtual MemoryMappedObject* split(uintptr_t at) override;
456 MemoryMappedObject* stageSlice(uintptr_t source, size_t sourceLength, uintptr_t destination,
457 size_t destinationLength) override;
458 void releaseDetachedPage(uintptr_t oldAddress,
459 const VirtualAddressSpace::DetachedPage& page) override;
460 void discardRange(VirtualAddressSpace& space, uintptr_t base, size_t length) override;
461 File* backingFile() const override {
462 return m_pBacking;
463 }
464 bool backingRangeValid(uintptr_t source, size_t length) const override;
465 bool resident(VirtualAddressSpace& space, uintptr_t address, FileResidencyAccess access,
466 void* credentials) override;
467 virtual bool remove(size_t length) override;
468
469 virtual void setPermissions(MemoryMappedObject::Permissions perms) override;
470
471 virtual bool sync(uintptr_t at, bool async) override;
472 bool syncRange(uintptr_t at, size_t length, bool async) override;
473 virtual void invalidate(uintptr_t at) override;
474 virtual bool sharedBacking(uintptr_t at, uintptr_t& identity, size_t& offset) const override;
475 virtual bool usesBacking(uintptr_t identity) const override;
476 virtual bool beyondBackingEnd(uintptr_t at) const override;
477 virtual void discardFilePages(VirtualAddressSpace& space, size_t end) override;
478 virtual bool preparePermissions(uintptr_t base, size_t length, Permissions perms) override;
479
480 virtual void unmap() override;
481
482 virtual bool trap(VirtualAddressSpace& space, uintptr_t address, bool bWrite,
483 PopulationStatus* population = nullptr) override;
484
500 virtual bool compact() override;
501
502 private:
503 void unmapUnlocked();
504
505 physical_uintptr_t getBackingPage(size_t fileOffset, size_t mappingBytes);
506
507 void releaseDetachedPageUnlocked(uintptr_t oldAddress,
509
511 void trackMapping(uintptr_t, physical_uintptr_t);
512
514 void untrackMapping(uintptr_t);
515
517 physical_uintptr_t getMapping(uintptr_t);
518
520 size_t getMappingCount();
521
523 void clearMappings();
524
527
529 size_t m_Offset;
530
531 size_t m_ReadAheadEnd = ~size_t{0};
532 size_t m_ReadAheadPages = 4;
533
536 FileMappingOrigin m_Origin;
537
545
548 bool m_ExecutableUse;
549 bool m_SharedWriteUse;
550 bool m_UseAdmitted;
551};
552
557class EXPORTED_PUBLIC MemoryMapManager : public MemoryTrapHandler, public MemoryPressureHandler {
558 friend class PosixSubsystem;
559 friend class VfsUserMemoryPolicy;
560
561 public:
562 enum class Placement {
563 Hint,
564 FixedReplace,
565 FixedNoReplace,
566 };
567
568 enum class MapStatus {
569 Success,
570 NoMemory,
571 AddressInUse,
572 PolicyDenied,
573 TextBusy,
574 LockLimit,
575 };
576
577 enum class VmStatus { Success, InvalidRange, Unmapped, Unsupported, NoMemory, LockLimit };
578 enum class FileRemapStatus {
579 Success,
580 InvalidRange,
581 Unsupported,
582 NoMemory,
583 PolicyDenied,
584 LockLimit,
585 PermissionDenied
586 };
587 FileRemapStatus remapFilePages(uintptr_t base, size_t length, size_t byteOffset, bool nonblock);
589 uintptr_t source, destination;
590 size_t oldLength, newLength;
591 bool mayMove, fixed;
592 };
593 VmStatus remap(const RemapRequest& request, uintptr_t& result);
594 VmStatus residency(uintptr_t base, size_t length, unsigned char* kernelVector,
595 FileResidencyAccess access, void* credentials);
596 VmStatus discard(uintptr_t base, size_t length);
597
598 enum class UserPageCopyStatus { Success, Inaccessible, NoMemory, IoError, Unsupported };
599 UserPageCopyStatus copyUserPage(VirtualAddressSpace& space, uintptr_t userAddress,
600 void* kernelBuffer, size_t bytes, bool write);
601
602 PopulationStatus populateMemory(VirtualAddressSpace& space, uintptr_t base, size_t length);
603 void bindMemoryLockPolicy(VirtualAddressSpace& space);
604 MemoryLockStatus lockMemory(VirtualAddressSpace& space, uintptr_t base, size_t length,
605 MemoryLockMode mode, bool privileged);
606 MemoryLockStatus lockAllMemory(VirtualAddressSpace& space, bool current,
607 MemoryLockMode currentMode, MemoryLockMode futureMode,
608 bool privileged);
609 bool hasLockedMemory(VirtualAddressSpace& space, uintptr_t base, size_t length);
610
613 return m_Instance;
614 }
615
616#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
618 void acquireLifecycleGateForHostedTest();
619 void releaseLifecycleGateForHostedTest();
620 bool trapForHostedTest(uintptr_t address, bool bIsWrite, bool bWasPresent);
621 const void* lifecycleGateAddressForHostedTest() const {
622 return static_cast<const Semaphore*>(&m_LifecycleLock);
623 }
624#endif
625
629 MemoryMappedObject* mapFile(File* pFile, uintptr_t& address, size_t length,
630 MemoryMappedObject::Permissions perms, size_t offset = 0,
631 bool bCopyOnWrite = true);
632
634 bool hasSharedWriteCapability(File* backing);
635
636 MemoryMappedObject* mapFile(
637 File* pFile, uintptr_t& address, size_t length, MemoryMappedObject::Permissions perms,
638 size_t offset, bool bCopyOnWrite, Placement placement, MapStatus* status,
639 MemoryMappedObject::Permissions maximumPerms = MemoryMappedObject::Read |
640 MemoryMappedObject::Write |
641 MemoryMappedObject::Exec,
643 MemoryLockMode requestedLock = MemoryLockMode::None, const FileMappingOrigin& origin = {});
644
648 MemoryMappedObject* mapAnon(uintptr_t& address, size_t length,
650
651 MemoryMappedObject* mapAnon(uintptr_t& address, size_t length,
652 MemoryMappedObject::Permissions perms, Placement placement,
653 MapStatus* status,
654 MemoryLockMode requestedLock = MemoryLockMode::None);
655
661 bool clone(Process* pTarget);
662 SwapStatus pageOutRange(uintptr_t base, size_t length);
663 SwapStatus activateSwap(uint32_t endpoint);
664 SwapStatus deactivateSwap(uint32_t endpoint);
665 SwapSnapshot swapSnapshot();
666 bool operationOwnedByCurrentExecution();
667
677 size_t remove(uintptr_t base, size_t length);
678
686 size_t removeAndRelease(uintptr_t base, size_t length, VmStatus* status = nullptr);
687
689 SharedPointer<MappingAttachment> findAttachment(uintptr_t base);
690
692 size_t removeAttachment(const SharedPointer<MappingAttachment>& attachment);
693
700 enum class ProtectStatus {
701 Success,
702 Unmapped,
703 AccessDenied,
704 InvalidRange,
705 Unsupported,
706 NoMemory,
707 TextBusy
708 };
709
710 size_t setPermissions(uintptr_t base, size_t length, MemoryMappedObject::Permissions perms,
711 ProtectStatus* status = nullptr);
712
717 bool contains(uintptr_t base, size_t length);
718
723 bool allows(uintptr_t base, size_t length, MemoryMappedObject::Permissions permissions);
724
725 bool sharedBacking(Process* process, uintptr_t address, uintptr_t& identity, size_t& offset);
726
727 bool faultIn(uintptr_t address, bool write);
729 bool faultInRange(uintptr_t address, size_t length, bool write);
733 bool writableAnonymousRange(uintptr_t address, size_t length);
734
735 enum class FaultResolution { Unhandled, Resolved, BackingFault };
736 FaultResolution resolveUserFault(uintptr_t address, bool write, bool wasPresent, bool execute);
737
738 enum class ResizeStatus { Ready, NoMemory, Unsupported, Invalid };
740 public:
742 const Cache::DiscardReference* loans() const;
743 size_t loanCount() const;
744 size_t totalLoans() const;
745 void commit();
746
747 private:
748 friend class MemoryMapManager;
749 struct Data;
750 explicit PreparedFileResize(Data* data);
751 NOT_COPYABLE_OR_ASSIGNABLE(PreparedFileResize);
752 UniquePointer<Data> m_Data;
753 };
754
757 ResizeStatus prepareFileResize(File* file, size_t oldSize, size_t newSize,
759
764 bool sync(uintptr_t base, size_t length, bool async, int* error = nullptr);
765
767 void invalidate(uintptr_t base, size_t length);
768
772 void unmap(MemoryMappedObject* pObj);
773
777 void unmapAll();
778
782 virtual bool trap(InterruptState& state, uintptr_t address, bool bIsWrite, bool bWasPresent);
783
789 virtual bool compact();
790
791 virtual const char* getMemoryPressureDescription() {
792 return "Unmap safe pages from memory mapped files.";
793 }
794
795 protected:
801 void unmapAllUnlocked();
802
810 void acquireLock();
811
815 void releaseLock();
816
817 public:
826 public:
827 explicit OperationGuard(MemoryMapManager& manager, bool tryOnly = false);
829
830 explicit operator bool() const {
831 return m_Acquired;
832 }
833
834 private:
835 NOT_COPYABLE_OR_ASSIGNABLE(OperationGuard);
836
837 Uninterruptible m_EventDeferral;
838 MemoryMapManager& m_Manager;
839 bool m_Acquired;
840 };
841
842 private:
846
847 class LockPlan;
848 MemoryLockStatus prepareManagedLocks(VirtualAddressSpace& space, uintptr_t base, size_t length,
849 MemoryLockMode mode, bool all,
851 MemoryMappedObject* publishMapping(File* file, uintptr_t& address, size_t length,
852 MemoryMappedObject::Permissions perms, size_t offset,
853 bool copyOnWrite, Placement placement, MapStatus* status,
855 const SharedPointer<MappingAttachment>& attachment,
856 MemoryLockMode requestedLock,
857 const FileMappingOrigin& origin = {});
858 void retireLockedPages(VirtualAddressSpace& space, size_t pages);
859
860 void enterOperation();
861 bool tryEnterOperation();
862 void leaveOperation();
863
864 size_t removeInternal(uintptr_t base, size_t length, bool releaseReservations,
865 VmStatus* status = nullptr);
866 void releaseReservation(Process* process, VirtualAddressSpace& addressSpace, uintptr_t base,
867 size_t length);
868 bool faultInUnlocked(uintptr_t address, bool write, MemoryMappedObject*& selected,
869 bool residentAnonymousOnly = false);
870 bool accessRange(uintptr_t address, size_t length, bool write, bool residentAnonymousOnly);
871 bool handleTrapUnlocked(uintptr_t address, bool bIsWrite, bool bWasPresent, bool execute,
872 MemoryMappedObject* selected);
873 bool handleTrap(uintptr_t address, bool bIsWrite, bool bWasPresent, bool execute = false,
874 MemoryMappedObject* selected = nullptr);
875
876 enum Ops {
877 Sync,
878 Invalidate,
879 };
880
881 bool op(Ops what, uintptr_t base, size_t length, bool async);
882
885
887
890
893
899
902
903 void* m_pLifecycleOwner;
904 size_t m_LifecycleDepth;
905};
906
909#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