JIT fixes

- fix fastmem problems on linux
- small fix memory leak
- SlowWrite functions always take in a 32-bit variable so that the C compiler knows that the values aren't necessary zero extended
- a few other stylistic things
- handle SIGBUS as well (for macos)
This commit is contained in:
RSDuck
2020-11-09 20:43:31 +01:00
parent ec232a9365
commit 78839f862e
8 changed files with 140 additions and 91 deletions

View File

@ -40,7 +40,8 @@
We handle this by only mapping those regions which are actually
used and by praying the games don't go wild.
Beware, this file is full of platform specific code.
Beware, this file is full of platform specific code and copied
from Dolphin, so enjoy the copied comments!
*/
@ -49,10 +50,10 @@ namespace ARMJIT_Memory
struct FaultDescription
{
u32 EmulatedFaultAddr;
u64 FaultPC;
u8* FaultPC;
};
bool FaultHandler(FaultDescription* faultDesc, s32& offset);
bool FaultHandler(FaultDescription& faultDesc);
}
#if defined(__SWITCH__)
@ -75,7 +76,7 @@ void __libnx_exception_handler(ThreadExceptionDump* ctx)
ARMJIT_Memory::FaultDescription desc;
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
desc.EmulatedFaultAddr = (u8*)ctx->far.x - curArea;
desc.FaultPC = ctx->pc.x;
desc.FaultPC = (u8*)ctx->pc.x;
u64 integerRegisters[33];
memcpy(integerRegisters, &ctx->cpu_gprs[0].x, 8*29);
@ -84,10 +85,9 @@ void __libnx_exception_handler(ThreadExceptionDump* ctx)
integerRegisters[31] = ctx->sp.x;
integerRegisters[32] = ctx->pc.x;
s32 offset;
if (ARMJIT_Memory::FaultHandler(&desc, offset))
if (ARMJIT_Memory::FaultHandler(desc, offset))
{
integerRegisters[32] += offset;
integerRegisters[32] = (u64)desc.FaultPC;
ARM_RestoreContext(integerRegisters);
}
@ -117,12 +117,11 @@ static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
ARMJIT_Memory::FaultDescription desc;
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
desc.EmulatedFaultAddr = (u8*)exceptionInfo->ExceptionRecord->ExceptionInformation[1] - curArea;
desc.FaultPC = exceptionInfo->ContextRecord->Rip;
desc.FaultPC = (u8*)exceptionInfo->ContextRecord->Rip;
s32 offset = 0;
if (ARMJIT_Memory::FaultHandler(&desc, offset))
if (ARMJIT_Memory::FaultHandler(desc))
{
exceptionInfo->ContextRecord->Rip += offset;
exceptionInfo->ContextRecord->Rip = (u8*)desc.FaultPC;
return EXCEPTION_CONTINUE_EXECUTION;
}
@ -131,50 +130,66 @@ static LONG ExceptionHandler(EXCEPTION_POINTERS* exceptionInfo)
#else
struct sigaction NewSa;
struct sigaction OldSa;
static struct sigaction OldSaSegv;
static struct sigaction OldSaBus;
static void SigsegvHandler(int sig, siginfo_t* info, void* rawContext)
{
if (sig != SIGSEGV && sig != SIGBUS)
{
// We are not interested in other signals - handle it as usual.
return;
}
if (info->si_code != SEGV_MAPERR && info->si_code != SEGV_ACCERR)
{
// Huh? Return.
return;
}
ucontext_t* context = (ucontext_t*)rawContext;
ARMJIT_Memory::FaultDescription desc;
u8* curArea = (u8*)(NDS::CurCPU == 0 ? ARMJIT_Memory::FastMem9Start : ARMJIT_Memory::FastMem7Start);
#ifdef __x86_64__
desc.EmulatedFaultAddr = (u8*)info->si_addr - curArea;
desc.FaultPC = context->uc_mcontext.gregs[REG_RIP];
desc.FaultPC = (u8*)context->uc_mcontext.gregs[REG_RIP];
#else
desc.EmulatedFaultAddr = (u8*)context->uc_mcontext.fault_address - curArea;
desc.FaultPC = context->uc_mcontext.pc;
desc.FaultPC = (u8*)context->uc_mcontext.pc;
#endif
s32 offset = 0;
if (ARMJIT_Memory::FaultHandler(&desc, offset))
if (ARMJIT_Memory::FaultHandler(desc))
{
#ifdef __x86_64__
context->uc_mcontext.gregs[REG_RIP] += offset;
context->uc_mcontext.gregs[REG_RIP] = (u64)desc.FaultPC;
#else
context->uc_mcontext.pc += offset;
context->uc_mcontext.pc = (u64)desc.FaultPC;
#endif
return;
}
if (OldSa.sa_flags & SA_SIGINFO)
struct sigaction* oldSa;
if (sig == SIGSEGV)
oldSa = &OldSaSegv;
else
oldSa = &OldSaBus;
if (oldSa->sa_flags & SA_SIGINFO)
{
OldSa.sa_sigaction(sig, info, rawContext);
oldSa->sa_sigaction(sig, info, rawContext);
return;
}
if (OldSa.sa_handler == SIG_DFL)
if (oldSa->sa_handler == SIG_DFL)
{
signal(sig, SIG_DFL);
return;
}
if (OldSa.sa_handler == SIG_IGN)
if (oldSa->sa_handler == SIG_IGN)
{
// Ignore signal
return;
}
OldSa.sa_handler(sig);
oldSa->sa_handler(sig);
}
#endif
@ -231,7 +246,7 @@ enum
{
memstate_Unmapped,
memstate_MappedRW,
// on switch this is unmapped as well
// on Switch this is unmapped as well
memstate_MappedProtected,
};
@ -505,6 +520,21 @@ bool MapAtAddress(u32 addr)
bool isExecutable = ARMJIT::CodeMemRegions[region];
#ifndef __SWITCH__
if (num == 0)
{
// if a DTCM mapping is mapped before the mapping below it
// we unmap it, so it won't just be overriden
for (int i = 0; i < Mappings[memregion_DTCM].Length; i++)
{
Mapping& mapping = Mappings[memregion_DTCM][i];
if (mirrorStart < mapping.Addr + mapping.Size && mirrorStart + mirrorSize >= mapping.Addr)
{
mapping.Unmap(memregion_DTCM);
}
}
Mappings[memregion_DTCM].Clear();
}
bool succeded = MapIntoRange(mirrorStart, num, OffsetsPerRegion[region] + memoryOffset, mirrorSize);
assert(succeded);
#endif
@ -562,21 +592,20 @@ bool MapAtAddress(u32 addr)
return true;
}
bool FaultHandler(FaultDescription* faultDesc, s32& offset)
bool FaultHandler(FaultDescription& faultDesc)
{
if (ARMJIT::JITCompiler->IsJITFault(faultDesc->FaultPC))
if (ARMJIT::JITCompiler->IsJITFault(faultDesc.FaultPC))
{
bool rewriteToSlowPath = true;
u32 addr = faultDesc->EmulatedFaultAddr;
u8* memStatus = NDS::CurCPU == 0 ? MappingStatus9 : MappingStatus7;
if ((NDS::CurCPU == 0 ? MappingStatus9 : MappingStatus7)[addr >> 12] == memstate_Unmapped)
rewriteToSlowPath = !MapAtAddress(faultDesc->EmulatedFaultAddr);
if (memStatus[faultDesc.EmulatedFaultAddr >> 12] == memstate_Unmapped)
rewriteToSlowPath = !MapAtAddress(faultDesc.EmulatedFaultAddr);
if (rewriteToSlowPath)
{
offset = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc->FaultPC);
}
faultDesc.FaultPC = ARMJIT::JITCompiler->RewriteMemAccess(faultDesc.FaultPC);
return true;
}
return false;
@ -624,22 +653,28 @@ void Init()
u8* basePtr = MemoryBase;
#else
FastMem9Start = mmap(NULL, AddrSpaceSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
FastMem7Start = mmap(NULL, AddrSpaceSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
MemoryBase = (u8*)mmap(NULL, MemoryTotalSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
// this used to be allocated with three different mmaps
// The idea was to give the OS more freedom where to position the buffers,
// but something was bad about this so instead we take this vmem eating monster
// which seems to work better.
MemoryBase = (u8*)mmap(NULL, AddrSpaceSize*4, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
munmap(MemoryBase, AddrSpaceSize*4);
FastMem9Start = MemoryBase;
FastMem7Start = MemoryBase + AddrSpaceSize;
MemoryBase = MemoryBase + AddrSpaceSize*2;
MemoryFile = memfd_create("melondsfastmem", 0);
ftruncate(MemoryFile, MemoryTotalSize);
NewSa.sa_flags = SA_SIGINFO;
sigemptyset(&NewSa.sa_mask);
NewSa.sa_sigaction = SigsegvHandler;
sigaction(SIGSEGV, &NewSa, &OldSa);
munmap(MemoryBase, MemoryTotalSize);
munmap(FastMem9Start, AddrSpaceSize);
munmap(FastMem7Start, AddrSpaceSize);
struct sigaction sa;
sa.sa_handler = nullptr;
sa.sa_sigaction = &SigsegvHandler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, &OldSaSegv);
#ifdef __APPLE__
sigaction(SIGBUS, &sa, &OldSaBus);
#endif
mmap(MemoryBase, MemoryTotalSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, MemoryFile, 0);
@ -657,8 +692,8 @@ void Init()
void DeInit()
{
#if defined(__SWITCH__)
virtmemFree(FastMem9Start, 0x100000000);
virtmemFree(FastMem7Start, 0x100000000);
virtmemFree(FastMem9Start, AddrSpaceSize);
virtmemFree(FastMem7Start, AddrSpaceSize);
svcUnmapProcessCodeMemory(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem, (u64)MemoryBase, MemoryTotalSize);
virtmemFree(MemoryBaseCodeMem, MemoryTotalSize);
@ -668,6 +703,14 @@ void DeInit()
CloseHandle(MemoryFile);
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
#else
sigaction(SIGSEGV, &OldSaSegv, nullptr);
#ifdef __APPLE__
sigaction(SIGBUS, &OldSaBus, nullptr);
#endif
munmap(MemoryBase, MemoryTotalSize);
close(MemoryFile);
#endif
}
@ -702,7 +745,15 @@ bool IsFastmemCompatible(int region)
|| region == memregion_NewSharedWRAM_C)
return false;
#endif
return OffsetsPerRegion[region] != UINT32_MAX;
if (region == memregion_DTCM
|| region == memregion_MainRAM
|| region == memregion_NewSharedWRAM_A
|| region == memregion_NewSharedWRAM_B
|| region == memregion_NewSharedWRAM_C
|| region == memregion_SharedWRAM)
return false;
//return OffsetsPerRegion[region] != UINT32_MAX;
return false;
}
bool GetMirrorLocation(int region, u32 num, u32 addr, u32& memoryOffset, u32& mirrorStart, u32& mirrorSize)
@ -997,9 +1048,11 @@ int ClassifyAddress7(u32 addr)
case 0x06000000:
case 0x06800000:
return memregion_VWRAM;
default:
return memregion_Other;
}
}
return memregion_Other;
}
void WifiWrite32(u32 addr, u32 val)