// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once #include "types.h" #include #include #if defined(_WIN32) // eww :/ but better than including windows.h enum class PageProtect : u32 { NoAccess = 0x01, // PAGE_NOACCESS ReadOnly = 0x02, // PAGE_READONLY ReadWrite = 0x04, // PAGE_READWRITE ReadExecute = 0x20, // PAGE_EXECUTE_READ ReadWriteExecute = 0x40, // PAGE_EXECUTE_READWRITE }; #elif defined(__APPLE__) #include enum class PageProtect : u32 { NoAccess = VM_PROT_NONE, ReadOnly = VM_PROT_READ, ReadWrite = VM_PROT_READ | VM_PROT_WRITE, ReadExecute = VM_PROT_READ | VM_PROT_EXECUTE, ReadWriteExecute = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, }; #else #include enum class PageProtect : u32 { NoAccess = PROT_NONE, ReadOnly = PROT_READ, ReadWrite = PROT_READ | PROT_WRITE, ReadExecute = PROT_READ | PROT_EXEC, ReadWriteExecute = PROT_READ | PROT_WRITE | PROT_EXEC, }; #endif class Error; namespace MemMap { std::string GetFileMappingName(const char* prefix); void* CreateSharedMemory(const char* name, size_t size, Error* error); void DeleteSharedMemory(const char* name); void DestroySharedMemory(void* ptr); void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, PageProtect mode); void UnmapSharedMemory(void* baseaddr, size_t size); bool MemProtect(void* baseaddr, size_t size, PageProtect mode); /// Returns the base address for the current process. const void* GetBaseAddress(); /// Allocates RWX memory in branch range from the base address. void* AllocateJITMemory(size_t size); /// Releases RWX memory. void ReleaseJITMemory(void* ptr, size_t size); /// Flushes the instruction cache on the host for the specified range. /// Only needed outside of X86, X86 has coherent D/I cache. #if !defined(CPU_ARCH_ARM32) && !defined(CPU_ARCH_ARM64) && !defined(CPU_ARCH_RISCV64) // clang-format off ALWAYS_INLINE static void FlushInstructionCache(void* address, size_t size) { } // clang-format on #else void FlushInstructionCache(void* address, size_t size); #endif /// JIT write protect for Apple Silicon. Needs to be called prior to writing to any RWX pages. #if !defined(__APPLE__) || !defined(__aarch64__) // clang-format off ALWAYS_INLINE static void BeginCodeWrite() { } ALWAYS_INLINE static void EndCodeWrite() { } // clang-format on #else void BeginCodeWrite(); void EndCodeWrite(); #endif } // namespace MemMap class SharedMemoryMappingArea { public: SharedMemoryMappingArea(); ~SharedMemoryMappingArea(); ALWAYS_INLINE size_t GetSize() const { return m_size; } ALWAYS_INLINE size_t GetNumPages() const { return m_num_pages; } ALWAYS_INLINE u8* BasePointer() const { return m_base_ptr; } ALWAYS_INLINE u8* OffsetPointer(size_t offset) const { return m_base_ptr + offset; } ALWAYS_INLINE u8* PagePointer(size_t page) const { return m_base_ptr + HOST_PAGE_SIZE * page; } bool Create(size_t size); void Destroy(); u8* Map(void* file_handle, size_t file_offset, void* map_base, size_t map_size, PageProtect mode); bool Unmap(void* map_base, size_t map_size); private: u8* m_base_ptr = nullptr; size_t m_size = 0; size_t m_num_pages = 0; size_t m_num_mappings = 0; #ifdef _WIN32 using PlaceholderMap = std::map; PlaceholderMap::iterator FindPlaceholder(size_t page); PlaceholderMap m_placeholder_ranges; #endif };