x64 rec: get rid of setjmp. standardize ngen_Rewrite/HandleException

move rewrite code from exception handlers to x86/x64 dynarecs
use same host context info on linux/win
x64: stack alignment issue in mem handlers
This commit is contained in:
Flyinghead 2021-01-30 16:14:44 +01:00
parent 594241ffa3
commit 80782475da
20 changed files with 268 additions and 221 deletions

View File

@ -645,7 +645,6 @@ target_sources(${PROJECT_NAME} PRIVATE
if(NOT WIN32)
target_sources(${PROJECT_NAME} PRIVATE
core/linux/context.cpp
core/linux/context.h
core/linux/posix_vmem.cpp)
endif()
@ -699,6 +698,8 @@ target_sources(${PROJECT_NAME} PRIVATE
core/oslib/audiobackend_sdl2.cpp
core/oslib/audiostream.cpp
core/oslib/audiostream.h
core/oslib/directory.h
core/oslib/host_context.h
core/oslib/oslib.h)
target_sources(${PROJECT_NAME} PRIVATE

View File

@ -147,7 +147,7 @@ void vmem32_protect_vram(u32 addr, u32 size)
{
if (!vmem32_inited)
return;
for (int page = (addr & VRAM_MASK) / VRAM_PROT_SEGMENT; page <= ((addr & VRAM_MASK) + size - 1) / VRAM_PROT_SEGMENT; page++)
for (u32 page = (addr & VRAM_MASK) / VRAM_PROT_SEGMENT; page <= ((addr & VRAM_MASK) + size - 1) / VRAM_PROT_SEGMENT; page++)
{
vram_blocks[page].push_back({ addr, addr + size - 1 });
}
@ -156,7 +156,7 @@ void vmem32_unprotect_vram(u32 addr, u32 size)
{
if (!vmem32_inited)
return;
for (int page = (addr & VRAM_MASK) / VRAM_PROT_SEGMENT; page <= ((addr & VRAM_MASK) + size - 1) / VRAM_PROT_SEGMENT; page++)
for (u32 page = (addr & VRAM_MASK) / VRAM_PROT_SEGMENT; page <= ((addr & VRAM_MASK) + size - 1) / VRAM_PROT_SEGMENT; page++)
{
std::vector<vram_lock>& block_list = vram_blocks[page];
for (auto it = block_list.begin(); it != block_list.end(); )
@ -241,7 +241,7 @@ static u32 vmem32_map_mmu(u32 address, bool write)
u32 vpn = (entry->Address.VPN << 10) & ~(page_size - 1);
u32 ppn = (entry->Data.PPN << 10) & ~(page_size - 1);
u32 offset = vmem32_paddr_to_offset(ppn);
if (offset == -1)
if (offset == (u32)-1)
return VMEM32_ERROR_NOT_MAPPED;
bool allow_write = (entry->Data.PR & 1) != 0;
@ -334,27 +334,30 @@ static u32 vmem32_map_address(u32 address, bool write)
}
#if !defined(NO_MMU) && defined(HOST_64BIT_CPU)
bool vmem32_handle_signal(void *fault_addr, bool write, u32 exception_pc)
// returns:
// 0 if the fault address isn't handled by the mmu
// 1 if the fault was handled and the access should be reattempted
// -1 if an sh4 exception has been thrown
int vmem32_handle_signal(void *fault_addr, bool write, u32 exception_pc)
{
if (!vmem32_inited || (u8*)fault_addr < virt_ram_base || (u8*)fault_addr >= virt_ram_base + VMEM32_SIZE)
return false;
return 0;
//vmem32_page_faults++;
u32 guest_addr = (u8*)fault_addr - virt_ram_base;
u32 rv = vmem32_map_address(guest_addr, write);
DEBUG_LOG(VMEM, "vmem32_handle_signal handled signal %s @ %p -> %08x rv=%d", write ? "W" : "R", fault_addr, guest_addr, rv);
if (rv == MMU_ERROR_NONE)
return true;
return 1;
if (rv == VMEM32_ERROR_NOT_MAPPED)
return false;
return 0;
#if HOST_CPU == CPU_ARM64
p_sh4rcb->cntx.pc = exception_pc;
#else
p_sh4rcb->cntx.pc = p_sh4rcb->cntx.exception_pc;
#endif
DoMMUException(guest_addr, rv, write ? MMU_TT_DWRITE : MMU_TT_DREAD);
ngen_HandleException();
// not reached
return true;
return -1;
}
#endif

View File

@ -24,7 +24,7 @@
bool vmem32_init();
void vmem32_term();
bool vmem32_handle_signal(void *fault_addr, bool write, u32 exception_pc);
int vmem32_handle_signal(void *fault_addr, bool write, u32 exception_pc);
void vmem32_flush_mmu();
void vmem32_protect_vram(u32 addr, u32 size);
void vmem32_unprotect_vram(u32 addr, u32 size);

View File

@ -256,8 +256,8 @@ void bm_Reset()
}
if (_nvmem_4gb_space())
{
mem_region_unlock(virt_ram_base + 0x8C000000, 0x90000000 - 0x8C000000);
mem_region_unlock(virt_ram_base + 0xAC000000, 0xB0000000 - 0xAC000000);
mem_region_unlock(virt_ram_base + 0x8C000000u, 0x90000000u - 0x8C000000u);
mem_region_unlock(virt_ram_base + 0xAC000000u, 0xB0000000u - 0xAC000000u);
}
}

View File

@ -35,7 +35,7 @@ struct RuntimeBlockInfo: RuntimeBlockInfo_Core
fpscr_t fpu_cfg;
u32 guest_cycles;
u32 guest_opcodes;
u32 host_opcodes;
u32 host_opcodes; // set by host code generator, optional
bool has_fpu_op;
u32 blockcheck_failures;
bool temp_block;
@ -49,7 +49,6 @@ struct RuntimeBlockInfo: RuntimeBlockInfo_Core
u32 relink_offset;
u32 relink_data;
u32 csc_RetCache; //only for stats for now
BlockEndType BlockType;
bool has_jcond;
@ -73,12 +72,8 @@ struct RuntimeBlockInfo: RuntimeBlockInfo_Core
void RemRef(RuntimeBlockInfoPtr other);
void Discard();
void UpdateRefs();
void SetProtectedFlags();
u32 memops;
u32 linkedmemops;
std::map<void*, u32> memory_accesses; // key is host pc when access is made, value is opcode id
bool read_only;
};

View File

@ -149,8 +149,9 @@ bool RuntimeBlockInfo::Setup(u32 rpc,fpscr_t rfpu_cfg)
pBranchBlock=pNextBlock=0;
code=0;
has_jcond=false;
BranchBlock=NextBlock=csc_RetCache=0xFFFFFFFF;
BlockType=BET_SCL_Intr;
BranchBlock = 0xFFFFFFFF;
NextBlock = 0xFFFFFFFF;
BlockType = BET_SCL_Intr;
has_fpu_op = false;
temp_block = false;

View File

@ -43,6 +43,7 @@
#pragma once
#include "decoder.h"
#include "blockmanager.h"
#include "oslib/host_context.h"
#define CODE_SIZE (10*1024*1024)
#ifdef NO_MMU
@ -111,7 +112,8 @@ extern void (*ngen_FailedToFindBlock)();
void ngen_mainloop(void* cntx);
void ngen_GetFeatures(ngen_features* dst);
void ngen_HandleException();
void ngen_HandleException(host_context_t &context);
bool ngen_Rewrite(host_context_t &context, void *faultAddress);
//Canonical callback interface
enum CanonicalParamType

View File

@ -82,7 +82,6 @@ bool find_entry_by_page_size(u32 address, const TLB_Entry **ret_entry)
u32 vpn = (address >> (10 + shift)) << shift;
u16 bucket = bucket_index(vpn << 10, size);
TLB_LinkedEntry *pEntry = entry_buckets[bucket];
u32 length = 0;
while (pEntry != NULL)
{
if (pEntry->entry.Address.VPN == vpn && (size >> 1) == pEntry->entry.Data.SZ1 && (size & 1) == pEntry->entry.Data.SZ0)

View File

@ -16,20 +16,21 @@
#include "hw/sh4/dyna/blockmanager.h"
#include "hw/mem/vmem32.h"
#include "linux/context.h"
#include "oslib/host_context.h"
#include "hw/sh4/dyna/ngen.h"
#if !defined(TARGET_NO_EXCEPTIONS)
bool ngen_Rewrite(unat& addr,unat retadr,unat acc);
u32* ngen_readm_fail_v2(u32* ptr,u32* regs,u32 saddr);
bool VramLockedWrite(u8* address);
bool BM_LockedWrite(u8* address);
void context_from_segfault(host_context_t* hctx, void* segfault_ctx);
void context_to_segfault(host_context_t* hctx, void* segfault_ctx);
#if defined(__APPLE__)
void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx) {
rei_host_context_t ctx;
host_context_t ctx;
context_from_segfault(&ctx, segfault_ctx);
@ -45,13 +46,12 @@ void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx) {
void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
{
rei_host_context_t ctx;
context_from_segfault(&ctx, segfault_ctx);
bool dyna_cde = ((unat)CC_RX2RW(ctx.pc) > (unat)CodeCache) && ((unat)CC_RX2RW(ctx.pc) < (unat)(CodeCache + CODE_SIZE + TEMP_CODE_SIZE));
#if !defined(NO_MMU) && defined(HOST_64BIT_CPU)
// WinCE virtual memory
#if HOST_CPU == CPU_ARM64
#define HOST_CTX_READY
host_context_t ctx;
context_from_segfault(&ctx, segfault_ctx);
u32 op = *(u32*)ctx.pc;
bool write = (op & 0x00400000) == 0;
u32 exception_pc = ctx.x2;
@ -59,52 +59,49 @@ void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
bool write = false; // TODO?
u32 exception_pc = 0;
#endif
if (vmem32_handle_signal(si->si_addr, write, exception_pc))
int rv = vmem32_handle_signal(si->si_addr, write, exception_pc);
if (rv == 1)
return;
if (rv == -1)
{
#ifndef HOST_CTX_READY
host_context_t ctx;
context_from_segfault(&ctx, segfault_ctx);
#endif
ngen_HandleException(ctx);
context_to_segfault(&ctx, segfault_ctx);
return;
}
#endif
// code protection in RAM
if (bm_RamWriteAccess(si->si_addr))
return;
if (VramLockedWrite((u8*)si->si_addr) || BM_LockedWrite((u8*)si->si_addr))
// texture protection in VRAM
if (VramLockedWrite((u8*)si->si_addr))
return;
// FPCB jump table protection
if (BM_LockedWrite((u8*)si->si_addr))
return;
#if FEAT_SHREC == DYNAREC_JIT
#if HOST_CPU==CPU_ARM
else if (dyna_cde)
{
ctx.pc = (u32)ngen_readm_fail_v2((u32*)ctx.pc, ctx.r, (unat)si->si_addr);
context_to_segfault(&ctx, segfault_ctx);
}
#elif HOST_CPU==CPU_X86
else if (ngen_Rewrite((unat&)ctx.pc, *(unat*)ctx.esp, ctx.eax))
{
//remove the call from call stack
ctx.esp += 4;
//restore the addr from eax to ecx so it's valid again
ctx.ecx = ctx.eax;
#if FEAT_SHREC == DYNAREC_JIT
// fast mem access rewriting
#ifndef HOST_CTX_READY
host_context_t ctx;
context_from_segfault(&ctx, segfault_ctx);
#endif
bool dyna_cde = ((unat)CC_RX2RW(ctx.pc) >= (unat)CodeCache) && ((unat)CC_RX2RW(ctx.pc) < (unat)(CodeCache + CODE_SIZE + TEMP_CODE_SIZE));
context_to_segfault(&ctx, segfault_ctx);
}
#elif HOST_CPU == CPU_X64
else if (dyna_cde && ngen_Rewrite((unat&)ctx.pc, 0, 0))
{
context_to_segfault(&ctx, segfault_ctx);
}
#elif HOST_CPU == CPU_ARM64
else if (dyna_cde && ngen_Rewrite(ctx.pc, 0, 0))
{
context_to_segfault(&ctx, segfault_ctx);
}
#else
#error JIT: Not supported arch
#endif
#endif
else
if (dyna_cde && ngen_Rewrite(ctx, si->si_addr))
{
ERROR_LOG(COMMON, "SIGSEGV @ %zx -> %p was not in vram, dynacode:%d", ctx.pc, si->si_addr, dyna_cde);
die("segfault");
signal(SIGSEGV, SIG_DFL);
context_to_segfault(&ctx, segfault_ctx);
return;
}
#endif
ERROR_LOG(COMMON, "SIGSEGV @ %p -> %p was not in vram, dynacode:%d", (void *)ctx.pc, si->si_addr, dyna_cde);
die("segfault");
signal(SIGSEGV, SIG_DFL);
}
#undef HOST_CTX_READY
void install_fault_handler(void)
{

View File

@ -1,4 +1,4 @@
#include "context.h"
#include "oslib/host_context.h"
#if defined(__ANDROID__)
#include <asm/sigcontext.h>
@ -17,76 +17,86 @@
//////
#define MCTX(p) (((ucontext_t *)(segfault_ctx))->uc_mcontext p)
template <typename Ta, typename Tb>
void bicopy(Ta& rei, Tb& seg, bool to_segfault) {
if (to_segfault) {
seg = rei;
}
else {
rei = seg;
}
template <bool ToSegfault, typename Tctx, typename Tseg>
static void bicopy(Tctx& ctx, Tseg& seg)
{
static_assert(sizeof(Tctx) == sizeof(Tseg), "Invalid assignment");
if (ToSegfault)
seg = (Tseg)ctx;
else
ctx = (Tctx)seg;
}
void context_segfault(rei_host_context_t* reictx, void* segfault_ctx, bool to_segfault) {
template<bool ToSegfault>
static void context_segfault(host_context_t* hostctx, void* segfault_ctx)
{
#if !defined(TARGET_NO_EXCEPTIONS)
#if HOST_CPU == CPU_ARM
#if defined(__FreeBSD__)
bicopy(reictx->pc, MCTX(.__gregs[_REG_PC]), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(.__gregs[_REG_PC]));
for (int i = 0; i < 15; i++)
bicopy(reictx->r[i], MCTX(.__gregs[i]), to_segfault);
bicopy<ToSegfault>(hostctx->reg[i], MCTX(.__gregs[i]));
#elif HOST_OS == OS_LINUX
bicopy(reictx->pc, MCTX(.arm_pc), to_segfault);
u32* r =(u32*) &MCTX(.arm_r0);
bicopy<ToSegfault>(hostctx->pc, MCTX(.arm_pc));
u32* reg =(u32*) &MCTX(.arm_r0);
for (int i = 0; i < 15; i++)
bicopy(reictx->r[i], r[i], to_segfault);
bicopy<ToSegfault>(hostctx->reg[i], reg[i]);
#elif defined(__APPLE__)
bicopy(reictx->pc, MCTX(->__ss.__pc), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(->__ss.__pc));
for (int i = 0; i < 15; i++)
bicopy(reictx->r[i], MCTX(->__ss.__r[i]), to_segfault);
bicopy<ToSegfault>(hostctx->reg[i], MCTX(->__ss.__r[i]));
#else
#error HOST_OS
#endif
#elif HOST_CPU == CPU_ARM64
bicopy(reictx->pc, MCTX(.pc), to_segfault);
bicopy(reictx->x2, MCTX(.regs[2]), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(.pc));
bicopy<ToSegfault>(hostctx->x2, MCTX(.regs[2]));
#elif HOST_CPU == CPU_X86
#if defined(__FreeBSD__)
bicopy(reictx->pc, MCTX(.mc_eip), to_segfault);
bicopy(reictx->esp, MCTX(.mc_esp), to_segfault);
bicopy(reictx->eax, MCTX(.mc_eax), to_segfault);
bicopy(reictx->ecx, MCTX(.mc_ecx), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(.mc_eip));
bicopy<ToSegfault>(hostctx->esp, MCTX(.mc_esp));
bicopy<ToSegfault>(hostctx->eax, MCTX(.mc_eax));
bicopy<ToSegfault>(hostctx->ecx, MCTX(.mc_ecx));
#elif HOST_OS == OS_LINUX
bicopy(reictx->pc, MCTX(.gregs[REG_EIP]), to_segfault);
bicopy(reictx->esp, MCTX(.gregs[REG_ESP]), to_segfault);
bicopy(reictx->eax, MCTX(.gregs[REG_EAX]), to_segfault);
bicopy(reictx->ecx, MCTX(.gregs[REG_ECX]), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(.gregs[REG_EIP]));
bicopy<ToSegfault>(hostctx->esp, MCTX(.gregs[REG_ESP]));
bicopy<ToSegfault>(hostctx->eax, MCTX(.gregs[REG_EAX]));
bicopy<ToSegfault>(hostctx->ecx, MCTX(.gregs[REG_ECX]));
#elif defined(__APPLE__)
bicopy(reictx->pc, MCTX(->__ss.__eip), to_segfault);
bicopy(reictx->esp, MCTX(->__ss.__esp), to_segfault);
bicopy(reictx->eax, MCTX(->__ss.__eax), to_segfault);
bicopy(reictx->ecx, MCTX(->__ss.__ecx), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(->__ss.__eip));
bicopy<ToSegfault>(hostctx->esp, MCTX(->__ss.__esp));
bicopy<ToSegfault>(hostctx->eax, MCTX(->__ss.__eax));
bicopy<ToSegfault>(hostctx->ecx, MCTX(->__ss.__ecx));
#else
#error HOST_OS
#endif
#elif HOST_CPU == CPU_X64
#if defined(__FreeBSD__) || defined(__DragonFly__)
bicopy(reictx->pc, MCTX(.mc_rip), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(.mc_rip));
#elif defined(__NetBSD__)
bicopy(reictx->pc, MCTX(.__gregs[_REG_RIP]), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(.__gregs[_REG_RIP]));
bicopy<ToSegfault>(hostctx->rsp, MCTX(.__gregs[REG_RSP]));
bicopy<ToSegfault>(hostctx->r9, MCTX(.__gregs[REG_R9]));
bicopy<ToSegfault>(hostctx->rdi, MCTX(.__gregs[REG_RDI]));
#elif HOST_OS == OS_LINUX
bicopy(reictx->pc, MCTX(.gregs[REG_RIP]), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(.gregs[REG_RIP]));
bicopy<ToSegfault>(hostctx->rsp, MCTX(.gregs[REG_RSP]));
bicopy<ToSegfault>(hostctx->r9, MCTX(.gregs[REG_R9]));
bicopy<ToSegfault>(hostctx->rdi, MCTX(.gregs[REG_RDI]));
#elif defined(__APPLE__)
bicopy(reictx->pc, MCTX(->__ss.__rip), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(->__ss.__rip));
bicopy<ToSegfault>(hostctx->rsp, MCTX(->__ss.__rsp));
bicopy<ToSegfault>(hostctx->r9, MCTX(->__ss.__r9));
bicopy<ToSegfault>(hostctx->rdi, MCTX(->__ss.__rdi));
#else
#error HOST_OS
#endif
#elif HOST_CPU == CPU_MIPS
bicopy(reictx->pc, MCTX(.pc), to_segfault);
bicopy<ToSegfault>(hostctx->pc, MCTX(.pc));
#elif HOST_CPU == CPU_GENERIC
//nothing!
#else
@ -96,10 +106,10 @@ void context_segfault(rei_host_context_t* reictx, void* segfault_ctx, bool to_se
}
void context_from_segfault(rei_host_context_t* reictx, void* segfault_ctx) {
context_segfault(reictx, segfault_ctx, false);
void context_from_segfault(host_context_t* hostctx, void* segfault_ctx) {
context_segfault<false>(hostctx, segfault_ctx);
}
void context_to_segfault(rei_host_context_t* reictx, void* segfault_ctx) {
context_segfault(reictx, segfault_ctx, true);
void context_to_segfault(host_context_t* hostctx, void* segfault_ctx) {
context_segfault<true>(hostctx, segfault_ctx);
}

View File

@ -1,9 +1,7 @@
#pragma once
#include "types.h"
struct rei_host_context_t {
struct host_context_t {
#if HOST_CPU != CPU_GENERIC
unat pc;
#endif
@ -12,12 +10,17 @@ struct rei_host_context_t {
u32 eax;
u32 ecx;
u32 esp;
#elif HOST_CPU == CPU_X64
u64 rsp;
u64 r9;
#ifdef _WIN32
u64 rcx;
#else
u64 rdi;
#endif
#elif HOST_CPU == CPU_ARM
u32 r[15];
u32 reg[15];
#elif HOST_CPU == CPU_ARM64
u64 x2;
#endif
};
void context_from_segfault(rei_host_context_t* reictx, void* segfault_ctx);
void context_to_segfault(rei_host_context_t* reictx, void* segfault_ctx);

View File

@ -747,9 +747,10 @@ void vmem_slowpath(eReg raddr, eReg rt, eFSReg ft, eFDReg fd, mem_op_type optp,
}
}
u32* ngen_readm_fail_v2(u32* ptrv,u32* regs,u32 fault_addr)
bool ngen_Rewrite(host_context_t &context, void *faultAddress)
{
arm_mem_op* ptr=(arm_mem_op*)ptrv;
u32 *regs = context.reg;
arm_mem_op *ptr = (arm_mem_op *)context.pc;
static_assert(sizeof(*ptr) == 4, "sizeof(arm_mem_op) == 4");
@ -804,7 +805,7 @@ u32* ngen_readm_fail_v2(u32* ptrv,u32* regs,u32 fault_addr)
//get some other relevant data
u32 sh4_addr=regs[raddr];
u32 fault_offs=fault_addr-regs[8];
u32 fault_offs = (uintptr_t)faultAddress - regs[8];
u8* sh4_ctr=(u8*)regs[8];
bool is_sq=(sh4_addr>>26)==0x38;
@ -900,9 +901,10 @@ u32* ngen_readm_fail_v2(u32* ptrv,u32* regs,u32 fault_addr)
vmem_platform_flush_cache((void*)ptr, (u8*)emit_ptr - 1, (void*)ptr, (u8*)emit_ptr - 1);
emit_ptr=0;
emit_ptr = 0;
context.pc = (size_t)ptr;
return (u32*)ptr;
return true;
}
EAPI NEG(eReg Rd, eReg Rs)

View File

@ -2228,10 +2228,10 @@ static const u32 op_sizes[] = {
4,
8,
};
bool ngen_Rewrite(unat& host_pc, unat, unat)
bool ngen_Rewrite(host_context_t &context, void *faultAddress)
{
//LOGI("ngen_Rewrite pc %zx\n", host_pc);
u32 *code_ptr = (u32 *)CC_RX2RW(host_pc);
//LOGI("ngen_Rewrite pc %zx\n", context.pc);
u32 *code_ptr = (u32 *)CC_RX2RW(context.pc);
u32 armv8_op = *code_ptr;
bool is_read;
u32 size;
@ -2264,7 +2264,7 @@ bool ngen_Rewrite(unat& host_pc, unat, unat)
}
assembler->Finalize(true);
delete assembler;
host_pc = (unat)CC_RW2RX(code_rewrite);
context.pc = (unat)CC_RW2RX(code_rewrite);
return true;
}
@ -2287,8 +2287,9 @@ RuntimeBlockInfo* ngen_AllocateBlock()
return new DynaRBI();
}
void ngen_HandleException()
void ngen_HandleException(host_context_t &context)
{
// TODO
longjmp(jmp_env, 1);
}

View File

@ -1956,7 +1956,7 @@ void ngen_ResetBlocks()
*/
}
void ngen_HandleException()
void ngen_HandleException(host_context_t &context)
{
die("rec-cpp exceptions not supported");
}

View File

@ -1,7 +1,6 @@
#include "build.h"
#if FEAT_SHREC == DYNAREC_JIT && HOST_CPU == CPU_X64
#include <setjmp.h>
//#define CANONICAL_TEST
@ -37,12 +36,13 @@ struct DynaRBI : RuntimeBlockInfo
static int cycle_counter;
static void (*mainloop)();
static void (*handleException)();
u32 mem_writes, mem_reads;
u32 mem_rewrites_w, mem_rewrites_r;
static jmp_buf jmp_env;
static u32 exception_raised;
static u64 jmp_rsp;
namespace MemSize {
enum {
@ -73,6 +73,7 @@ static const u8 *MemHandlerStart, *MemHandlerEnd;
void ngen_mainloop(void *)
{
verify(mainloop != nullptr);
try {
mainloop();
} catch (const SH4ThrownException&) {
@ -106,13 +107,9 @@ static void handle_mem_exception(u32 exception_raised, u32 pc)
{
if (exception_raised)
{
if (pc & 1)
// Delay slot
spc = pc - 1;
else
spc = pc;
spc = pc;
cycle_counter += 2; // probably more is needed but no easy way to find out
longjmp(jmp_env, 1);
handleException();
}
}
@ -150,7 +147,7 @@ static void handle_sh4_exception(SH4ThrownException& ex, u32 pc)
}
Do_Exception(pc, ex.expEvn, ex.callVect);
cycle_counter += 4; // probably more is needed
longjmp(jmp_env, 1);
handleException();
}
static void interpreter_fallback(u16 op, OpCallFP *oph, u32 pc)
@ -291,7 +288,7 @@ public:
int size = op.flags & 0x7f;
if (mmu_enabled())
mov(call_regs[2], block->vaddr + op.guest_offs - (op.delay_slot ? 1 : 0)); // pc
mov(call_regs[2], block->vaddr + op.guest_offs - (op.delay_slot ? 2 : 0)); // pc
size = size == 1 ? MemSize::S8 : size == 2 ? MemSize::S16 : size == 4 ? MemSize::S32 : MemSize::S64;
GenCall((void (*)())MemHandlers[optimise ? MemType::Fast : MemType::Slow][size][MemOp::R], mmu_enabled());
@ -331,7 +328,7 @@ public:
}
if (mmu_enabled())
mov(call_regs[2], block->vaddr + op.guest_offs - (op.delay_slot ? 1 : 0)); // pc
mov(call_regs[2], block->vaddr + op.guest_offs - (op.delay_slot ? 2 : 0)); // pc
size = size == 1 ? MemSize::S8 : size == 2 ? MemSize::S16 : size == 4 ? MemSize::S32 : MemSize::S64;
GenCall((void (*)())MemHandlers[optimise ? MemType::Fast : MemType::Slow][size][MemOp::W], mmu_enabled());
}
@ -670,16 +667,7 @@ public:
#endif
mov(dword[rip + &cycle_counter], SH4_TIMESLICE);
lea(call_regs64[0], qword[rip + &jmp_env]);
#ifdef _WIN32
xor_(call_regs64[1], call_regs64[1]); // no frame pointer
#endif
#ifdef _MSC_VER
// FIXME call((const void *)_setjmp);
#else
call((const void *)_setjmp);
#endif
mov(qword[rip + &jmp_rsp], rsp);
//run_loop:
Xbyak::Label run_loop;
@ -726,29 +714,37 @@ public:
pop(rbx);
ret();
//handleException:
Xbyak::Label handleExceptionLabel;
L(handleExceptionLabel);
mov(rsp, qword[rip + &jmp_rsp]);
jmp(run_loop);
genMemHandlers();
ready();
mainloop = (void (*)())getCode();
handleException = (void(*)())handleExceptionLabel.getAddress();
emit_Skip(getSize());
}
bool rewriteMemAccess(size_t& host_pc, size_t retadr, size_t accessedAddress)
bool rewriteMemAccess(host_context_t &context)
{
if (!_nvmem_enabled() || (mmu_enabled() && !vmem32_enabled()))
return false;
//printf("ngen_Rewrite pc %p\n", host_pc);
if (host_pc < (size_t)MemHandlerStart || host_pc >= (size_t)MemHandlerEnd)
//printf("ngen_Rewrite pc %p\n", context.pc);
if (context.pc < (size_t)MemHandlerStart || context.pc >= (size_t)MemHandlerEnd)
return false;
size_t ca = *(s32 *)(retadr - 4) + retadr;
u8 *retAddr = *(u8 **)context.rsp;
void *ca = *(s32 *)(retAddr - 4) + retAddr;
for (int size = 0; size < MemSize::Count; size++)
{
for (int op = 0; op < MemOp::Count; op++)
{
if ((size_t)MemHandlers[MemType::Fast][size][op] != ca)
if ((void *)MemHandlers[MemType::Fast][size][op] != ca)
continue;
//found !
@ -758,12 +754,21 @@ public:
ready();
host_pc = retadr - 5;
context.pc = (uintptr_t)(retAddr - 5);
// remove the call from the stack
context.rsp += 8;
if (!_nvmem_4gb_space())
//restore the addr from r9 to arg0 (rcx or rdi) so it's valid again
#ifdef _WIN32
context.rcx = context.r9;
#else
context.rdi = context.r9;
#endif
return true;
}
}
ERROR_LOG(DYNAREC, "rewriteMemAccess code not found: hpc %08x retadr %08x acc %08x", host_pc, retadr, accessedAddress);
ERROR_LOG(DYNAREC, "rewriteMemAccess code not found: host pc %p", (void *)context.pc);
die("Failed to match the code");
return false;
@ -1090,9 +1095,11 @@ private:
mov(dword[rax], call_regs[2]);
}
mov(rax, (uintptr_t)virt_ram_base);
mov(r9, call_regs64[0]);
if (!_nvmem_4gb_space())
{
mov(r9, call_regs64[0]);
and_(call_regs[0], 0x1FFFFFFF);
}
switch (size)
{
case MemSize::S8:
@ -1133,18 +1140,22 @@ private:
mov(call_regs[1], call_regs[2]);
switch (size) {
case MemSize::S8:
sub(rsp, 8);
if (mmu_enabled())
call((const void *)ReadMemNoEx<u8>);
else
call((const void *)ReadMem8);
movsx(eax, al);
add(rsp, 8);
break;
case MemSize::S16:
sub(rsp, 8);
if (mmu_enabled())
call((const void *)ReadMemNoEx<u16>);
else
call((const void *)ReadMem16);
movsx(eax, ax);
add(rsp, 8);
break;
case MemSize::S32:
if (mmu_enabled())
@ -1253,7 +1264,7 @@ private:
if (xmm8_mapped || xmm9_mapped || xmm10_mapped || xmm11_mapped)
{
u32 stack_size = 4 * (xmm8_mapped + xmm9_mapped + xmm10_mapped + xmm11_mapped);
int offset = stack_size;
int offset = stack_size - 4;
stack_size = (((stack_size + 15) >> 4) << 4); // Stack needs to be 16-byte aligned before the call
if (xmm11_mapped)
{
@ -1321,55 +1332,57 @@ void X64RegAlloc::Writeback_FPU(u32 reg, s8 nreg)
compiler->RegWriteback_FPU(reg, nreg);
}
static BlockCompiler* compiler;
static BlockCompiler* ccCompiler;
void ngen_Compile(RuntimeBlockInfo* block, bool smc_checks, bool reset, bool staging, bool optimise)
{
verify(emit_FreeSpace() >= 16 * 1024);
compiler = new BlockCompiler();
BlockCompiler compiler;
::ccCompiler = &compiler;
try {
compiler->compile(block, smc_checks, reset, staging, optimise);
compiler.compile(block, smc_checks, reset, staging, optimise);
} catch (const Xbyak::Error& e) {
ERROR_LOG(DYNAREC, "Fatal xbyak error: %s", e.what());
}
delete compiler;
::ccCompiler = nullptr;
}
void ngen_CC_Start(shil_opcode* op)
{
compiler->ngen_CC_Start(*op);
ccCompiler->ngen_CC_Start(*op);
}
void ngen_CC_Param(shil_opcode* op, shil_param* par, CanonicalParamType tp)
{
compiler->ngen_CC_param(*op, *par, tp);
ccCompiler->ngen_CC_param(*op, *par, tp);
}
void ngen_CC_Call(shil_opcode* op, void* function)
{
compiler->ngen_CC_Call(*op, function);
ccCompiler->ngen_CC_Call(*op, function);
}
void ngen_CC_Finish(shil_opcode* op)
{
}
bool ngen_Rewrite(size_t& host_pc, size_t retadr, size_t acc)
bool ngen_Rewrite(host_context_t &context, void *faultAddress)
{
std::unique_ptr<BlockCompiler> compiler(new BlockCompiler((u8*)(retadr - 5)));
u8 *retAddr = *(u8 **)context.rsp - 5;
BlockCompiler compiler(retAddr);
try {
return compiler->rewriteMemAccess(host_pc, retadr, acc);
return compiler.rewriteMemAccess(context);
} catch (const Xbyak::Error& e) {
ERROR_LOG(DYNAREC, "Fatal xbyak error: %s", e.what());
return false;
}
}
void ngen_HandleException()
void ngen_HandleException(host_context_t &context)
{
longjmp(jmp_env, 1);
context.pc = (uintptr_t)handleException;
context.rsp = jmp_rsp;
}
void ngen_ResetBlocks()
@ -1378,9 +1391,9 @@ void ngen_ResetBlocks()
if (mainloop != nullptr && mainloop != emit_GetCCPtr())
return;
std::unique_ptr<BlockCompiler> compiler(new BlockCompiler());
BlockCompiler compiler;
try {
compiler->genMainloop();
compiler.genMainloop();
} catch (const Xbyak::Error& e) {
ERROR_LOG(DYNAREC, "Fatal xbyak error: %s", e.what());
}

View File

@ -752,10 +752,11 @@ void ngen_Compile(RuntimeBlockInfo* block, bool smc_checks, bool, bool, bool opt
delete compiler;
}
bool ngen_Rewrite(size_t& host_pc, size_t addr, size_t acc)
bool ngen_Rewrite(host_context_t &context, void *faultAddress)
{
X86Compiler *compiler = new X86Compiler((u8*)(addr - 5));
bool rv = compiler->rewriteMemAccess(host_pc, addr, acc);
u8 *rewriteAddr = *(u8 **)context.esp - 5;
X86Compiler *compiler = new X86Compiler(rewriteAddr);
bool rv = compiler->rewriteMemAccess(context);
delete compiler;
return rv;

View File

@ -75,7 +75,7 @@ public:
void genMainloop();
u32 relinkBlock(RuntimeBlockInfo *block);
bool rewriteMemAccess(size_t& host_pc, size_t retadr, size_t acc);
bool rewriteMemAccess(host_context_t &context);
private:
void genOpcode(RuntimeBlockInfo *block, bool optimise, shil_opcode& op);

View File

@ -422,19 +422,20 @@ void X86Compiler::genOpcode(RuntimeBlockInfo* block, bool optimise, shil_opcode&
}
}
bool X86Compiler::rewriteMemAccess(size_t& host_pc, size_t retadr, size_t acc)
bool X86Compiler::rewriteMemAccess(host_context_t &context)
{
//DEBUG_LOG(DYNAREC, "rewriteMemAccess hpc %08x retadr %08x", host_pc, retadr);
if (host_pc < (size_t)MemHandlerStart || host_pc >= (size_t)MemHandlerEnd)
u8 *retAddr = *(u8 **)context.esp;
//DEBUG_LOG(DYNAREC, "rewriteMemAccess hpc %08x retadr %08x", context.pc, (size_t)retAddr);
if (context.pc < (size_t)MemHandlerStart || context.pc >= (size_t)MemHandlerEnd)
return false;
u32 ca = *(u32 *)(retadr - 4) + retadr;
void *ca = *(u32 *)(retAddr - 4) + retAddr;
for (int size = 0; size < MemOp::SizeCount; size++)
{
for (int op = 0; op < MemOp::OpCount; op++)
{
if ((u32)MemHandlers[MemOp::Fast][size][op] != ca)
if ((void *)MemHandlers[MemOp::Fast][size][op] != ca)
continue;
//found !
@ -444,12 +445,16 @@ bool X86Compiler::rewriteMemAccess(size_t& host_pc, size_t retadr, size_t acc)
ready();
host_pc = retadr - 5;
context.pc = (size_t)(retAddr - 5);
//remove the call from call stack
context.esp += 4;
//restore the addr from eax to ecx so it's valid again
context.ecx = context.eax;
return true;
}
}
ERROR_LOG(DYNAREC, "rewriteMemAccess code not found: hpc %08x retadr %08x acc %08x", host_pc, retadr, acc);
ERROR_LOG(DYNAREC, "rewriteMemAccess code not found: hpc %08x retadr %p acc %08x", context.pc, retAddr, context.eax);
die("Failed to match the code");
return false;

View File

@ -15,6 +15,8 @@
#include "hw/maple/maple_devs.h"
#include "emulator.h"
#include "rend/mainui.h"
#include "hw/sh4/dyna/ngen.h"
#include "oslib/host_context.h"
#include <windows.h>
#include <windowsx.h>
@ -114,7 +116,6 @@ PCHAR*
}
bool VramLockedWrite(u8* address);
bool ngen_Rewrite(unat& addr,unat retadr,unat acc);
bool BM_LockedWrite(u8* address);
static std::shared_ptr<WinKbGamepadDevice> kb_gamepad;
@ -133,59 +134,75 @@ void os_SetupInput()
#endif
}
LONG ExeptionHandler(EXCEPTION_POINTERS *ExceptionInfo)
static void readContext(const EXCEPTION_POINTERS *ep, host_context_t &context)
{
EXCEPTION_POINTERS* ep = ExceptionInfo;
#if HOST_CPU == CPU_X86
context.pc = ep->ContextRecord->Eip;
context.esp = ep->ContextRecord->Esp;
context.eax = ep->ContextRecord->Eax;
context.ecx = ep->ContextRecord->Ecx;
#elif HOST_CPU == CPU_X64
context.pc = ep->ContextRecord->Rip;
context.rsp = ep->ContextRecord->Rsp;
context.r9 = ep->ContextRecord->R9;
context.rcx = ep->ContextRecord->Rcx;
#endif
}
static void writeContext(EXCEPTION_POINTERS *ep, const host_context_t &context)
{
#if HOST_CPU == CPU_X86
ep->ContextRecord->Eip = context.pc;
ep->ContextRecord->Esp = context.esp;
ep->ContextRecord->Eax = context.eax;
ep->ContextRecord->Ecx = context.ecx;
#elif HOST_CPU == CPU_X64
ep->ContextRecord->Rip = context.pc;
ep->ContextRecord->Rsp = context.rsp;
ep->ContextRecord->R9 = context.r9;
ep->ContextRecord->Rcx = context.rcx;
#endif
}
LONG ExeptionHandler(EXCEPTION_POINTERS *ep)
{
u32 dwCode = ep->ExceptionRecord->ExceptionCode;
EXCEPTION_RECORD* pExceptionRecord=ep->ExceptionRecord;
if (dwCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
u8* address=(u8*)pExceptionRecord->ExceptionInformation[1];
EXCEPTION_RECORD* pExceptionRecord = ep->ExceptionRecord;
u8* address = (u8 *)pExceptionRecord->ExceptionInformation[1];
//printf("[EXC] During access to : 0x%X\n", address);
#if 0
bool write = false; // TODO?
// WinCE virtual memory
bool write = false;
if (vmem32_handle_signal(address, write, 0))
return EXCEPTION_CONTINUE_EXECUTION;
#endif
// code protection in RAM
if (bm_RamWriteAccess(address))
{
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (VramLockedWrite(address))
{
// texture protection in VRAM
if (VramLockedWrite(address))
return EXCEPTION_CONTINUE_EXECUTION;
}
else if (BM_LockedWrite(address))
{
// FPCB jump table protection
if (BM_LockedWrite(address))
return EXCEPTION_CONTINUE_EXECUTION;
}
host_context_t context;
readContext(ep, context);
#if FEAT_SHREC == DYNAREC_JIT
#if HOST_CPU == CPU_X86
else if ( ngen_Rewrite((unat&)ep->ContextRecord->Eip,*(unat*)ep->ContextRecord->Esp,ep->ContextRecord->Eax) )
{
//remove the call from call stack
ep->ContextRecord->Esp+=4;
//restore the addr from eax to ecx so its valid again
ep->ContextRecord->Ecx=ep->ContextRecord->Eax;
return EXCEPTION_CONTINUE_EXECUTION;
}
#elif HOST_CPU == CPU_X64
else if (ngen_Rewrite((unat&)ep->ContextRecord->Rip, 0, 0))
{
return EXCEPTION_CONTINUE_EXECUTION;
}
#endif
#endif
else
// fast mem access rewriting
if (ngen_Rewrite(context, address))
{
ERROR_LOG(COMMON, "[GPF]Unhandled access to : %p", address);
os_DebugBreak();
writeContext(ep, context);
return EXCEPTION_CONTINUE_EXECUTION;
}
#endif
ERROR_LOG(COMMON, "[GPF] PC %p unhandled access to %p", (void *)context.pc, address);
os_DebugBreak();
return EXCEPTION_CONTINUE_SEARCH;
}
@ -592,7 +609,6 @@ void ReserveBottomMemory()
}
#ifdef _WIN64
#include "hw/sh4/dyna/ngen.h"
typedef union _UNWIND_CODE {
struct {

View File

@ -568,7 +568,6 @@
84B7BE631B72720100F9733F /* khrplatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = khrplatform.h; sourceTree = "<group>"; };
84B7BE651B72720100F9733F /* common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = common.cpp; sourceTree = "<group>"; };
84B7BE661B72720100F9733F /* context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = context.cpp; sourceTree = "<group>"; };
84B7BE671B72720100F9733F /* context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = context.h; sourceTree = "<group>"; };
84B7BE6E1B72720200F9733F /* nullDC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = nullDC.cpp; path = ../../../core/nullDC.cpp; sourceTree = "<group>"; };
84B7BE701B72720200F9733F /* audiobackend_alsa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audiobackend_alsa.cpp; sourceTree = "<group>"; };
84B7BE711B72720200F9733F /* audiobackend_alsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audiobackend_alsa.h; sourceTree = "<group>"; };
@ -1805,7 +1804,6 @@
children = (
84B7BE651B72720100F9733F /* common.cpp */,
84B7BE661B72720100F9733F /* context.cpp */,
84B7BE671B72720100F9733F /* context.h */,
AEF2564722886A2E00348550 /* posix_vmem.cpp */,
);
name = linux;