diff options
author | notaz | 2016-09-19 02:40:17 +0300 |
---|---|---|
committer | notaz | 2016-09-19 02:43:55 +0300 |
commit | d148d26560527efdd71685df8eac0497827ca766 (patch) | |
tree | 46a2775848ca37860515062b3a383632ae0acb2b /libpcsxcore | |
parent | 1fedf1ea555e4a6be68dd0ba384909ac21da65d0 (diff) | |
download | pcsx_rearmed-d148d26560527efdd71685df8eac0497827ca766.tar.gz pcsx_rearmed-d148d26560527efdd71685df8eac0497827ca766.tar.bz2 pcsx_rearmed-d148d26560527efdd71685df8eac0497827ca766.zip |
drc: try to support w^x platforms like iOS
untested...
Diffstat (limited to 'libpcsxcore')
-rw-r--r-- | libpcsxcore/new_dynarec/assem_arm.c | 33 | ||||
-rw-r--r-- | libpcsxcore/new_dynarec/assem_arm.h | 12 | ||||
-rw-r--r-- | libpcsxcore/new_dynarec/linkage_arm.S | 11 | ||||
-rw-r--r-- | libpcsxcore/new_dynarec/new_dynarec.c | 103 | ||||
-rw-r--r-- | libpcsxcore/new_dynarec/new_dynarec_config.h | 13 |
5 files changed, 114 insertions, 58 deletions
diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index 9a5e3a9..6c3826c 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 2d10ac7..acf65bd 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 95af8b4..147b0df 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 bfe3961..ec2a6fa 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -23,7 +23,11 @@ #include <assert.h> #include <errno.h> #include <sys/mman.h> +#ifdef __MACH__ +#include <libkern/OSCacheControl.h> +#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 <libkern/OSCacheControl.h> -#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<<TARGET_SIZE_2)) + end = (u_char *)BASE_ADDR + (1<<TARGET_SIZE_2); + start_tcache_write(out, end); + return out; +} + +static void end_block(void *start) +{ + end_tcache_write(start, out); +} + //#define DEBUG_CYCLE_COUNT 1 #define NO_CYCLE_PENALTY_THR 12 @@ -829,7 +870,7 @@ void ll_clear(struct ll_entry **head) } // Dereference the pointers and remove if it matches -void ll_kill_pointers(struct ll_entry *head,int addr,int shift) +static void ll_kill_pointers(struct ll_entry *head,int addr,int shift) { while(head) { int ptr=get_pointer(head->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<<TARGET_SIZE_2, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) SysPrintf("mprotect() failed: %s\n", strerror(errno)); @@ -7172,16 +7216,15 @@ int new_recompile_block(int addr) if (Config.HLE && start == 0x80001000) // hlecall { // XXX: is this enough? Maybe check hleSoftCall? - u_int beginning=(u_int)out; + void *beginning=start_block(); u_int page=get_page(start); + invalid_code[start>>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<MAX_OUTPUT_BLOCK_SIZE); + assert((u_int)out-(u_int)beginning<MAX_OUTPUT_BLOCK_SIZE); //printf("shadow buffer: %x-%x\n",(int)copy,(int)copy+slen*4); memcpy(copy,source,slen*4); copy+=slen*4; - #ifdef __arm__ - __clear_cache((void *)beginning,out); - #endif + end_block(beginning); // If we're within 256K of the end of the buffer, // start over from the beginning. (Is 256K enough?) diff --git a/libpcsxcore/new_dynarec/new_dynarec_config.h b/libpcsxcore/new_dynarec/new_dynarec_config.h new file mode 100644 index 0000000..86af297 --- /dev/null +++ b/libpcsxcore/new_dynarec/new_dynarec_config.h @@ -0,0 +1,13 @@ + + +#define CORTEX_A8_BRANCH_PREDICTION_HACK 1 +#define USE_MINI_HT 1 +//#define REG_PREFETCH 1 + +#ifndef BASE_ADDR_FIXED +#define BASE_ADDR_FIXED 0 +#endif + +#ifdef __MACH__ +#define NO_WRITE_EXEC +#endif |