From: notaz Date: Sun, 18 Sep 2016 23:40:17 +0000 (+0300) Subject: drc: try to support w^x platforms like iOS X-Git-Tag: r23~167 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=commitdiff_plain;h=d148d26560527efdd71685df8eac0497827ca766 drc: try to support w^x platforms like iOS untested... --- diff --git a/frontend/libretro.c b/frontend/libretro.c index 37cccc4f..940ff05a 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -10,6 +10,10 @@ #include #include #include +#ifdef __MACH__ +#include +#include +#endif #include "../libpcsxcore/misc.h" #include "../libpcsxcore/psxcounters.h" @@ -1202,6 +1206,11 @@ void retro_init(void) int i, ret; bool found_bios = false; +#ifdef __MACH__ + // magic sauce to make the dynarec work on iOS + syscall(SYS_ptrace, 0 /*PTRACE_TRACEME*/, 0, 0, 0); +#endif + ret = emu_core_preinit(); ret |= emu_core_init(); if (ret != 0) { diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index 9a5e3a94..6c3826c0 100644 --- a/libpcsxcore/new_dynarec/assem_arm.c +++ b/libpcsxcore/new_dynarec/assem_arm.c @@ -114,7 +114,7 @@ const u_int invalidate_addr_reg[16] = { 0, 0}; -static unsigned int needs_clear_cache[1<<(TARGET_SIZE_2-17)]; +static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)]; /* Linker */ @@ -193,15 +193,15 @@ static void add_literal(int addr,int val) literalcount++; } -static void *kill_pointer(void *stub) +// from a pointer to external jump stub (which was produced by emit_extjump2) +// find where the jumping insn is +static void *find_extjump_insn(void *stub) { int *ptr=(int *)(stub+4); - assert((*ptr&0x0ff00000)==0x05900000); + assert((*ptr&0x0fff0000)==0x059f0000); // ldr rx, [pc, #ofs] u_int offset=*ptr&0xfff; - int **l_ptr=(void *)ptr+offset+8; - int *i_ptr=*l_ptr; - set_jump_target((int)i_ptr,(int)stub); - return i_ptr; + void **l_ptr=(void *)ptr+offset+8; + return *l_ptr; } // find where external branch is liked to using addr of it's stub: @@ -211,11 +211,7 @@ static void *kill_pointer(void *stub) static int get_pointer(void *stub) { //printf("get_pointer(%x)\n",(int)stub); - int *ptr=(int *)(stub+4); - assert((*ptr&0x0fff0000)==0x059f0000); - u_int offset=*ptr&0xfff; - int **l_ptr=(void *)ptr+offset+8; - int *i_ptr=*l_ptr; + int *i_ptr=find_extjump_insn(stub); assert((*i_ptr&0x0f000000)==0x0a000000); return (int)i_ptr+((*i_ptr<<8)>>6)+8; } @@ -4094,6 +4090,17 @@ static void wb_invalidate_arm(signed char pre[],signed char entry[],uint64_t dir #define wb_invalidate wb_invalidate_arm */ +static void mark_clear_cache(void *target) +{ + u_long offset = (char *)target - (char *)BASE_ADDR; + u_int mask = 1u << ((offset >> 12) & 31); + if (!(needs_clear_cache[offset >> 17] & mask)) { + char *start = (char *)((u_long)target & ~4095ul); + start_tcache_write(start, start + 4096); + needs_clear_cache[offset >> 17] |= mask; + } +} + // Clearing the cache is rather slow on ARM Linux, so mark the areas // that need to be cleared, and then only clear these areas once. static void do_clear_cache() @@ -4115,7 +4122,7 @@ static void do_clear_cache() end+=4096; j++; }else{ - __clear_cache((void *)start,(void *)end); + end_tcache_write((void *)start,(void *)end); break; } } diff --git a/libpcsxcore/new_dynarec/assem_arm.h b/libpcsxcore/new_dynarec/assem_arm.h index 2d10ac73..acf65bd7 100644 --- a/libpcsxcore/new_dynarec/assem_arm.h +++ b/libpcsxcore/new_dynarec/assem_arm.h @@ -5,21 +5,9 @@ #define HOST_IMM8 1 #define HAVE_CMOV_IMM 1 -#define CORTEX_A8_BRANCH_PREDICTION_HACK 1 -#define USE_MINI_HT 1 -//#define REG_PREFETCH 1 #define HAVE_CONDITIONAL_CALL 1 #define RAM_SIZE 0x200000 -#ifndef __ARM_ARCH_7A__ -//#undef CORTEX_A8_BRANCH_PREDICTION_HACK -//#undef USE_MINI_HT -#endif - -#ifndef BASE_ADDR_FIXED -#define BASE_ADDR_FIXED 0 -#endif - #define REG_SHIFT 2 /* ARM calling convention: diff --git a/libpcsxcore/new_dynarec/linkage_arm.S b/libpcsxcore/new_dynarec/linkage_arm.S index 95af8b4e..147b0dfc 100644 --- a/libpcsxcore/new_dynarec/linkage_arm.S +++ b/libpcsxcore/new_dynarec/linkage_arm.S @@ -20,6 +20,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "arm_features.h" +#include "new_dynarec_config.h" #include "linkage_offsets.h" @@ -160,9 +161,10 @@ ptr_hash_table: #endif .endm +/* r0 = virtual target address */ +/* r1 = instruction to patch */ .macro dyna_linker_main - /* r0 = virtual target address */ - /* r1 = instruction to patch */ +#ifndef NO_WRITE_EXEC load_varadr_ext r3, jump_in /* get_page */ lsr r2, r0, #12 @@ -242,6 +244,11 @@ ptr_hash_table: str r3, [r6, #12] mov pc, r1 8: +#else + /* XXX: should be able to do better than this... */ + bl get_addr_ht + mov pc, r0 +#endif .endm diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index bfe3961e..ec2a6fae 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -23,7 +23,11 @@ #include #include #include +#ifdef __MACH__ +#include +#endif +#include "new_dynarec_config.h" #include "emu_if.h" //emulator interface //#define DISASM @@ -42,19 +46,6 @@ #include "assem_arm.h" #endif -#ifdef __BLACKBERRY_QNX__ -#undef __clear_cache -#define __clear_cache(start,end) msync(start, (size_t)((void*)end - (void*)start), MS_SYNC | MS_CACHE_ONLY | MS_INVALIDATE_ICACHE); -#elif defined(__MACH__) -#include -#define __clear_cache mach_clear_cache -static void __clear_cache(void *start, void *end) { - size_t len = (char *)end - (char *)start; - sys_dcache_flush(start, len); - sys_icache_invalidate(start, len); -} -#endif - #define MAXBLOCK 4096 #define MAX_OUTPUT_BLOCK_SIZE 262144 @@ -271,6 +262,56 @@ static void add_to_linker(int addr,int target,int ext); static int tracedebug=0; +static void mprotect_w_x(void *start, void *end, int is_x) +{ +#ifdef NO_WRITE_EXEC + u_long mstart = (u_long)start & ~4095ul; + u_long mend = (u_long)end; + if (mprotect((void *)mstart, mend - mstart, + PROT_READ | (is_x ? PROT_EXEC : PROT_WRITE)) != 0) + SysPrintf("mprotect(%c) failed: %s\n", is_x ? 'x' : 'w', strerror(errno)); +#endif +} + +static void start_tcache_write(void *start, void *end) +{ + mprotect_w_x(start, end, 0); +} + +static void end_tcache_write(void *start, void *end) +{ +#ifdef __arm__ + size_t len = (char *)end - (char *)start; + #if defined(__BLACKBERRY_QNX__) + msync(start, len, MS_SYNC | MS_CACHE_ONLY | MS_INVALIDATE_ICACHE); + #elif defined(__MACH__) + sys_cache_control(kCacheFunctionPrepareForExecution, start, len); + #elif defined(VITA) + int block = sceKernelFindMemBlockByAddr(start, len); + sceKernelSyncVMDomain(block, start, len); + #else + __clear_cache(start, end); + #endif + (void)len; +#endif + + mprotect_w_x(start, end, 1); +} + +static void *start_block(void) +{ + u_char *end = out + MAX_OUTPUT_BLOCK_SIZE; + if (end > (u_char *)BASE_ADDR + (1<addr); @@ -838,10 +879,11 @@ void ll_kill_pointers(struct ll_entry *head,int addr,int shift) (((ptr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(addr>>shift))) { inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr); - u_int host_addr=(u_int)kill_pointer(head->addr); + void *host_addr=find_extjump_insn(head->addr); #ifdef __arm__ - needs_clear_cache[(host_addr-(u_int)BASE_ADDR)>>17]|=1<<(((host_addr-(u_int)BASE_ADDR)>>12)&31); + mark_clear_cache(host_addr); #endif + set_jump_target((int)host_addr,(int)head->addr); } head=head->next; } @@ -865,10 +907,11 @@ void invalidate_page(u_int page) jump_out[page]=0; while(head!=NULL) { inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(int)head->addr); - u_int host_addr=(u_int)kill_pointer(head->addr); + void *host_addr=find_extjump_insn(head->addr); #ifdef __arm__ - needs_clear_cache[(host_addr-(u_int)BASE_ADDR)>>17]|=1<<(((host_addr-(u_int)BASE_ADDR)>>12)&31); + mark_clear_cache(host_addr); #endif + set_jump_target((int)host_addr,(int)head->addr); next=head->next; free(head); head=next; @@ -6936,13 +6979,14 @@ static void disassemble_inst(int i) {} static int new_dynarec_test(void) { int (*testfunc)(void) = (void *)out; + void *beginning; int ret; + + beginning = start_block(); emit_movimm(DRC_TEST_VAL,0); // test emit_jmpreg(14); literal_pool(0); -#ifdef __arm__ - __clear_cache((void *)testfunc, out); -#endif + end_block(beginning); SysPrintf("testing if we can run recompiled code..\n"); ret = testfunc(); if (ret == DRC_TEST_VAL) @@ -6987,7 +7031,7 @@ void new_dynarec_init() -1, 0) <= 0) { SysPrintf("mmap() failed: %s\n", strerror(errno)); } -#else +#elif !defined(NO_WRITE_EXEC) // not all systems allow execute in data segment by default if (mprotect(out, 1<>12]=0; emit_movimm(start,0); emit_writeword(0,(int)&pcaddr); emit_jmp((int)new_dyna_leave); literal_pool(0); -#ifdef __arm__ - __clear_cache((void *)beginning,out); -#endif + end_block(beginning); ll_add_flags(jump_in+page,start,state_rflags,(void *)beginning); return 0; } @@ -9883,7 +9926,7 @@ int new_recompile_block(int addr) cop1_usable=0; uint64_t is32_pre=0; u_int dirty_pre=0; - u_int beginning=(u_int)out; + void *beginning=start_block(); if((u_int)addr&1) { ds=1; pagespan_ds(); @@ -10173,14 +10216,12 @@ int new_recompile_block(int addr) // Align code if(((u_int)out)&7) emit_addnop(13); #endif - assert((u_int)out-beginning