summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/host_memory.cpp117
1 files changed, 88 insertions, 29 deletions
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index c6d65aab9..9ae384f01 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -1,18 +1,10 @@
#ifdef _WIN32
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0A00 // Windows 10
-
-#include <windows.h>
-
-#include <boost/icl/separate_interval_set.hpp>
-
#include <iterator>
#include <unordered_map>
-
-#pragma comment(lib, "mincore.lib")
+#include <boost/icl/separate_interval_set.hpp>
+#include <windows.h>
+#include "common/dynamic_library.h"
#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv
@@ -40,38 +32,99 @@ constexpr size_t HugePageSize = 0x200000;
#ifdef _WIN32
+// Manually imported for MinGW compatibility
+#ifndef MEM_RESERVE_PLACEHOLDER
+#define MEM_RESERVE_PLACEHOLDER 0x0004000
+#endif
+#ifndef MEM_REPLACE_PLACEHOLDER
+#define MEM_REPLACE_PLACEHOLDER 0x00004000
+#endif
+#ifndef MEM_COALESCE_PLACEHOLDERS
+#define MEM_COALESCE_PLACEHOLDERS 0x00000001
+#endif
+#ifndef MEM_PRESERVE_PLACEHOLDER
+#define MEM_PRESERVE_PLACEHOLDER 0x00000002
+#endif
+
+using PFN_CreateFileMapping2 = _Ret_maybenull_ HANDLE(WINAPI*)(
+ _In_ HANDLE File, _In_opt_ SECURITY_ATTRIBUTES* SecurityAttributes, _In_ ULONG DesiredAccess,
+ _In_ ULONG PageProtection, _In_ ULONG AllocationAttributes, _In_ ULONG64 MaximumSize,
+ _In_opt_ PCWSTR Name,
+ _Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
+ _In_ ULONG ParameterCount);
+
+using PFN_VirtualAlloc2 = _Ret_maybenull_ PVOID(WINAPI*)(
+ _In_opt_ HANDLE Process, _In_opt_ PVOID BaseAddress, _In_ SIZE_T Size,
+ _In_ ULONG AllocationType, _In_ ULONG PageProtection,
+ _Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
+ _In_ ULONG ParameterCount);
+
+using PFN_MapViewOfFile3 = _Ret_maybenull_ PVOID(WINAPI*)(
+ _In_ HANDLE FileMapping, _In_opt_ HANDLE Process, _In_opt_ PVOID BaseAddress,
+ _In_ ULONG64 Offset, _In_ SIZE_T ViewSize, _In_ ULONG AllocationType, _In_ ULONG PageProtection,
+ _Inout_updates_opt_(ParameterCount) MEM_EXTENDED_PARAMETER* ExtendedParameters,
+ _In_ ULONG ParameterCount);
+
+using PFN_UnmapViewOfFile2 = BOOL(WINAPI*)(_In_ HANDLE Process, _In_ PVOID BaseAddress,
+ _In_ ULONG UnmapFlags);
+
+template <typename T>
+static void GetFuncAddress(Common::DynamicLibrary& dll, const char* name, T& pfn) {
+ if (!dll.GetSymbol(name, &pfn)) {
+ LOG_CRITICAL(HW_Memory, "Failed to load {}", name);
+ throw std::bad_alloc{};
+ }
+}
+
class HostMemory::Impl {
public:
explicit Impl(size_t backing_size_, size_t virtual_size_)
- : backing_size{backing_size_}, virtual_size{virtual_size_}, process{GetCurrentProcess()} {
+ : backing_size{backing_size_}, virtual_size{virtual_size_}, process{GetCurrentProcess()},
+ kernelbase_dll("Kernelbase") {
+ if (!kernelbase_dll.IsOpen()) {
+ LOG_CRITICAL(HW_Memory, "Failed to load Kernelbase.dll");
+ throw std::bad_alloc{};
+ }
+ GetFuncAddress(kernelbase_dll, "CreateFileMapping2", pfn_CreateFileMapping2);
+ GetFuncAddress(kernelbase_dll, "VirtualAlloc2", pfn_VirtualAlloc2);
+ GetFuncAddress(kernelbase_dll, "MapViewOfFile3", pfn_MapViewOfFile3);
+ GetFuncAddress(kernelbase_dll, "UnmapViewOfFile2", pfn_UnmapViewOfFile2);
+
// Allocate backing file map
backing_handle =
- CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
- PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0);
+ pfn_CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
+ PAGE_READWRITE, SEC_COMMIT, backing_size, nullptr, nullptr, 0);
if (!backing_handle) {
+ LOG_CRITICAL(HW_Memory, "Failed to allocate {} MiB of backing memory",
+ backing_size >> 20);
throw std::bad_alloc{};
}
// Allocate a virtual memory for the backing file map as placeholder
- backing_base = static_cast<u8*>(VirtualAlloc2(process, nullptr, backing_size,
- MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
- PAGE_NOACCESS, nullptr, 0));
+ backing_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, backing_size,
+ MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
+ PAGE_NOACCESS, nullptr, 0));
if (!backing_base) {
Release();
+ LOG_CRITICAL(HW_Memory, "Failed to reserve {} MiB of virtual memory",
+ backing_size >> 20);
throw std::bad_alloc{};
}
// Map backing placeholder
- void* const ret = MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size,
- MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
+ void* const ret = pfn_MapViewOfFile3(backing_handle, process, backing_base, 0, backing_size,
+ MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
if (ret != backing_base) {
Release();
+ LOG_CRITICAL(HW_Memory, "Failed to map {} MiB of virtual memory", backing_size >> 20);
throw std::bad_alloc{};
}
// Allocate virtual address placeholder
- virtual_base = static_cast<u8*>(VirtualAlloc2(process, nullptr, virtual_size,
- MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
- PAGE_NOACCESS, nullptr, 0));
+ virtual_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, virtual_size,
+ MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
+ PAGE_NOACCESS, nullptr, 0));
if (!virtual_base) {
Release();
+ LOG_CRITICAL(HW_Memory, "Failed to reserve {} GiB of virtual memory",
+ virtual_size >> 30);
throw std::bad_alloc{};
}
}
@@ -136,8 +189,8 @@ private:
void Release() {
if (!placeholders.empty()) {
for (const auto& placeholder : placeholders) {
- if (!UnmapViewOfFile2(process, virtual_base + placeholder.lower(),
- MEM_PRESERVE_PLACEHOLDER)) {
+ if (!pfn_UnmapViewOfFile2(process, virtual_base + placeholder.lower(),
+ MEM_PRESERVE_PLACEHOLDER)) {
LOG_CRITICAL(HW_Memory, "Failed to unmap virtual memory placeholder");
}
}
@@ -149,7 +202,7 @@ private:
}
}
if (backing_base) {
- if (!UnmapViewOfFile2(process, backing_base, MEM_PRESERVE_PLACEHOLDER)) {
+ if (!pfn_UnmapViewOfFile2(process, backing_base, MEM_PRESERVE_PLACEHOLDER)) {
LOG_CRITICAL(HW_Memory, "Failed to unmap backing memory placeholder");
}
if (!VirtualFreeEx(process, backing_base, 0, MEM_RELEASE)) {
@@ -184,8 +237,8 @@ private:
const bool split_left = unmap_begin > placeholder_begin;
const bool split_right = unmap_end < placeholder_end;
- if (!UnmapViewOfFile2(process, virtual_base + placeholder_begin,
- MEM_PRESERVE_PLACEHOLDER)) {
+ if (!pfn_UnmapViewOfFile2(process, virtual_base + placeholder_begin,
+ MEM_PRESERVE_PLACEHOLDER)) {
LOG_CRITICAL(HW_Memory, "Failed to unmap placeholder");
}
// If we have to remap memory regions due to partial unmaps, we are in a data race as
@@ -235,8 +288,8 @@ private:
}
void MapView(size_t virtual_offset, size_t host_offset, size_t length) {
- if (!MapViewOfFile3(backing_handle, process, virtual_base + virtual_offset, host_offset,
- length, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0)) {
+ if (!pfn_MapViewOfFile3(backing_handle, process, virtual_base + virtual_offset, host_offset,
+ length, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0)) {
LOG_CRITICAL(HW_Memory, "Failed to map placeholder");
}
}
@@ -279,6 +332,12 @@ private:
HANDLE process{}; ///< Current process handle
HANDLE backing_handle{}; ///< File based backing memory
+ DynamicLibrary kernelbase_dll;
+ PFN_CreateFileMapping2 pfn_CreateFileMapping2{};
+ PFN_VirtualAlloc2 pfn_VirtualAlloc2{};
+ PFN_MapViewOfFile3 pfn_MapViewOfFile3{};
+ PFN_UnmapViewOfFile2 pfn_UnmapViewOfFile2{};
+
std::mutex placeholder_mutex; ///< Mutex for placeholders
boost::icl::separate_interval_set<size_t> placeholders; ///< Mapped placeholders
std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset