Use direct jumps on MIPS hosts. The jump address has to be written atomically, so a R_MIPS_26 needs to be used. It means the code generation buffer should not be bigger than 256MB, and has to be aligned on a 256MB boundary.
Signed-off-by: Aurelien Jarno <aurel...@aurel32.net> --- exec-all.h | 13 ++++++++++++- exec.c | 7 +++++++ tcg/mips/tcg-target.c | 3 ++- tcg/mips/tcg-target.h | 5 ----- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/exec-all.h b/exec-all.h index 820b59e..21d6c91 100644 --- a/exec-all.h +++ b/exec-all.h @@ -114,7 +114,7 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, #define CODE_GEN_AVG_BLOCK_SIZE 64 #endif -#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) +#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) || defined(__mips__) #define USE_DIRECT_JUMP #endif @@ -222,6 +222,17 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); #endif } +#elif defined(__mips__) +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) +{ + *(uint32_t *)jmp_addr = 0x08000000 | ((addr >> 2) & 0x03ffffff); +#if QEMU_GNUC_PREREQ(4, 1) + void __clear_cache(char *beg, char *end); + __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); +#else +# error __clear_cache not available +#endif +} #endif static inline void tb_set_jmp_target(TranslationBlock *tb, diff --git a/exec.c b/exec.c index 076d26b..1d3f48c 100644 --- a/exec.c +++ b/exec.c @@ -454,6 +454,13 @@ static void code_gen_alloc(unsigned long tb_size) start = (void *) 0x01000000UL; if (code_gen_buffer_size > 16 * 1024 * 1024) code_gen_buffer_size = 16 * 1024 * 1024; +#elif defined(__mips__) + /* Map the buffer aligned on a 256M boundary, so we can use direct + calls and branches (R_MIPS_26 relocation) */ + flags |= MAP_FIXED; + start = (void *) 0x30000000UL; + if (code_gen_buffer_size > 256 * 1024 * 1024) + code_gen_buffer_size = 256 * 1024 * 1024; #endif code_gen_buffer = mmap(start, code_gen_buffer_size, PROT_WRITE | PROT_READ | PROT_EXEC, diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 03fdcbf..d445169 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -1042,7 +1042,8 @@ static inline void tcg_out_op(TCGContext *s, int opc, case INDEX_op_goto_tb: if (s->tb_jmp_offset) { /* direct jump method */ - tcg_abort(); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + s->code_ptr += 4; } else { /* indirect jump method */ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (tcg_target_long)(s->tb_next + args[0])); diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index ba91623..3d36100 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -98,10 +98,5 @@ enum { static inline void flush_icache_range(unsigned long start, unsigned long stop) { -#if QEMU_GNUC_PREREQ(4, 1) - void __clear_cache(char *beg, char *end); __clear_cache((char *) start, (char *) stop); -#else -# error __clear_cache not available -#endif } -- 1.6.1.3