aboutsummaryrefslogtreecommitdiff
path: root/libpcsxcore
diff options
context:
space:
mode:
authornotaz2016-09-19 02:40:17 +0300
committernotaz2016-09-19 02:43:55 +0300
commitd148d26560527efdd71685df8eac0497827ca766 (patch)
tree46a2775848ca37860515062b3a383632ae0acb2b /libpcsxcore
parent1fedf1ea555e4a6be68dd0ba384909ac21da65d0 (diff)
downloadpcsx_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.c33
-rw-r--r--libpcsxcore/new_dynarec/assem_arm.h12
-rw-r--r--libpcsxcore/new_dynarec/linkage_arm.S11
-rw-r--r--libpcsxcore/new_dynarec/new_dynarec.c103
-rw-r--r--libpcsxcore/new_dynarec/new_dynarec_config.h13
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