diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 10c8022ed1..4179a95eb2 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -203,7 +203,7 @@ public: virtual_base = static_cast(pfn_VirtualAlloc2 (process, nullptr, virtual_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0)); } - + virtual_map_base = virtual_base; if (!virtual_base) { Release(); LOG_CRITICAL(HW_Memory, "Failed to reserve {} GiB of virtual memory", virtual_size >> 30); @@ -217,6 +217,7 @@ public: } void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) { + AdjustMap(virtual_map_base, virtual_size, &virtual_offset, &length); std::unique_lock lock{placeholder_mutex}; if (!IsNiechePlaceholder(virtual_offset, length)) { Split(virtual_offset, length); @@ -228,6 +229,7 @@ public: } void Unmap(size_t virtual_offset, size_t length) { + AdjustMap(virtual_map_base, virtual_size, &virtual_offset, &length); std::scoped_lock lock{placeholder_mutex}; // Unmap until there are no more placeholders @@ -236,15 +238,21 @@ public: } void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) { + AdjustMap(virtual_map_base, virtual_size, &virtual_offset, &length); + DWORD new_flags{}; - if (read && write) { + if (read && write && execute) { + new_flags = PAGE_EXECUTE_READWRITE; + } else if (read && write) { new_flags = PAGE_READWRITE; + } else if (read && execute) { + new_flags = PAGE_EXECUTE_READ; } else if (read && !write) { new_flags = PAGE_READONLY; - } else if (!read && !write) { + } else if (!read && !write && !execute) { new_flags = PAGE_NOACCESS; } else { - UNIMPLEMENTED_MSG("Protection flag combination read={} write={}", read, write); + UNIMPLEMENTED_MSG("Protection flag combination read={} write={} execute={}", read, write, execute); } const size_t virtual_end = virtual_offset + length; @@ -263,7 +271,7 @@ public: void EnableDirectMappedAddress() { // TODO - UNREACHABLE(); + virtual_base = nullptr; } const size_t backing_size; ///< Size of the backing memory in bytes @@ -271,6 +279,7 @@ public: u8* backing_base{}; u8* virtual_base{}; + u8* virtual_map_base{}; private: /// Release all resources in the object @@ -284,8 +293,8 @@ private: } Coalesce(0, virtual_size); } - if (virtual_base) { - if (!VirtualFree(virtual_base, 0, MEM_RELEASE)) { + if (virtual_map_base) { + if (!VirtualFree(virtual_map_base, 0, MEM_RELEASE)) { LOG_CRITICAL(HW_Memory, "Failed to free virtual memory"); } } @@ -668,7 +677,7 @@ public: void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) { // Intersect the range with our address space. - AdjustMap(&virtual_offset, &length); + AdjustMap(virtual_map_base, virtual_size, &virtual_offset, &length); // We are removing a placeholder. free_manager.AllocateBlock(virtual_base + virtual_offset, length); @@ -693,7 +702,7 @@ public: // We don't want to unmap, we want to reserve this memory. // Intersect the range with our address space. - AdjustMap(&virtual_offset, &length); + AdjustMap(virtual_map_base, virtual_size, &virtual_offset, &length); // Merge with any adjacent placeholder mappings. auto [merged_pointer, merged_size] = @@ -705,7 +714,7 @@ public: void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) { // Intersect the range with our address space. - AdjustMap(&virtual_offset, &length); + AdjustMap(virtual_map_base, virtual_size, &virtual_offset, &length); int flags = PROT_NONE; if (read) { @@ -753,27 +762,6 @@ private: } } - void AdjustMap(size_t* virtual_offset, size_t* length) { - if (virtual_base != nullptr) { - return; - } - - // If we are direct mapped, we want to make sure we are operating on a region - // that is in range of our virtual mapping. - size_t intended_start = *virtual_offset; - size_t intended_end = intended_start + *length; - size_t address_space_start = reinterpret_cast(virtual_map_base); - size_t address_space_end = address_space_start + virtual_size; - - if (address_space_start > intended_end || intended_start > address_space_end) { - *virtual_offset = 0; - *length = 0; - } else { - *virtual_offset = (std::max)(intended_start, address_space_start); - *length = (std::min)(intended_end, address_space_end) - *virtual_offset; - } - } - int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create FreeRegionManager free_manager{}; }; diff --git a/src/common/host_memory.h b/src/common/host_memory.h index 649686b5b0..a2ce6eb3e9 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h @@ -94,6 +94,23 @@ public: return address >= virtual_base && address < virtual_base + virtual_size; } + static void AdjustMap(u8* virtual_map_base, size_t virtual_size, size_t* virtual_offset, size_t* length) { + // If we are direct mapped, we want to make sure we are operating on a region + // that is in range of our virtual mapping. + size_t intended_start = *virtual_offset; + size_t intended_end = intended_start + *length; + size_t address_space_start = reinterpret_cast(virtual_map_base); + size_t address_space_end = address_space_start + virtual_size; + + if (address_space_start > intended_end || intended_start > address_space_end) { + *virtual_offset = 0; + *length = 0; + } else { + *virtual_offset = (std::max)(intended_start, address_space_start); + *length = (std::min)(intended_end, address_space_end) - *virtual_offset; + } + } + using by_vaddr = bi::set_base_hook>; struct MisalignedMapping : by_vaddr {