mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-27 00:00:07 -06:00
Windows
This commit is contained in:
@ -39,6 +39,7 @@
|
||||
|
||||
#include "ARMJIT_Internal.h"
|
||||
#include "ARMJIT_Compiler.h"
|
||||
#include "ARMJIT_Global.h"
|
||||
|
||||
#include "DSi.h"
|
||||
#include "GPU.h"
|
||||
@ -155,6 +156,15 @@ void __libnx_exception_handler(ThreadExceptionDump* ctx)
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
static LPVOID ExceptionHandlerHandle = nullptr;
|
||||
static HMODULE KernelBaseDll = nullptr;
|
||||
|
||||
using VirtualAlloc2Type = PVOID WINAPI (*)(HANDLE Process, PVOID BaseAddress, SIZE_T Size, ULONG AllocationType, ULONG PageProtection, MEM_EXTENDED_PARAMETER* ExtendedParameters, ULONG ParameterCount);
|
||||
using MapViewOfFile3Type = PVOID WINAPI (*)(HANDLE FileMapping, HANDLE Process, PVOID BaseAddress, ULONG64 Offset, SIZE_T ViewSize, ULONG AllocationType, ULONG PageProtection, MEM_EXTENDED_PARAMETER* ExtendedParameters, ULONG ParameterCount);
|
||||
|
||||
static VirtualAlloc2Type virtualAlloc2Ptr;
|
||||
static MapViewOfFile3Type mapViewOfFile3Ptr;
|
||||
|
||||
LONG ARMJIT_Memory::ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
|
||||
{
|
||||
if (exceptionInfo->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
@ -173,6 +183,7 @@ LONG ARMJIT_Memory::ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
Log(LogLevel::Debug, "it all returns to nothing\n");
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
@ -274,8 +285,47 @@ bool ARMJIT_Memory::MapIntoRange(u32 addr, u32 num, u32 offset, u32 size) noexce
|
||||
(u64)(MemoryBaseCodeMem + offset), size));
|
||||
return R_SUCCEEDED(r);
|
||||
#elif defined(_WIN32)
|
||||
bool r = MapViewOfFileEx(MemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, offset, size, dst) == dst;
|
||||
return r;
|
||||
uintptr_t uintptrDst = reinterpret_cast<uintptr_t>(dst);
|
||||
for (auto it = VirtmemPlaceholders.begin(); it != VirtmemPlaceholders.end(); it++)
|
||||
{
|
||||
if (uintptrDst >= it->Start && uintptrDst+size <= it->Start+it->Size)
|
||||
{
|
||||
//Log(LogLevel::Debug, "found mapping %llx %llx %llx %llx\n", uintptrDst, size, it->Start, it->Size);
|
||||
// we split this place holder so that we have a fitting place holder for the mapping
|
||||
if (uintptrDst != it->Start || size != it->Size)
|
||||
{
|
||||
if (!VirtualFree(dst, size, MEM_RELEASE|MEM_PRESERVE_PLACEHOLDER))
|
||||
{
|
||||
Log(LogLevel::Debug, "VirtualFree failed with %x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VirtmemPlaceholder splitPlaceholder = *it;
|
||||
VirtmemPlaceholders.erase(it);
|
||||
if (uintptrDst > splitPlaceholder.Start)
|
||||
{
|
||||
//Log(LogLevel::Debug, "splitting on the left %llx\n", uintptrDst - splitPlaceholder.Start);
|
||||
VirtmemPlaceholders.push_back({splitPlaceholder.Start, uintptrDst - splitPlaceholder.Start});
|
||||
}
|
||||
if (uintptrDst+size < splitPlaceholder.Start+splitPlaceholder.Size)
|
||||
{
|
||||
//Log(LogLevel::Debug, "splitting on the right %llx\n", (splitPlaceholder.Start+splitPlaceholder.Size)-(uintptrDst+size));
|
||||
VirtmemPlaceholders.push_back({uintptrDst+size, (splitPlaceholder.Start+splitPlaceholder.Size)-(uintptrDst+size)});
|
||||
}
|
||||
|
||||
if (!mapViewOfFile3Ptr(MemoryFile, nullptr, dst, offset, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0))
|
||||
{
|
||||
Log(LogLevel::Debug, "MapViewOfFile3 failed with %x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Log(LogLevel::Debug, "no mapping at all found??? %p %x %p\n", dst, size, MemoryBase);
|
||||
return false;
|
||||
#else
|
||||
return mmap(dst, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, MemoryFile, offset) != MAP_FAILED;
|
||||
#endif
|
||||
@ -289,7 +339,47 @@ bool ARMJIT_Memory::UnmapFromRange(u32 addr, u32 num, u32 offset, u32 size) noex
|
||||
(u64)(MemoryBaseCodeMem + offset), size);
|
||||
return R_SUCCEEDED(r);
|
||||
#elif defined(_WIN32)
|
||||
return UnmapViewOfFile(dst);
|
||||
if (!UnmapViewOfFileEx(dst, MEM_PRESERVE_PLACEHOLDER))
|
||||
{
|
||||
Log(LogLevel::Debug, "UnmapViewOfFileEx failed %x\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t uintptrDst = reinterpret_cast<uintptr_t>(dst);
|
||||
uintptr_t coalesceStart = uintptrDst;
|
||||
size_t coalesceSize = size;
|
||||
|
||||
for (auto it = VirtmemPlaceholders.begin(); it != VirtmemPlaceholders.end();)
|
||||
{
|
||||
if (it->Start+it->Size == uintptrDst)
|
||||
{
|
||||
//Log(LogLevel::Debug, "Coalescing to the left\n");
|
||||
coalesceStart = it->Start;
|
||||
coalesceSize += it->Size;
|
||||
it = VirtmemPlaceholders.erase(it);
|
||||
}
|
||||
else if (it->Start == uintptrDst+size)
|
||||
{
|
||||
//Log(LogLevel::Debug, "Coalescing to the right\n");
|
||||
coalesceSize += it->Size;
|
||||
it = VirtmemPlaceholders.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
if (coalesceStart != uintptrDst || coalesceSize != size)
|
||||
{
|
||||
if (!VirtualFree(reinterpret_cast<void*>(coalesceStart), coalesceSize, MEM_RELEASE|MEM_COALESCE_PLACEHOLDERS))
|
||||
return false;
|
||||
|
||||
}
|
||||
VirtmemPlaceholders.push_back({coalesceStart, coalesceSize});
|
||||
//Log(LogLevel::Debug, "Adding coalesced region %llx %llx", coalesceStart, coalesceSize);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return mmap(dst, size, PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) != MAP_FAILED;
|
||||
#endif
|
||||
@ -308,6 +398,10 @@ void ARMJIT_Memory::SetCodeProtectionRange(u32 addr, u32 size, u32 num, int prot
|
||||
else
|
||||
winProtection = PAGE_READWRITE;
|
||||
bool success = VirtualProtect(dst, size, winProtection, &oldProtection);
|
||||
if (!success)
|
||||
{
|
||||
Log(LogLevel::Debug, "VirtualProtect failed with %x\n", GetLastError());
|
||||
}
|
||||
assert(success);
|
||||
#else
|
||||
int posixProt;
|
||||
@ -361,7 +455,6 @@ void ARMJIT_Memory::Mapping::Unmap(int region, melonDS::NDS& nds) noexcept
|
||||
}
|
||||
|
||||
#ifndef __SWITCH__
|
||||
#ifndef _WIN32
|
||||
u32 dtcmEnd = dtcmStart + dtcmSize;
|
||||
if (Num == 0
|
||||
&& dtcmEnd >= Addr
|
||||
@ -381,7 +474,6 @@ void ARMJIT_Memory::Mapping::Unmap(int region, melonDS::NDS& nds) noexcept
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bool succeded = nds.JIT.Memory.UnmapFromRange(Addr, Num, OffsetsPerRegion[region] + LocalOffset, Size);
|
||||
assert(succeded);
|
||||
@ -546,7 +638,6 @@ bool ARMJIT_Memory::MapAtAddress(u32 addr) noexcept
|
||||
u32 dtcmSize = ~NDS.ARM9.DTCMMask + 1;
|
||||
u32 dtcmEnd = dtcmStart + dtcmSize;
|
||||
#ifndef __SWITCH__
|
||||
#ifndef _WIN32
|
||||
if (num == 0
|
||||
&& dtcmEnd >= mirrorStart
|
||||
&& dtcmStart < mirrorStart + mirrorSize)
|
||||
@ -565,7 +656,6 @@ bool ARMJIT_Memory::MapAtAddress(u32 addr) noexcept
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
bool succeded = MapIntoRange(mirrorStart, num, OffsetsPerRegion[region] + memoryOffset, mirrorSize);
|
||||
assert(succeded);
|
||||
@ -582,9 +672,6 @@ bool ARMJIT_Memory::MapAtAddress(u32 addr) noexcept
|
||||
{
|
||||
if (skipDTCM && mirrorStart + offset == dtcmStart)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetCodeProtectionRange(dtcmStart, dtcmSize, 0, 0);
|
||||
#endif
|
||||
offset += dtcmSize;
|
||||
}
|
||||
else
|
||||
@ -627,10 +714,45 @@ bool ARMJIT_Memory::MapAtAddress(u32 addr) noexcept
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ARMJIT_Memory::IsFastMemSupported()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
return false;
|
||||
#else
|
||||
static bool initialised = false;
|
||||
static bool isSupported = false;
|
||||
if (!initialised)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ARMJIT_Global::Init();
|
||||
isSupported = virtualAlloc2Ptr != nullptr;
|
||||
ARMJIT_Global::DeInit();
|
||||
#else
|
||||
// TODO: check page size is 4kb for posix
|
||||
isSupported = true;
|
||||
#endif
|
||||
initialised = true;
|
||||
}
|
||||
return isSupported;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ARMJIT_Memory::RegisterFaultHandler()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ExceptionHandlerHandle = AddVectoredExceptionHandler(1, ExceptionHandler);
|
||||
|
||||
KernelBaseDll = LoadLibrary("KernelBase.dll");
|
||||
/* if (KernelBaseDll)
|
||||
{
|
||||
virtualAlloc2Ptr = reinterpret_cast<VirtualAlloc2Type>(GetProcAddress(KernelBaseDll, "VirtualAlloc2"));
|
||||
mapViewOfFile3Ptr = reinterpret_cast<MapViewOfFile3Type>(GetProcAddress(KernelBaseDll, "MapViewOfFile3"));
|
||||
}*/
|
||||
|
||||
if (!virtualAlloc2Ptr)
|
||||
{
|
||||
Log(LogLevel::Error, "Could not load new Windows virtual memory functions, fast memory is disabled.\n");
|
||||
}
|
||||
#else
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = nullptr;
|
||||
@ -646,10 +768,24 @@ void ARMJIT_Memory::RegisterFaultHandler()
|
||||
|
||||
void ARMJIT_Memory::UnregisterFaultHandler()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (ExceptionHandlerHandle)
|
||||
{
|
||||
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
|
||||
ExceptionHandlerHandle = nullptr;
|
||||
}
|
||||
|
||||
if (KernelBaseDll)
|
||||
{
|
||||
FreeLibrary(KernelBaseDll);
|
||||
KernelBaseDll = nullptr;
|
||||
}
|
||||
#else
|
||||
sigaction(SIGSEGV, &OldSaSegv, nullptr);
|
||||
#ifdef __APPLE__
|
||||
sigaction(SIGBUS, &OldSaBus, nullptr);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ARMJIT_Memory::FaultHandler(FaultDescription& faultDesc, melonDS::NDS& nds)
|
||||
@ -673,6 +809,7 @@ bool ARMJIT_Memory::FaultHandler(FaultDescription& faultDesc, melonDS::NDS& nds)
|
||||
|
||||
ARMJIT_Memory::ARMJIT_Memory(melonDS::NDS& nds) : NDS(nds)
|
||||
{
|
||||
ARMJIT_Global::Init();
|
||||
#if defined(__SWITCH__)
|
||||
MemoryBase = (u8*)aligned_alloc(0x1000, MemoryTotalSize);
|
||||
virtmemLock();
|
||||
@ -697,27 +834,27 @@ ARMJIT_Memory::ARMJIT_Memory(melonDS::NDS& nds) : NDS(nds)
|
||||
|
||||
u8* basePtr = MemoryBaseCodeMem;
|
||||
#elif defined(_WIN32)
|
||||
ExceptionHandlerHandle = AddVectoredExceptionHandler(1, ExceptionHandler);
|
||||
if (virtualAlloc2Ptr)
|
||||
{
|
||||
MemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, MemoryTotalSize, nullptr);
|
||||
|
||||
MemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MemoryTotalSize, NULL);
|
||||
MemoryBase = reinterpret_cast<u8*>(virtualAlloc2Ptr(nullptr, nullptr, VirtmemAreaSize,
|
||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
||||
PAGE_NOACCESS,
|
||||
nullptr, 0));
|
||||
// split off placeholder and map base mapping
|
||||
VirtualFree(MemoryBase, MemoryTotalSize, MEM_RELEASE|MEM_PRESERVE_PLACEHOLDER);
|
||||
mapViewOfFile3Ptr(MemoryFile, nullptr, MemoryBase, 0, MemoryTotalSize, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
|
||||
|
||||
MemoryBase = (u8*)VirtualAlloc(NULL, AddrSpaceSize*4, MEM_RESERVE, PAGE_READWRITE);
|
||||
VirtualFree(MemoryBase, 0, MEM_RELEASE);
|
||||
// this is incredible hacky
|
||||
// but someone else is trying to go into our address space!
|
||||
// Windows will very likely give them virtual memory starting at the same address
|
||||
// as it is giving us now.
|
||||
// That's why we don't use this address, but instead 4gb inwards
|
||||
// I know this is terrible
|
||||
FastMem9Start = MemoryBase + AddrSpaceSize;
|
||||
FastMem7Start = MemoryBase + AddrSpaceSize*2;
|
||||
MemoryBase = MemoryBase + AddrSpaceSize*3;
|
||||
|
||||
MapViewOfFileEx(MemoryFile, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, MemoryTotalSize, MemoryBase);
|
||||
VirtmemPlaceholders.push_back({reinterpret_cast<uintptr_t>(MemoryBase)+MemoryTotalSize, AddrSpaceSize*2});
|
||||
}
|
||||
else
|
||||
{
|
||||
// old Windows version
|
||||
MemoryBase = new u8[MemoryTotalSize];
|
||||
}
|
||||
#else
|
||||
MemoryBase = (u8*)mmap(NULL, VirtmemAreaSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
FastMem9Start = MemoryBase+MemoryTotalSize;
|
||||
FastMem7Start = static_cast<u8*>(FastMem9Start)+AddrSpaceSize;
|
||||
MemoryBase = (u8*)mmap(nullptr, VirtmemAreaSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
Libandroid = Platform::DynamicLibrary_Load("libandroid.so");
|
||||
@ -752,6 +889,8 @@ ARMJIT_Memory::ARMJIT_Memory(melonDS::NDS& nds) : NDS(nds)
|
||||
|
||||
mmap(MemoryBase, MemoryTotalSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, MemoryFile, 0);
|
||||
#endif
|
||||
FastMem9Start = MemoryBase+MemoryTotalSize;
|
||||
FastMem7Start = static_cast<u8*>(FastMem9Start)+AddrSpaceSize;
|
||||
}
|
||||
|
||||
ARMJIT_Memory::~ARMJIT_Memory() noexcept
|
||||
@ -772,25 +911,32 @@ ARMJIT_Memory::~ARMJIT_Memory() noexcept
|
||||
free(MemoryBase);
|
||||
MemoryBase = nullptr;
|
||||
#elif defined(_WIN32)
|
||||
if (MemoryBase)
|
||||
if (virtualAlloc2Ptr)
|
||||
{
|
||||
bool viewUnmapped = UnmapViewOfFile(MemoryBase);
|
||||
assert(viewUnmapped);
|
||||
MemoryBase = nullptr;
|
||||
FastMem9Start = nullptr;
|
||||
FastMem7Start = nullptr;
|
||||
}
|
||||
if (MemoryBase)
|
||||
{
|
||||
bool viewUnmapped = UnmapViewOfFileEx(MemoryBase, MEM_PRESERVE_PLACEHOLDER);
|
||||
assert(viewUnmapped);
|
||||
bool viewCoalesced = VirtualFree(MemoryBase, VirtmemAreaSize, MEM_RELEASE|MEM_COALESCE_PLACEHOLDERS);
|
||||
assert(viewCoalesced);
|
||||
bool freeEverything = VirtualFree(MemoryBase, 0, MEM_RELEASE);
|
||||
assert(freeEverything);
|
||||
|
||||
if (MemoryFile)
|
||||
{
|
||||
CloseHandle(MemoryFile);
|
||||
MemoryFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
MemoryBase = nullptr;
|
||||
FastMem9Start = nullptr;
|
||||
FastMem7Start = nullptr;
|
||||
printf("unmappinged everything\n");
|
||||
}
|
||||
|
||||
if (ExceptionHandlerHandle)
|
||||
if (MemoryFile)
|
||||
{
|
||||
CloseHandle(MemoryFile);
|
||||
MemoryFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
|
||||
ExceptionHandlerHandle = nullptr;
|
||||
delete[] MemoryBase;
|
||||
}
|
||||
#else
|
||||
if (MemoryBase)
|
||||
@ -816,6 +962,8 @@ ARMJIT_Memory::~ARMJIT_Memory() noexcept
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
ARMJIT_Global::DeInit();
|
||||
}
|
||||
|
||||
void ARMJIT_Memory::Reset() noexcept
|
||||
@ -838,17 +986,6 @@ void ARMJIT_Memory::Reset() noexcept
|
||||
|
||||
bool ARMJIT_Memory::IsFastmemCompatible(int region) const noexcept
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/*
|
||||
TODO: with some hacks, the smaller shared WRAM regions
|
||||
could be mapped in some occaisons as well
|
||||
*/
|
||||
if (region == memregion_DTCM
|
||||
|| region == memregion_SharedWRAM
|
||||
|| region == memregion_NewSharedWRAM_B
|
||||
|| region == memregion_NewSharedWRAM_C)
|
||||
return false;
|
||||
#endif
|
||||
return OffsetsPerRegion[region] != UINT32_MAX;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user