memmap.h (3529B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "types.h" 7 8 #include <map> 9 #include <string> 10 11 #if defined(_WIN32) 12 13 // eww :/ but better than including windows.h 14 enum class PageProtect : u32 15 { 16 NoAccess = 0x01, // PAGE_NOACCESS 17 ReadOnly = 0x02, // PAGE_READONLY 18 ReadWrite = 0x04, // PAGE_READWRITE 19 ReadExecute = 0x20, // PAGE_EXECUTE_READ 20 ReadWriteExecute = 0x40, // PAGE_EXECUTE_READWRITE 21 }; 22 23 #elif defined(__APPLE__) 24 25 #include <mach/mach_vm.h> 26 27 enum class PageProtect : u32 28 { 29 NoAccess = VM_PROT_NONE, 30 ReadOnly = VM_PROT_READ, 31 ReadWrite = VM_PROT_READ | VM_PROT_WRITE, 32 ReadExecute = VM_PROT_READ | VM_PROT_EXECUTE, 33 ReadWriteExecute = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, 34 }; 35 36 #else 37 38 #include <sys/mman.h> 39 40 enum class PageProtect : u32 41 { 42 NoAccess = PROT_NONE, 43 ReadOnly = PROT_READ, 44 ReadWrite = PROT_READ | PROT_WRITE, 45 ReadExecute = PROT_READ | PROT_EXEC, 46 ReadWriteExecute = PROT_READ | PROT_WRITE | PROT_EXEC, 47 }; 48 49 #endif 50 51 class Error; 52 53 namespace MemMap { 54 std::string GetFileMappingName(const char* prefix); 55 void* CreateSharedMemory(const char* name, size_t size, Error* error); 56 void DeleteSharedMemory(const char* name); 57 void DestroySharedMemory(void* ptr); 58 void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode); 59 void UnmapSharedMemory(void* baseaddr, size_t size); 60 bool MemProtect(void* baseaddr, size_t size, PageProtect mode); 61 62 /// Returns the base address for the current process. 63 const void* GetBaseAddress(); 64 65 /// Allocates RWX memory in branch range from the base address. 66 void* AllocateJITMemory(size_t size); 67 68 /// Releases RWX memory. 69 void ReleaseJITMemory(void* ptr, size_t size); 70 71 /// Flushes the instruction cache on the host for the specified range. 72 /// Only needed outside of X86, X86 has coherent D/I cache. 73 #if !defined(CPU_ARCH_ARM32) && !defined(CPU_ARCH_ARM64) && !defined(CPU_ARCH_RISCV64) 74 // clang-format off 75 ALWAYS_INLINE static void FlushInstructionCache(void* address, size_t size) { } 76 // clang-format on 77 #else 78 void FlushInstructionCache(void* address, size_t size); 79 #endif 80 81 /// JIT write protect for Apple Silicon. Needs to be called prior to writing to any RWX pages. 82 #if !defined(__APPLE__) || !defined(__aarch64__) 83 // clang-format off 84 ALWAYS_INLINE static void BeginCodeWrite() { } 85 ALWAYS_INLINE static void EndCodeWrite() { } 86 // clang-format on 87 #else 88 void BeginCodeWrite(); 89 void EndCodeWrite(); 90 #endif 91 } // namespace MemMap 92 93 class SharedMemoryMappingArea 94 { 95 public: 96 SharedMemoryMappingArea(); 97 ~SharedMemoryMappingArea(); 98 99 ALWAYS_INLINE size_t GetSize() const { return m_size; } 100 ALWAYS_INLINE size_t GetNumPages() const { return m_num_pages; } 101 102 ALWAYS_INLINE u8* BasePointer() const { return m_base_ptr; } 103 ALWAYS_INLINE u8* OffsetPointer(size_t offset) const { return m_base_ptr + offset; } 104 ALWAYS_INLINE u8* PagePointer(size_t page) const { return m_base_ptr + HOST_PAGE_SIZE * page; } 105 106 bool Create(size_t size); 107 void Destroy(); 108 109 u8* Map(void* file_handle, size_t file_offset, void* map_base, size_t map_size, PageProtect mode); 110 bool Unmap(void* map_base, size_t map_size); 111 112 private: 113 u8* m_base_ptr = nullptr; 114 size_t m_size = 0; 115 size_t m_num_pages = 0; 116 size_t m_num_mappings = 0; 117 118 #ifdef _WIN32 119 using PlaceholderMap = std::map<size_t, size_t>; 120 121 PlaceholderMap::iterator FindPlaceholder(size_t page); 122 123 PlaceholderMap m_placeholder_ranges; 124 #endif 125 };