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"
33 arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
35 /* Classic CMUCL comment:
37 Finding the bad address on the mips is easy. */
38 return (os_vm_address_t)siginfo->si_addr;
41 static inline unsigned int
42 os_context_register(os_context_t *context, int offset)
44 return (unsigned int)(*os_context_register_addr(context, offset));
47 static inline unsigned int
48 os_context_pc(os_context_t *context)
50 return (unsigned int)(*os_context_pc_addr(context));
53 static inline unsigned int
54 os_context_insn(os_context_t *context)
56 return *(unsigned int *)(os_context_pc(context));
59 /* This function is somewhat misnamed, it actually just jumps to the
60 correct target address without attempting to execute the delay slot.
61 For other instructions it just increments the returned PC value. */
63 emulate_branch(os_context_t *context, unsigned int inst)
65 unsigned int opcode = inst >> 26;
66 unsigned int r1 = (inst >> 21) & 0x1f;
67 unsigned int r2 = (inst >> 16) & 0x1f;
68 unsigned int r3 = (inst >> 11) & 0x1f;
69 unsigned int disp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
70 unsigned int jtgt = (os_context_pc(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2;
71 unsigned int tgt = os_context_pc(context);
74 case 0x0: /* jr, jalr */
77 tgt = os_context_register(context, r1);
80 tgt = os_context_register(context, r1);
81 *os_context_register_addr(context, r3)
82 = os_context_pc(context) + 4;
89 case 0x1: /* bltz, bgez, bltzal, bgezal */
90 switch((inst >> 16) & 0x1f) {
92 if(os_context_register(context, r1) < 0)
96 if(os_context_register(context, r1) >= 0)
99 case 0x10: /* bltzal */
100 if(os_context_register(context, r1) < 0)
102 *os_context_register_addr(context, 31)
103 = os_context_pc(context) + 4;
105 case 0x11: /* bgezal */
106 if(os_context_register(context, r1) >= 0)
108 *os_context_register_addr(context, 31)
109 = os_context_pc(context) + 4;
111 default: /* conditional branches/traps for > MIPS I, ignore for now. */
116 if(os_context_register(context, r1)
117 == os_context_register(context, r2))
121 if(os_context_register(context, r1)
122 != os_context_register(context, r2))
126 if(os_context_register(context, r1)
127 <= os_context_register(context, r2))
131 if(os_context_register(context, r1)
132 > os_context_register(context, r2))
140 *os_context_register_addr(context, 31)
141 = os_context_pc(context) + 4;
151 arch_skip_instruction(os_context_t *context)
153 /* Skip the offending instruction */
154 *os_context_pc_addr(context)
155 = emulate_branch(context, os_context_insn(context));
159 arch_internal_error_arguments(os_context_t *context)
161 if (os_context_bd_cause(context))
162 return (unsigned char *)(os_context_pc(context) + 8);
164 return (unsigned char *)(os_context_pc(context) + 4);
168 arch_pseudo_atomic_atomic(os_context_t *context)
170 return os_context_register(context, reg_ALLOC) & 1;
174 arch_set_pseudo_atomic_interrupted(os_context_t *context)
176 *os_context_register_addr(context, reg_NL4) |= -1LL<<31;
180 arch_install_breakpoint(void *pc)
182 unsigned int *ptr = (unsigned int *)pc;
183 unsigned long result;
185 /* Don't install over a branch/jump. */
186 switch (*ptr >> 26) {
187 case 0x0: /* immediate jumps */
188 switch (*ptr & 0x3f) {
194 /* branches and register jumps */
205 result = (unsigned long) *ptr;
206 *ptr = (trap_Breakpoint << 16) | 0xd;
207 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
213 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
215 unsigned int *ptr = (unsigned int *)pc;
217 *ptr = (unsigned int) orig_inst;
218 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
221 static unsigned int *skipped_break_addr, displaced_after_inst;
222 static sigset_t orig_sigmask;
225 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
227 unsigned int *pc = (unsigned int *)os_context_pc(context);
228 unsigned int *break_pc, *next_pc;
229 unsigned int next_inst;
231 orig_sigmask = *os_context_sigmask_addr(context);
232 sigaddset_blockable(os_context_sigmask_addr(context));
234 /* Figure out where the breakpoint is, and what happens next. */
235 if (os_context_bd_cause(context)) {
240 next_inst = orig_inst;
243 /* Put the original instruction back. */
244 arch_remove_breakpoint(break_pc, orig_inst);
245 skipped_break_addr = break_pc;
247 /* Figure out where it goes. */
248 next_pc = (unsigned int *)emulate_branch(context, next_inst);
250 displaced_after_inst = arch_install_breakpoint(next_pc);
254 sigill_handler(int signal, siginfo_t *info, void *void_context)
256 os_context_t *context = arch_os_get_context(&void_context);
258 fake_foreign_function_call(context);
259 monitor_or_something();
263 sigtrap_handler(int signal, siginfo_t *info, void *void_context)
265 os_context_t *context = arch_os_get_context(&void_context);
266 unsigned int code = (os_context_insn(context) >> 16) & 0x1f;
270 fake_foreign_function_call(context);
271 lose("%%primitive halt called; the party is over.\n");
273 case trap_PendingInterrupt:
274 arch_skip_instruction(context);
275 interrupt_handle_pending(context);
280 interrupt_internal_error(signal, info, context, code == trap_Cerror);
283 case trap_Breakpoint:
284 handle_breakpoint(signal, info, context);
287 case trap_FunEndBreakpoint:
288 *os_context_pc_addr(context)
289 = (os_context_register_t)(unsigned int)
290 handle_fun_end_breakpoint(signal, info, context);
293 case trap_AfterBreakpoint:
294 arch_remove_breakpoint(os_context_pc_addr(context), displaced_after_inst);
295 displaced_after_inst = arch_install_breakpoint(skipped_break_addr);
296 *os_context_sigmask_addr(context) = orig_sigmask;
300 /* Clear the pseudo-atomic flag */
301 *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
302 arch_skip_instruction(context);
303 interrupt_handle_pending(context);
307 interrupt_handle_now(signal, info, context);
312 #define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
315 sigfpe_handler(int signal, siginfo_t *info, void *void_context)
317 unsigned int bad_inst;
318 unsigned int op, rs, rt, rd, funct, dest = 32;
321 os_context_t *context = arch_os_get_context(&void_context);
323 if (os_context_bd_cause(context))
324 bad_inst = *(unsigned int *)(os_context_pc(context) + 4);
326 bad_inst = os_context_insn(context);
328 op = (bad_inst >> 26) & 0x3f;
329 rs = (bad_inst >> 21) & 0x1f;
330 rt = (bad_inst >> 16) & 0x1f;
331 rd = (bad_inst >> 11) & 0x1f;
332 funct = bad_inst & 0x3f;
333 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
336 case 0x0: /* SPECIAL */
339 result = FIXNUM_VALUE(os_context_register(context, rs))
340 + FIXNUM_VALUE(os_context_register(context, rt));
345 result = FIXNUM_VALUE(os_context_register(context, rs))
346 - FIXNUM_VALUE(os_context_register(context, rt));
351 interrupt_handle_now(signal, info, context);
357 result = FIXNUM_VALUE(os_context_register(context,rs))
358 + (immed >> N_FIXNUM_TAG_BITS);
363 interrupt_handle_now(signal, info, context);
367 dynamic_space_free_pointer =
368 (lispobj *)(unsigned int)*os_context_register_addr(context,reg_ALLOC);
370 *os_context_register_addr(context,dest) = alloc_number(result);
372 *os_context_register_addr(context, reg_ALLOC) =
373 (unsigned int) dynamic_space_free_pointer;
375 arch_skip_instruction(context);
379 arch_install_interrupt_handlers()
381 undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler);
382 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
383 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
386 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
389 funcall0(lispobj function)
391 lispobj *args = current_control_stack_pointer;
393 return call_into_lisp(function, args, 0);
397 funcall1(lispobj function, lispobj arg0)
399 lispobj *args = current_control_stack_pointer;
401 current_control_stack_pointer += 1;
404 return call_into_lisp(function, args, 1);
408 funcall2(lispobj function, lispobj arg0, lispobj arg1)
410 lispobj *args = current_control_stack_pointer;
412 current_control_stack_pointer += 2;
416 return call_into_lisp(function, args, 2);
420 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
422 lispobj *args = current_control_stack_pointer;
424 current_control_stack_pointer += 3;
429 return call_into_lisp(function, args, 3);