36inline constexpr u32 kPageSize4KiB = 4 * 1024;
41inline constexpr u32 kPageSize16MiB = 16 * 1024 * 1024;
45namespace rex::kernel::detail {
52template <
typename T,
bool IsOpaque = std::is_
void_v<T> || std::is_function_v<T>>
53struct PointeeAlignment {
54 static constexpr u32 kValue = 1;
59struct PointeeAlignment<T, false> {
60 static constexpr u32 kValue =
static_cast<u32
>(
alignof(T));
73 kSystemHeapVirtual = 1 << 0,
74 kSystemHeapPhysical = 1 << 1,
76 kSystemHeapDefault = kSystemHeapVirtual,
90 u32 system_heap_flags = kSystemHeapDefault) = 0;
97 virtual void SystemHeapFree(u32 address, u32* out_region_size =
nullptr) = 0;
99 [[nodiscard]]
virtual bool IsAddressMapped(u32 address)
const = 0;
112 virtual u32
AllocPhysical(u32 size, u32 page_size, u32 protect, u32 min_address, u32 max_address,
123 kMemoryAllocationReserve = 1 << 0,
124 kMemoryAllocationCommit = 1 << 1,
129enum MemoryProtectFlag : u8 {
130 kMemoryProtectRead = 1 << 0,
131 kMemoryProtectWrite = 1 << 1,
132 kMemoryProtectNoCache = 1 << 2,
133 kMemoryProtectWriteCombine = 1 << 3,
135 kMemoryProtectNoAccess = 0,
181 u32 GetHeapSize()
const {
return heap_size_; }
183 u32 GetPageSize()
const {
return page_size_; }
185 HeapType GetHeapType()
const {
return heap_type_; }
193 template <
typename T = u8*>
201 u32 GetTotalPageCount()
const {
return static_cast<u32
>(page_table_.size()); }
203 u32 GetUnreservedPageCount()
const {
return unreserved_page_count_; }
205 u32 GetReservedPageCount()
const {
return GetTotalPageCount() - GetUnreservedPageCount(); }
207 u32 GetCommittedPages()
const {
return committed_pages_.load(std::memory_order_relaxed); }
222 virtual bool Alloc(u32 size, u32 alignment, u32 allocation_type, u32 protect,
bool top_down,
232 virtual bool AllocFixed(u32 base_address, u32 size, u32 alignment, u32 allocation_type,
243 virtual bool AllocRange(u32 low_address, u32 high_address, u32 size, u32 alignment,
244 u32 allocation_type, u32 protect,
bool top_down, u32* out_address);
254 virtual bool AllocSystemHeap(u32 size, u32 alignment, u32 allocation_type, u32 protect,
255 bool top_down, u32* out_address);
265 virtual bool Release(u32 address, u32* out_region_size =
nullptr);
276 bool ReleaseRange(u32 address, u32 size, u32* out_address, u32* out_size);
284 virtual bool Protect(u32 address, u32 size, u32 protect, u32* old_protect =
nullptr);
329 friend class PhysicalHeap;
365 bool AllocFixedLocked(u32 base_address, u32 size, u32 alignment, u32 allocation_type,
368 bool AllocRangeLocked(u32 low_address, u32 high_address, u32 size, u32 alignment,
369 u32 allocation_type, u32 protect,
bool top_down, u32* out_address);
371 bool DecommitLocked(u32 address, u32 size);
373 bool ReleaseLocked(u32 address, u32* out_region_size);
375 bool ReleaseRangeLocked(u32 address, u32 size, u32* out_address, u32* out_size);
377 bool ProtectLocked(u32 address, u32 size, u32 protect, u32* old_protect);
416 u32 heap_size, u32 page_size, u32 host_address_offset = 0);
429 u32 unreserved_page_count_ = 0;
434 const char* profile_plot_ =
nullptr;
436 std::vector<PageEntry> page_table_;
442 ~VirtualHeap()
override;
450 u32 heap_size, u32 page_size);
460 ~PhysicalHeap()
override;
469 u32 heap_size, u32 page_size,
VirtualHeap* parent_heap);
479 bool Alloc(u32 size, u32 alignment, u32 allocation_type, u32 protect,
bool top_down,
480 u32* out_address)
override;
488 bool AllocFixed(u32 base_address, u32 size, u32 alignment, u32 allocation_type,
489 u32 protect)
override;
498 bool AllocRange(u32 low_address, u32 high_address, u32 size, u32 alignment, u32 allocation_type,
499 u32 protect,
bool top_down, u32* out_address)
override;
508 bool AllocSystemHeap(u32 size, u32 alignment, u32 allocation_type, u32 protect,
bool top_down,
509 u32* out_address)
override;
517 bool Release(u32 base_address, u32* out_region_size =
nullptr)
override;
525 bool Protect(u32 address, u32 size, u32 protect, u32* old_protect =
nullptr)
override;
534 bool enable_invalidation_notifications,
bool enable_data_providers);
542 bool TriggerCallbacks(u32 virtual_address, u32 length,
bool is_write,
bool unwatch_exact_range,
543 bool unprotect =
true);
545 bool TriggerCallbacksLocked(u32 virtual_address, u32 length,
bool is_write,
546 bool unwatch_exact_range,
bool unprotect =
true);
568 u32 system_page_size_;
608 const std::filesystem::path&
GetFileName()
const {
return file_name_; }
610 u8* GetVirtualMembase()
const {
return virtual_membase_; }
621 template <
typename T = u8*>
623 assert(!LookupHeap(guest_address) ||
624 LookupHeap(guest_address)->GetHostAddressOffset() ==
625 rex::memory::detail::PhysicalHostOffset(guest_address));
636 template <
typename T = u8*>
638 static_assert(std::is_pointer_v<T>,
"TryTranslateVirtual returns a pointer type");
639 constexpr u32 kAlignment = detail::PointeeAlignment<std::remove_pointer_t<T>>::kValue;
640 if (guest_address == 0 || guest_address % kAlignment != 0) {
643 const BaseHeap* heap = LookupHeap(guest_address);
645 if (heap ==
nullptr || !
const_cast<BaseHeap*
>(heap)->QueryProtect(guest_address, &protect) ||
646 (protect & required) != required) {
652 u8* GetPhysicalMembase()
const {
return physical_membase_; }
655 template <
typename T = u8*>
657 return reinterpret_cast<T
>(physical_membase_ + (guest_address & 0x1FFFFFFF));
671 void Zero(u32 address, u32 size)
const;
673 void Fill(u32 address, u32 size, u8 value)
const;
676 void Copy(u32 dest, u32 src, u32 size)
const;
704 u32 physical_address_start,
705 u32 length,
bool exact_range);
712 void* callback_context);
724 bool enable_invalidation_notifications,
725 bool enable_data_providers);
734 u32 system_heap_flags = kSystemHeapDefault)
override;
738 u32
AllocPhysical(u32 size, u32 page_size, u32 protect, u32 min_address, u32 max_address,
739 u32 alignment)
override;
741 bool IsAddressMapped(u32 address)
const override {
return LookupHeap(address) !=
nullptr; }
743 const BaseHeap* LookupHeap(u32 address)
const;
750 BaseHeap* LookupHeapByType(
bool physical, u32 page_size);
759 u32& unreserved_pages, u32& reserved_pages, u32& used_pages,
760 u32& reserved_bytes);
811 [[nodiscard]] std::unique_lock<rex::platform::RankedMutex>
LockWatches() {
812 return std::unique_lock(watch_mutex_);
819 int MapViews(u8* mapping_base);
821 bool ReserveMMIOBlocks()
const;
823 bool AccessViolationCallback(
void* host_address,
bool is_write);
831 bool ReserveBudgetPages(u32 pages);
836 void ReleaseBudgetPages(u32 pages);
838 std::filesystem::path file_name_;
839 u32 system_page_size_ = 0;
840 u32 system_allocation_granularity_ = 0;
841 u8* virtual_membase_ =
nullptr;
842 u8* physical_membase_ =
nullptr;
844 struct FunctionTableEntry {
850 std::vector<FunctionTableEntry> function_tables_;
851 mutable std::mutex function_tables_mutex_;
854 u8* mapping_base_ =
nullptr;
868 } views_ = {{0, 0, 0, 0, 0, 0, 0, 0, 0}};
871 VirtualHeap v00000000;
872 VirtualHeap v40000000;
873 VirtualHeap v80000000;
874 VirtualHeap v90000000;
876 VirtualHeap physical;
877 PhysicalHeap va0000000;
878 PhysicalHeap vc0000000;
879 PhysicalHeap ve0000000;
882 friend class BaseHeap;
883 friend class GuestAllocator;
884 friend class WorkspaceHeap;
886 friend class PhysicalHeap;
888 std::vector<std::unique_ptr<std::pair<PhysicalMemoryInvalidationCallback, void*>>>
889 physical_memory_invalidation_callbacks_;
890 std::atomic<u32> title_pages_{0};
891 std::atomic<u32> budget_pages_{0};
892 std::mutex allocators_mutex_;
893 std::vector<GuestAllocator*> allocators_;
894 std::vector<const WorkspaceHeap*> workspaces_;
virtual bool AllocSystemHeap(u32 size, u32 alignment, u32 allocation_type, u32 protect, bool top_down, u32 *out_address)
const char * profile_pool_
Definition heap.h:433
std::atomic< u32 > committed_pages_
Definition heap.h:431
u32 GetHostAddressOffset() const
Definition heap.h:190
u32 host_address_offset_
Definition heap.h:428
void OnPageCommitted(u32 page_number)
rex::memory::PageAccess QueryRangeAccess(u32 low_address, u32 high_address)
bool QueryRegionInfo(u32 base_address, HeapAllocation *out_info)
bool ReapplyHostPageAccess(void *host_address, bool is_write)
u32 page_size_shift_
Definition heap.h:426
virtual bool AllocRange(u32 low_address, u32 high_address, u32 size, u32 alignment, u32 allocation_type, u32 protect, bool top_down, u32 *out_address)
virtual bool Protect(u32 address, u32 size, u32 protect, u32 *old_protect=nullptr)
bool QueryProtect(u32 address, u32 *out_protect)
bool CheckProtectRangeLocked(u32 address, u32 size, u32 *out_start_page, u32 *out_end_page)
void Initialize(kernel::GuestAddressSpace *memory, u8 *membase, HeapType heap_type, u32 heap_base, u32 heap_size, u32 page_size, u32 host_address_offset=0)
virtual bool Release(u32 address, u32 *out_region_size=nullptr)
rex::memory::PageAccess GetHostPageAccess(u32 host_page_number) const
virtual bool AllocFixed(u32 base_address, u32 size, u32 alignment, u32 allocation_type, u32 protect)
bool ReleaseRange(u32 address, u32 size, u32 *out_address, u32 *out_size)
kernel::GuestAddressSpace * memory_
Definition heap.h:419
T TranslateRelative(size_t relative_address) const
Definition heap.h:194
rex::memory::PageAccess GetHostPageGuestAccess(u32 host_page_number) const
void OnPageDecommitted(u32 page_number)
virtual bool IsHostPageWriteWatched(u32 host_page_number) const
Definition heap.h:397
virtual std::unique_lock< rex::platform::RankedMutex > AcquireHostPageReconcileLock() const
u32 GetSystemRangeBase() const
bool QuerySize(u32 address, u32 *out_size)
virtual bool Decommit(u32 address, u32 size)
u32 GetHeapBase() const
Definition heap.h:179
std::recursive_mutex heap_mutex_
Definition heap.h:435
virtual bool Alloc(u32 size, u32 alignment, u32 allocation_type, u32 protect, bool top_down, u32 *out_address)
bool SyncHostPageAccess(u32 start_page_number, u32 end_page_number)
T TranslatePhysical(u32 guest_address) const
Definition heap.h:656
bool DestroyFunctionTable(u32 code_base)
bool SetFunction(u32 guest_address, PPCFunc *host_function)
std::pair< u32, u32 >(*)(void *context_ptr, u32 physical_address_start, u32 length, bool exact_range) PhysicalMemoryInvalidationCallback
Definition heap.h:703
AccessViolationResult HandleAccessViolation(void *host_address, bool is_write)
u32 GetBudgetPages() const
std::unique_lock< rex::platform::RankedMutex > LockWatches()
Definition heap.h:811
const std::filesystem::path & GetFileName() const
Definition heap.h:608
u32 SystemHeapAlloc(u32 size, u32 alignment=0x20, u32 system_heap_flags=kSystemHeapDefault) override
void GetHeapsPageStats(const BaseHeap *const *provided_heaps, size_t heaps_count, u32 &unreserved_pages, u32 &reserved_pages, u32 &used_pages, u32 &reserved_bytes)
u32 GetPhysicalAddress(u32 address) const
void EnablePhysicalMemoryAccessCallbacks(u32 physical_address, u32 length, bool enable_invalidation_notifications, bool enable_data_providers)
void SetBudget(u32 megabytes)
void * RegisterPhysicalMemoryInvalidationCallback(PhysicalMemoryInvalidationCallback callback, void *callback_context)
u32 AllocPhysical(u32 size, u32 page_size, u32 protect, u32 min_address, u32 max_address, u32 alignment) override
void Copy(u32 dest, u32 src, u32 size) const
u32 HostToGuestVirtual(const void *host_address) const
T TranslateVirtual(u32 guest_address) const
Definition heap.h:622
T TryTranslateVirtual(u32 guest_address, u32 required=kMemoryProtectRead) const
Definition heap.h:637
u32 GetTitlePages() const
void SystemHeapFree(u32 address, u32 *out_region_size=nullptr) override
rex::memory::GuestMembase GetMembase() const
Definition heap.h:613
bool InitializeFunctionTable(u32 code_base, u32 code_size, u32 image_base, u32 image_size)
void UnregisterPhysicalMemoryInvalidationCallback(void *callback_handle)
Definition guest_allocator.h:49
virtual u32 AllocPhysical(u32 size, u32 page_size, u32 protect, u32 min_address, u32 max_address, u32 alignment)=0
virtual u32 SystemHeapAlloc(u32 size, u32 alignment=0x20, u32 system_heap_flags=kSystemHeapDefault)=0
virtual void SystemHeapFree(u32 address, u32 *out_region_size=nullptr)=0
std::unique_lock< rex::platform::RankedMutex > AcquireHostPageReconcileLock() const override
bool Protect(u32 address, u32 size, u32 protect, u32 *old_protect=nullptr) override
bool Release(u32 base_address, u32 *out_region_size=nullptr) override
bool Decommit(u32 address, u32 size) override
bool AllocSystemHeap(u32 size, u32 alignment, u32 allocation_type, u32 protect, bool top_down, u32 *out_address) override
void EnableAccessCallbacks(u32 physical_address, u32 length, bool enable_invalidation_notifications, bool enable_data_providers)
bool AllocFixed(u32 base_address, u32 size, u32 alignment, u32 allocation_type, u32 protect) override
VirtualHeap * parent_heap_
Definition heap.h:566
bool TriggerCallbacks(u32 virtual_address, u32 length, bool is_write, bool unwatch_exact_range, bool unprotect=true)
bool IsHostPageWriteWatched(u32 host_page_number) const override
bool Alloc(u32 size, u32 alignment, u32 allocation_type, u32 protect, bool top_down, u32 *out_address) override
u32 system_page_count_
Definition heap.h:570
bool AllocRange(u32 low_address, u32 high_address, u32 size, u32 alignment, u32 allocation_type, u32 protect, bool top_down, u32 *out_address) override
void Initialize(kernel::GuestAddressSpace *memory, u8 *membase, HeapType heap_type, u32 heap_base, u32 heap_size, u32 page_size, VirtualHeap *parent_heap)
u32 GetPhysicalAddress(u32 address) const
std::vector< SystemPageFlagsBlock > system_page_flags_
Definition heap.h:578
void Initialize(kernel::GuestAddressSpace *memory, u8 *membase, HeapType heap_type, u32 heap_base, u32 heap_size, u32 page_size)
Definition guest_allocator.h:179
Definition mapped_ptr.h:412
AccessViolationResult
Definition heap.h:581
@ kUnhandled
Definition heap.h:587
@ kMMIOMiss
Definition heap.h:585
@ kResumed
Definition heap.h:583
MemoryAllocationFlag
Definition heap.h:122
@ kMemoryAllocationTitle
Definition heap.h:126
HeapType
Definition heap.h:116
@ kGuestXEX
Definition heap.h:118
constexpr u32 kPageSize64KiB
Definition heap.h:39
SystemHeapFlag
Definition heap.h:72
int FileMappingHandle
Definition virtual_memory.h:148
T GuestPtr(u8 *base, u32 guest_address) noexcept
Definition mapped_ptr.h:393
constexpr FileMappingHandle kFileMappingHandleInvalid
Definition virtual_memory.h:150
u32 allocation_protect
Definition heap.h:144
u32 allocation_base
Definition heap.h:142
u32 protect
Definition heap.h:151
u32 state
Definition heap.h:150
u32 allocation_size
Definition heap.h:146
u32 region_size
Definition heap.h:148
u32 base_address
Definition heap.h:140
u64 notify_on_invalidation
Definition heap.h:575
Integer types, byte order wrappers and size literals.
u64 qword
Definition heap.h:155