3 This code was written as part of the CMU Common Lisp project at
4 Carnegie Mellon University, and has been placed in the public domain.
19 #include "interrupt.h"
21 #include "breakpoint.h"
24 #include "genesis/constants.h"
26 #define INSN_LEN sizeof(unsigned int)
35 arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
37 /* Classic CMUCL comment:
39 Finding the bad address on the mips is easy. */
40 return (os_vm_address_t)siginfo->si_addr;
43 static inline unsigned int
44 os_context_register(os_context_t *context, int offset)
46 return (unsigned int)(*os_context_register_addr(context, offset));
49 static inline unsigned int
50 os_context_pc(os_context_t *context)
52 return (unsigned int)(*os_context_pc_addr(context));
55 static inline unsigned int
56 os_context_insn(os_context_t *context)
58 if (os_context_bd_cause(context))
59 return *(unsigned int *)(os_context_pc(context) + INSN_LEN);
61 return *(unsigned int *)(os_context_pc(context));
65 arch_insn_with_bdelay_p(unsigned int insn)
69 switch (insn & 0x3f) {
76 /* branches and immediate jumps */
78 switch ((insn >> 16) & 0x1f) {
100 switch ((insn >> 21) & 0x1f) {
101 /* CP0/CP1/CP2 branches */
106 /* branch likely (MIPS II) */
116 /* Find the next instruction in the control flow. For a instruction
117 with branch delay slot, this is the branch/jump target if the branch
118 is taken, and PC + 8 if it is not taken. For other instructions it
121 next_insn_addr(os_context_t *context, unsigned int inst)
123 unsigned int opcode = inst >> 26;
124 unsigned int r1 = (inst >> 21) & 0x1f;
125 unsigned int r2 = (inst >> 16) & 0x1f;
126 unsigned int r3 = (inst >> 11) & 0x1f;
127 unsigned int disp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
128 unsigned int jtgt = (os_context_pc(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2;
129 unsigned int tgt = os_context_pc(context);
132 case 0x0: /* jr, jalr */
133 switch(inst & 0x3f) {
135 tgt = os_context_register(context, r1);
137 case 0x09: /* jalr */
138 tgt = os_context_register(context, r1);
139 *os_context_register_addr(context, r3)
140 = os_context_pc(context) + INSN_LEN;
147 case 0x1: /* bltz, bgez, bltzal, bgezal, ... */
149 case 0x00: /* bltz */
150 case 0x02: /* bltzl */
151 if(os_context_register(context, r1) < 0)
156 case 0x01: /* bgez */
157 case 0x03: /* bgezl */
158 if(os_context_register(context, r1) >= 0)
163 case 0x10: /* bltzal */
164 case 0x12: /* bltzall */
165 if(os_context_register(context, r1) < 0) {
167 *os_context_register_addr(context, 31)
168 = os_context_pc(context) + INSN_LEN;
172 case 0x11: /* bgezal */
173 case 0x13: /* bgezall */
174 if(os_context_register(context, r1) >= 0) {
176 *os_context_register_addr(context, 31)
177 = os_context_pc(context) + INSN_LEN;
191 *os_context_register_addr(context, 31)
192 = os_context_pc(context) + INSN_LEN;
195 case 0x14: /* beql */
196 if(os_context_register(context, r1)
197 == os_context_register(context, r2))
203 case 0x15: /* bnel */
204 if(os_context_register(context, r1)
205 != os_context_register(context, r2))
211 case 0x16: /* blezl */
212 if(os_context_register(context, r1)
213 <= os_context_register(context, r2))
219 case 0x17: /* bgtzl */
220 if(os_context_register(context, r1)
221 > os_context_register(context, r2))
230 /* CP0/CP1/CP2 branches */
245 arch_skip_instruction(os_context_t *context)
247 /* Skip the offending instruction. Don't use os_context_insn here,
248 since in case of a branch we want the branch insn, not the delay
250 *os_context_pc_addr(context)
251 = (os_context_register_t)
252 next_insn_addr(context,
253 *(unsigned int *)(os_context_pc(context)));
257 arch_internal_error_arguments(os_context_t *context)
259 if (os_context_bd_cause(context))
260 return (unsigned char *)(os_context_pc(context) + (INSN_LEN * 2));
262 return (unsigned char *)(os_context_pc(context) + INSN_LEN);
266 arch_pseudo_atomic_atomic(os_context_t *context)
268 return os_context_register(context, reg_ALLOC) & 1;
272 arch_set_pseudo_atomic_interrupted(os_context_t *context)
274 *os_context_register_addr(context, reg_NL4) |= -1LL<<31;
278 arch_install_breakpoint(void *pc)
280 unsigned int *ptr = (unsigned int *)pc;
283 /* Don't install over a branch/jump with delay slot. */
284 if (arch_insn_with_bdelay_p(*ptr))
288 *ptr = (trap_Breakpoint << 6) | 0xd;
289 os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
294 static inline unsigned int
295 arch_install_after_breakpoint(void *pc)
297 unsigned int *ptr = (unsigned int *)pc;
300 /* Don't install over a branch/jump with delay slot. */
301 if (arch_insn_with_bdelay_p(*ptr))
305 *ptr = (trap_AfterBreakpoint << 6) | 0xd;
306 os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
312 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
314 unsigned int *ptr = (unsigned int *)pc;
316 /* We may remove from a branch delay slot. */
317 if (arch_insn_with_bdelay_p(*ptr))
321 os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
324 /* Perform the instruction that we overwrote with a breakpoint. As we
325 don't have a single-step facility, this means we have to:
326 - put the instruction back
327 - put a second breakpoint at the following instruction,
328 set after_breakpoint and continue execution.
330 When the second breakpoint is hit (very shortly thereafter, we hope)
331 sigtrap_handler gets called again, but follows the AfterBreakpoint
333 - puts a bpt back in the first breakpoint place (running across a
334 breakpoint shouldn't cause it to be uninstalled)
335 - replaces the second bpt with the instruction it was meant to be
340 static unsigned int *skipped_break_addr, displaced_after_inst;
341 static sigset_t orig_sigmask;
344 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
346 unsigned int *pc = (unsigned int *)os_context_pc(context);
347 unsigned int *next_pc;
349 orig_sigmask = *os_context_sigmask_addr(context);
350 sigaddset_blockable(os_context_sigmask_addr(context));
352 /* Put the original instruction back. */
353 arch_remove_breakpoint(pc, orig_inst);
354 skipped_break_addr = pc;
356 /* Figure out where it goes. */
357 next_pc = (unsigned int *)next_insn_addr(context, *pc);
358 displaced_after_inst = arch_install_after_breakpoint(next_pc);
362 sigtrap_handler(int signal, siginfo_t *info, void *void_context)
364 os_context_t *context = arch_os_get_context(&void_context);
365 unsigned int code = (os_context_insn(context) >> 6) & 0xfffff;
369 fake_foreign_function_call(context);
370 lose("%%primitive halt called; the party is over.\n");
372 case trap_PendingInterrupt:
373 arch_skip_instruction(context);
374 interrupt_handle_pending(context);
379 interrupt_internal_error(signal, info, context, code == trap_Cerror);
382 case trap_Breakpoint:
383 handle_breakpoint(signal, info, context);
386 case trap_FunEndBreakpoint:
387 *os_context_pc_addr(context)
388 = (os_context_register_t)(unsigned int)
389 handle_fun_end_breakpoint(signal, info, context);
392 case trap_AfterBreakpoint:
393 arch_install_breakpoint(skipped_break_addr);
394 arch_remove_breakpoint((unsigned int *)os_context_pc(context),
395 displaced_after_inst);
396 *os_context_sigmask_addr(context) = orig_sigmask;
400 /* Clear the pseudo-atomic flag */
401 *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
402 arch_skip_instruction(context);
403 interrupt_handle_pending(context);
407 interrupt_handle_now(signal, info, context);
412 #define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
415 sigfpe_handler(int signal, siginfo_t *info, void *void_context)
417 os_context_t *context = arch_os_get_context(&void_context);
418 unsigned int bad_inst = os_context_insn(context);
419 unsigned int op, rs, rt, rd, funct, dest = 32;
423 op = (bad_inst >> 26) & 0x3f;
424 rs = (bad_inst >> 21) & 0x1f;
425 rt = (bad_inst >> 16) & 0x1f;
426 rd = (bad_inst >> 11) & 0x1f;
427 funct = bad_inst & 0x3f;
428 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
431 case 0x0: /* SPECIAL */
434 result = FIXNUM_VALUE(os_context_register(context, rs))
435 + FIXNUM_VALUE(os_context_register(context, rt));
440 result = FIXNUM_VALUE(os_context_register(context, rs))
441 - FIXNUM_VALUE(os_context_register(context, rt));
446 interrupt_handle_now(signal, info, context);
452 result = FIXNUM_VALUE(os_context_register(context,rs))
453 + (immed >> N_FIXNUM_TAG_BITS);
458 interrupt_handle_now(signal, info, context);
462 dynamic_space_free_pointer =
463 (lispobj *)(unsigned int)*os_context_register_addr(context,reg_ALLOC);
465 *os_context_register_addr(context,dest) = alloc_number(result);
467 *os_context_register_addr(context, reg_ALLOC) =
468 (unsigned int) dynamic_space_free_pointer;
470 arch_skip_instruction(context);
474 arch_install_interrupt_handlers()
476 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
477 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
480 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
483 funcall0(lispobj function)
485 lispobj *args = current_control_stack_pointer;
487 return call_into_lisp(function, args, 0);
491 funcall1(lispobj function, lispobj arg0)
493 lispobj *args = current_control_stack_pointer;
495 current_control_stack_pointer += 1;
498 return call_into_lisp(function, args, 1);
502 funcall2(lispobj function, lispobj arg0, lispobj arg1)
504 lispobj *args = current_control_stack_pointer;
506 current_control_stack_pointer += 2;
510 return call_into_lisp(function, args, 2);
514 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
516 lispobj *args = current_control_stack_pointer;
518 current_control_stack_pointer += 3;
523 return call_into_lisp(function, args, 3);