duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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 };