#include <assert.h>
#include <errno.h>
#include <sys/mman.h>
+#ifdef __MACH__
+#include <libkern/OSCacheControl.h>
+#endif
+#ifdef _3DS
+#include <3ds_utils.h>
+#endif
+#ifdef VITA
+#include <psp2/kernel/sysmem.h>
+static int sceBlock;
+#endif
+#include "new_dynarec_config.h"
#include "emu_if.h" //emulator interface
//#define DISASM
#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
static int tracedebug=0;
+static void mprotect_w_x(void *start, void *end, int is_x)
+{
+#ifdef NO_WRITE_EXEC
+ #if defined(VITA)
+ // *Open* enables write on all memory that was
+ // allocated by sceKernelAllocMemBlockForVM()?
+ if (is_x)
+ sceKernelCloseVMDomain();
+ else
+ sceKernelOpenVMDomain();
+ #else
+ 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
+#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)
+ sceKernelSyncVMDomain(sceBlock, start, len);
+ #elif defined(_3DS)
+ ctr_flush_invalidate_cache();
+ #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
}
// 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);
(((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;
}
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;
restore_candidate[(page&2047)>>3]|=1<<(page&7);
restore_candidate[((page&2047)>>3)+256]|=1<<(page&7);
}
- #ifdef __arm__
- __clear_cache((void *)BASE_ADDR,(void *)BASE_ADDR+(1<<TARGET_SIZE_2));
- #endif
#ifdef USE_MINI_HT
memset(mini_ht,-1,sizeof(mini_ht));
#endif
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)
void new_dynarec_init()
{
SysPrintf("Init new dynarec\n");
- out=(u_char *)BASE_ADDR;
-#if BASE_ADDR_FIXED
- if (mmap (out, 1<<TARGET_SIZE_2,
+
+ // allocate/prepare a buffer for translation cache
+ // see assem_arm.h for some explanation
+#if defined(BASE_ADDR_FIXED)
+ if (mmap (translation_cache, 1 << TARGET_SIZE_2,
PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0) <= 0) {
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0) != translation_cache) {
SysPrintf("mmap() failed: %s\n", strerror(errno));
+ SysPrintf("disable BASE_ADDR_FIXED and recompile\n");
+ abort();
+ }
+#elif defined(BASE_ADDR_DYNAMIC)
+ #ifdef VITA
+ sceBlock = sceKernelAllocMemBlockForVM("code", 1 << TARGET_SIZE_2);
+ if (sceBlock < 0)
+ SysPrintf("sceKernelAllocMemBlockForVM failed\n");
+ int ret = sceKernelGetMemBlockBase(sceBlock, (void **)&translation_cache);
+ if (ret < 0)
+ SysPrintf("sceKernelGetMemBlockBase failed\n");
+ #else
+ translation_cache = mmap (NULL, 1 << TARGET_SIZE_2,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (translation_cache == MAP_FAILED) {
+ SysPrintf("mmap() failed: %s\n", strerror(errno));
+ abort();
}
+ #endif
#else
+ #ifndef 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)
+ if (mprotect((void *)BASE_ADDR, 1<<TARGET_SIZE_2, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
SysPrintf("mprotect() failed: %s\n", strerror(errno));
+ #endif
#endif
+ out=(u_char *)BASE_ADDR;
cycle_multiplier=200;
new_dynarec_clear_full();
#ifdef HOST_IMM8
void new_dynarec_cleanup()
{
int n;
- #if BASE_ADDR_FIXED
- if (munmap ((void *)BASE_ADDR, 1<<TARGET_SIZE_2) < 0) {SysPrintf("munmap() failed\n");}
+#if defined(BASE_ADDR_FIXED) || defined(BASE_ADDR_DYNAMIC)
+ #ifdef VITA
+ sceKernelFreeMemBlock(sceBlock);
+ sceBlock = -1;
+ #else
+ if (munmap ((void *)BASE_ADDR, 1<<TARGET_SIZE_2) < 0)
+ SysPrintf("munmap() failed\n");
#endif
+#endif
for(n=0;n<4096;n++) ll_clear(jump_in+n);
for(n=0;n<4096;n++) ll_clear(jump_out+n);
for(n=0;n<4096;n++) ll_clear(jump_dirty+n);
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;
}
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();
// 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?)