The Pedigree Project 0.1
include/pedigree/kernel/processor/VirtualAddressSpace.h
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 KERNEL_PROCESSOR_VIRTUALADDRESSSPACE_H
21#define KERNEL_PROCESSOR_VIRTUALADDRESSSPACE_H
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/processor/UserMemoryPolicy.h"
25#include "pedigree/kernel/processor/types.h"
26#include "pedigree/kernel/utilities/Pointers.h"
27#include "pedigree/kernel/utilities/utility.h"
28
29#include <config.h>
30
39 public:
41 friend class Debugger;
42
43 class Stack;
44
47 static const size_t KernelMode = 0x01;
49 static const size_t Write = 0x02;
52 static const size_t Execute = 0x04;
54 static const size_t WriteThrough = 0x08;
56 static const size_t CacheDisable = 0x10;
58 static const size_t CopyOnWrite = 0x20;
60 static const size_t Swapped = 0x40;
62 static const size_t Shared = 0x200;
64 static const size_t WriteCombine = 0x400;
66 static const size_t Accessed = 0x800;
68 static const size_t Dirty = 0x1000;
70 static const size_t ClearDirty = 0x2000;
72 static const size_t NoAccess = 0x4000;
74 static const size_t WriteProtected = 0x8000;
76 static const size_t Borrowed = 0x10000;
78 static const size_t RuntimeMapping = 0x20000;
79
80 RawUserMemory& rawUserMemory() {
81 return m_RawUserMemory;
82 }
83 virtual size_t runtimeMappingPages(uintptr_t, size_t) {
84 return 0;
85 }
86 MemoryLockAccount* memoryLockAccount() const {
87 return m_MemoryLockAccount;
88 }
89 void setMemoryLockAccount(MemoryLockAccount* account) {
90 m_MemoryLockAccount = account;
91 }
92 UserMemoryPolicy* userMemoryPolicy() const {
93 return m_UserMemoryPolicy;
94 }
95 void setUserMemoryPolicy(UserMemoryPolicy* policy) {
96 m_UserMemoryPolicy = policy;
97 }
98
101 EXPORTED_PUBLIC static VirtualAddressSpace& getKernelAddressSpace();
102
108 virtual void* expandHeap(ssize_t incr, size_t flags);
109
113 virtual bool isAddressValid(void* virtualAddress) = 0;
119 virtual bool isMapped(void* virtualAddress) = 0;
120
130 virtual bool map(physical_uintptr_t physicalAddress, void* virtualAddress, size_t flags) = 0;
131 // Fallible user-page publication; the caller retains the page on failure.
132 // These checked paging helpers leave process accounting to the admitted owner.
133 // Report only new table pages committed by a successful publication.
134 virtual bool tryMapUserPage(physical_uintptr_t physical, void* address, size_t flags,
135 size_t* committedTablePages = nullptr) {
136 if (committedTablePages)
137 *committedTablePages = 0;
138 return false;
139 }
140 // Detach only the expected, access-revoked user page. No ownership transfers
141 // until success, including host mapping failures.
142 virtual bool tryDetachUserPage(void* address, physical_uintptr_t expected) {
143 return false;
144 }
152 virtual bool mapHuge(physical_uintptr_t physAddress, void* virtualAddress, size_t count,
153 size_t flags);
159 virtual bool getMapping(void* virtualAddress, physical_uintptr_t& physicalAddress,
160 size_t& flags) = 0;
161
172 virtual bool handleCopyOnWriteFault(void* virtualAddress, bool userMode) = 0;
173
174 enum class ResidentCopyStatus { Success, Inaccessible, Unsupported };
175
177 virtual ResidentCopyStatus copyResidentUserPage(uintptr_t userAddress, void* kernelBuffer,
178 size_t bytes, bool write) {
179 (void)userAddress;
180 (void)kernelBuffer;
181 (void)bytes;
182 (void)write;
183 return ResidentCopyStatus::Unsupported;
184 }
185
191 virtual bool tryWriteUser32(uintptr_t address, uint32_t value) {
192 (void)address;
193 (void)value;
194 return false;
195 }
196
198 virtual bool tryReadUser32(uintptr_t address, uint32_t& value) {
199 (void)address;
200 (void)value;
201 return false;
202 }
203
204 virtual bool tryReadUserPointer(uintptr_t address, uintptr_t& value) {
205 (void)address;
206 (void)value;
207 return false;
208 }
209
211 virtual bool tryCompareExchangeUser32(uintptr_t address, uint32_t& expected, uint32_t desired,
212 bool& exchanged) {
213 (void)address;
214 (void)expected;
215 (void)desired;
216 exchanged = false;
217 return false;
218 }
219
220#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
221 using CopyOnWritePreCommitHook = void (*)(void*);
222
224 static EXPORTED_PUBLIC void setCopyOnWritePreCommitHookForTest(CopyOnWritePreCommitHook hook);
225#endif
226
231 virtual void setFlags(void* virtualAddress, size_t newFlags) = 0;
232
234 MUST_USE_RESULT virtual bool trySetFlags(void* virtualAddress, size_t newFlags) {
235 (void)virtualAddress;
236 (void)newFlags;
237 return false;
238 }
243 virtual void unmap(void* virtualAddress) = 0;
244
247 virtual bool detachMapping(void* virtualAddress, physical_uintptr_t& physical, size_t& flags,
248 size_t requiredFlags = 0) {
249 physical = 0;
250 flags = 0;
251 return false;
252 }
253
254 enum class RemapStatus { Success, InvalidRange, Unsupported, NoMemory, Retry };
255 static constexpr size_t MaximumRemapPages = 65536;
256 struct RemapRange {
257 uintptr_t base;
258 size_t length;
259 };
261 uintptr_t source, destination;
262 size_t oldLength, newLength;
263 bool replace;
264 const RemapRange* victims = nullptr;
265 size_t victimCount = 0;
266 };
268 uintptr_t address;
269 physical_uintptr_t physical;
270 size_t flags;
271 bool mapped;
272 };
273 using RemapAdmission = bool (*)(void* context);
275 public:
276 virtual ~PreparedPageRemap() = default;
278 virtual RemapStatus commit(RemapAdmission admission, void* context) = 0;
279 virtual const DetachedPage* detachedPages() const = 0;
280 virtual size_t detachedPageCount() const = 0;
281 };
283 virtual RemapStatus prepareRemap(const PageRemapRequest& request,
285 (void)request;
286 plan.reset();
287 return RemapStatus::Unsupported;
288 }
289
291 virtual void setRemapPreparationFailureForTest(ssize_t allocations) {
292 (void)allocations;
293 }
294
297 virtual Stack* allocateStack() = 0;
299 virtual Stack* allocateStack(size_t stackSz) {
300 // Default implementation just ignores the stack size.
301 return allocateStack();
302 }
304 virtual void freeStack(Stack* pStack) = 0;
305
309 static VirtualAddressSpace* create();
310
316 virtual VirtualAddressSpace* clone(bool copyOnWrite = true) = 0;
317
321 virtual void revertToKernelAddressSpace() = 0;
322
324 inline virtual ~VirtualAddressSpace() {}
325
327 void setHeap(void* heap, void* heapEnd) {
328 m_Heap = heap;
329 m_HeapEnd = heapEnd;
330 }
331
334 virtual bool memIsInKernelHeap(void* pMem) = 0;
335
338 virtual bool memIsInHeap(void* pMem) = 0;
339
341 virtual void* getEndOfHeap() = 0;
342
344 virtual uintptr_t getKernelStart() const = 0;
345
347 virtual uintptr_t getUserStart() const = 0;
348
350 virtual uintptr_t getUserReservedStart() const = 0;
351
353 virtual uintptr_t getDynamicLinkerAddress() const = 0;
354
356 virtual uintptr_t getKernelHeapStart() const = 0;
357
359 virtual uintptr_t getKernelHeapEnd() const = 0;
360
362 virtual uintptr_t getKernelCacheStart() const = 0;
363
365 virtual uintptr_t getKernelCacheEnd() const = 0;
366
368 virtual uintptr_t getKernelEventBlockStart() const = 0;
369
371 virtual uintptr_t getKernelModulesStart() const = 0;
372
374 virtual uintptr_t getKernelModulesEnd() const = 0;
375
377 virtual uintptr_t getKernelVirtualPagestack() const {
378 return 0;
379 }
380
382 virtual uintptr_t getKernelVirtualPagestackAdd1() const {
383 return 0;
384 }
385
387 virtual uintptr_t getKernelVirtualPagestackAdd2() const {
388 return 0;
389 }
390
398 virtual uintptr_t getDynamicStart() const {
399 return 0;
400 }
402 virtual uintptr_t getDynamicEnd() const {
403 return 0;
404 }
405
407 virtual uintptr_t getGlobalInfoBlock() const {
408 return 0;
409 }
410
412 void* m_Heap;
416 static physical_uintptr_t m_ZeroPage;
417
419 class Stack {
420 public:
421 Stack(void* top, size_t size, uint64_t regionId = 0)
422 : m_Top(top), m_Size(size), m_RegionId(regionId) {}
423 uint64_t regionId() const {
424 return m_RegionId;
425 }
426
427 void* getTop() const {
428 return m_Top;
429 }
430
431 void* getBase() const {
432 if (m_Top) {
433 return adjust_pointer(m_Top, -m_Size);
434 } else {
435 return nullptr;
436 }
437 }
438
439 size_t getSize() const {
440 return m_Size;
441 }
442
443 operator void*() const {
444 return m_Top;
445 }
446
447 private:
448 void* m_Top;
449 size_t m_Size;
450 uint64_t m_RegionId;
451 };
452
453 protected:
454 bool admitRawMemoryChange(const PreparedMemoryLock& plan, bool privileged,
455 MemoryLockCharge& charge) const;
456 void commitRawMemoryChange(PreparedMemoryLock& plan, MemoryLockCharge charge);
457 bool prepareZeroPage();
458 uint64_t m_HeapRegionId = 0;
459
461 inline VirtualAddressSpace(void* Heap) : m_Heap(Heap), m_HeapEnd(Heap), m_RawUserMemory(*this) {}
462
463#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
464 static void copyOnWritePreCommitForTest(void* virtualAddress);
465#endif
466
467 private:
468 RawUserMemory m_RawUserMemory;
469 MemoryLockAccount* m_MemoryLockAccount = nullptr;
470 UserMemoryPolicy* m_UserMemoryPolicy = nullptr;
471
480
481#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
482 static CopyOnWritePreCommitHook m_CopyOnWritePreCommitHook;
483#endif
484
488 void rollbackHeapExpansion(void* virtualAddress, size_t pageCount);
489};
490
493#endif
virtual RemapStatus commit(RemapAdmission admission, void *context)=0
virtual void setFlags(void *virtualAddress, size_t newFlags)=0
static VirtualAddressSpace * create()
virtual void setRemapPreparationFailureForTest(ssize_t allocations)
virtual uintptr_t getUserReservedStart() const =0
virtual uintptr_t getKernelCacheEnd() const =0
virtual uintptr_t getDynamicLinkerAddress() const =0
virtual uintptr_t getKernelHeapStart() const =0
virtual void freeStack(Stack *pStack)=0
virtual Stack * allocateStack()=0
virtual bool mapHuge(physical_uintptr_t physAddress, void *virtualAddress, size_t count, size_t flags)
VirtualAddressSpace(const VirtualAddressSpace &)
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
virtual bool tryWriteUser32(uintptr_t address, uint32_t value)
virtual bool tryCompareExchangeUser32(uintptr_t address, uint32_t &expected, uint32_t desired, bool &exchanged)
virtual uintptr_t getKernelCacheStart() const =0
virtual bool isMapped(void *virtualAddress)=0
virtual void revertToKernelAddressSpace()=0
virtual uintptr_t getUserStart() const =0
virtual bool handleCopyOnWriteFault(void *virtualAddress, bool userMode)=0
virtual bool memIsInKernelHeap(void *pMem)=0
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)=0
virtual uintptr_t getKernelModulesEnd() const =0
VirtualAddressSpace & operator=(const VirtualAddressSpace &)
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual bool detachMapping(void *virtualAddress, physical_uintptr_t &physical, size_t &flags, size_t requiredFlags=0)
virtual ResidentCopyStatus copyResidentUserPage(uintptr_t userAddress, void *kernelBuffer, size_t bytes, bool write)
virtual RemapStatus prepareRemap(const PageRemapRequest &request, UniquePointer< PreparedPageRemap > &plan)
virtual uintptr_t getKernelHeapEnd() const =0
virtual bool memIsInHeap(void *pMem)=0
virtual uintptr_t getKernelStart() const =0
virtual MUST_USE_RESULT bool trySetFlags(void *virtualAddress, size_t newFlags)
void rollbackHeapExpansion(void *virtualAddress, size_t pageCount)
virtual void * getEndOfHeap()=0
virtual void unmap(void *virtualAddress)=0
virtual VirtualAddressSpace * clone(bool copyOnWrite=true)=0
virtual void * expandHeap(ssize_t incr, size_t flags)
virtual bool isAddressValid(void *virtualAddress)=0
virtual bool tryReadUser32(uintptr_t address, uint32_t &value)
virtual uintptr_t getKernelModulesStart() const =0
virtual uintptr_t getKernelEventBlockStart() const =0
uintptr_t physicalAddress(physical_uintptr_t address) PURE
Definition utils.h:39