X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fmips-arch.c;h=125e163312bc399091352d31c9220e53f741287b;hb=5e92e9ed61903658015c2a75c79a32ad41dbd29d;hp=bfcff9c0546969960268a79f53c0dbe734a40e53;hpb=b3e3fbe7d381147fccc8a3027cb6fae923e57d13;p=sbcl.git diff --git a/src/runtime/mips-arch.c b/src/runtime/mips-arch.c index bfcff9c..125e163 100644 --- a/src/runtime/mips-arch.c +++ b/src/runtime/mips-arch.c @@ -23,6 +23,8 @@ #include "genesis/constants.h" +#define INSN_LEN 4 + void arch_init() { @@ -53,7 +55,62 @@ os_context_pc(os_context_t *context) static inline unsigned int os_context_insn(os_context_t *context) { - return *(unsigned int *)(os_context_pc(context)); + if (os_context_bd_cause(context)) + return *(unsigned int *)(os_context_pc(context) + INSN_LEN); + else + return *(unsigned int *)(os_context_pc(context)); +} + +boolean +arch_insn_with_bdelay_p(unsigned int insn) +{ + switch (insn >> 26) { + case 0x0: + switch (insn & 0x3f) { + /* register jumps */ + case 0x08: + case 0x09: + return 1; + } + break; + /* branches and immediate jumps */ + case 0x1: + switch ((insn >> 16) & 0x1f) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + return 1; + } + break; + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + return 1; + case 0x10: + case 0x11: + case 0x12: + switch ((insn >> 21) & 0x1f) { + /* CP0/CP1/CP2 branches */ + case 0x08: + return 1; + } + break; + /* branch likely (MIPS II) */ + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return 1; + } + return 0; } /* This function is somewhat misnamed, it actually just jumps to the @@ -79,10 +136,10 @@ emulate_branch(os_context_t *context, unsigned int inst) case 0x09: /* jalr */ tgt = os_context_register(context, r1); *os_context_register_addr(context, r3) - = os_context_pc(context) + 4; + = os_context_pc(context) + INSN_LEN; break; default: - tgt += 4; + tgt += INSN_LEN; break; } break; @@ -100,13 +157,13 @@ emulate_branch(os_context_t *context, unsigned int inst) if(os_context_register(context, r1) < 0) tgt += disp; *os_context_register_addr(context, 31) - = os_context_pc(context) + 4; + = os_context_pc(context) + INSN_LEN; break; case 0x11: /* bgezal */ if(os_context_register(context, r1) >= 0) tgt += disp; *os_context_register_addr(context, 31) - = os_context_pc(context) + 4; + = os_context_pc(context) + INSN_LEN; break; default: /* conditional branches/traps for > MIPS I, ignore for now. */ break; @@ -138,7 +195,7 @@ emulate_branch(os_context_t *context, unsigned int inst) case 0x3: /* jal */ tgt = jtgt; *os_context_register_addr(context, 31) - = os_context_pc(context) + 4; + = os_context_pc(context) + INSN_LEN; break; default: tgt += 4; @@ -150,18 +207,21 @@ emulate_branch(os_context_t *context, unsigned int inst) void arch_skip_instruction(os_context_t *context) { - /* Skip the offending instruction */ - *os_context_pc_addr(context) - = emulate_branch(context, os_context_insn(context)); + /* Skip the offending instruction. Don't use os_context_insn here, + since in case of a branch we want the branch insn, not the delay + slot. */ + *os_context_pc_addr(context) + = emulate_branch(context, + *(unsigned int *)(os_context_pc(context))); } unsigned char * arch_internal_error_arguments(os_context_t *context) { if (os_context_bd_cause(context)) - return (unsigned char *)(os_context_pc(context) + 8); + return (unsigned char *)(os_context_pc(context) + (INSN_LEN * 2)); else - return (unsigned char *)(os_context_pc(context) + 4); + return (unsigned char *)(os_context_pc(context) + INSN_LEN); } boolean @@ -180,31 +240,16 @@ unsigned long arch_install_breakpoint(void *pc) { unsigned int *ptr = (unsigned int *)pc; + unsigned int insn = *ptr; unsigned long result; - /* Don't install over a branch/jump. */ - switch (*ptr >> 26) { - case 0x0: /* immediate jumps */ - switch (*ptr & 0x3f) { - case 0x08: - case 0x09: + /* Don't install over a branch/jump with delay slot. */ + if (arch_insn_with_bdelay_p(insn)) ptr++; - } - break; - /* branches and register jumps */ - case 0x1: - case 0x2: - case 0x3: - case 0x4: - case 0x5: - case 0x6: - case 0x7: - ptr++; - } - result = (unsigned long) *ptr; + result = (unsigned long)insn; *ptr = (trap_Breakpoint << 16) | 0xd; - os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int)); + os_flush_icache((os_vm_address_t)ptr, INSN_LEN); return result; } @@ -215,7 +260,7 @@ arch_remove_breakpoint(void *pc, unsigned long orig_inst) unsigned int *ptr = (unsigned int *)pc; *ptr = (unsigned int) orig_inst; - os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int)); + os_flush_icache((os_vm_address_t)ptr, INSN_LEN); } static unsigned int *skipped_break_addr, displaced_after_inst; @@ -251,15 +296,6 @@ arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) } static void -sigill_handler(int signal, siginfo_t *info, void *void_context) -{ - os_context_t *context = arch_os_get_context(&void_context); - - fake_foreign_function_call(context); - monitor_or_something(); -} - -static void sigtrap_handler(int signal, siginfo_t *info, void *void_context) { os_context_t *context = arch_os_get_context(&void_context); @@ -314,16 +350,11 @@ sigtrap_handler(int signal, siginfo_t *info, void *void_context) static void sigfpe_handler(int signal, siginfo_t *info, void *void_context) { - unsigned int bad_inst; + os_context_t *context = arch_os_get_context(&void_context); + unsigned int bad_inst = os_context_insn(context); unsigned int op, rs, rt, rd, funct, dest = 32; int immed; int result; - os_context_t *context = arch_os_get_context(&void_context); - - if (os_context_bd_cause(context)) - bad_inst = *(unsigned int *)(os_context_pc(context) + 4); - else - bad_inst = os_context_insn(context); op = (bad_inst >> 26) & 0x3f; rs = (bad_inst >> 21) & 0x1f; @@ -378,7 +409,6 @@ sigfpe_handler(int signal, siginfo_t *info, void *void_context) void arch_install_interrupt_handlers() { - undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler); undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler); undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler); }