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 if (os_context_bd_cause(context))
57 return *(unsigned int *)(os_context_pc(context) + 4);
59 return *(unsigned int *)(os_context_pc(context));
62 /* This function is somewhat misnamed, it actually just jumps to the
63 correct target address without attempting to execute the delay slot.
64 For other instructions it just increments the returned PC value. */
66 emulate_branch(os_context_t *context, unsigned int inst)
68 unsigned int opcode = inst >> 26;
69 unsigned int r1 = (inst >> 21) & 0x1f;
70 unsigned int r2 = (inst >> 16) & 0x1f;
71 unsigned int r3 = (inst >> 11) & 0x1f;
72 unsigned int disp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
73 unsigned int jtgt = (os_context_pc(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2;
74 unsigned int tgt = os_context_pc(context);
77 case 0x0: /* jr, jalr */
80 tgt = os_context_register(context, r1);
83 tgt = os_context_register(context, r1);
84 *os_context_register_addr(context, r3)
85 = os_context_pc(context) + 4;
92 case 0x1: /* bltz, bgez, bltzal, bgezal */
93 switch((inst >> 16) & 0x1f) {
95 if(os_context_register(context, r1) < 0)
99 if(os_context_register(context, r1) >= 0)
102 case 0x10: /* bltzal */
103 if(os_context_register(context, r1) < 0)
105 *os_context_register_addr(context, 31)
106 = os_context_pc(context) + 4;
108 case 0x11: /* bgezal */
109 if(os_context_register(context, r1) >= 0)
111 *os_context_register_addr(context, 31)
112 = os_context_pc(context) + 4;
114 default: /* conditional branches/traps for > MIPS I, ignore for now. */
119 if(os_context_register(context, r1)
120 == os_context_register(context, r2))
124 if(os_context_register(context, r1)
125 != os_context_register(context, r2))
129 if(os_context_register(context, r1)
130 <= os_context_register(context, r2))
134 if(os_context_register(context, r1)
135 > os_context_register(context, r2))
143 *os_context_register_addr(context, 31)
144 = os_context_pc(context) + 4;
154 arch_skip_instruction(os_context_t *context)
156 /* Skip the offending instruction. Don't use os_context_insn here,
157 since in case of a branch we want the branch insn, not the delay
159 *os_context_pc_addr(context)
160 = emulate_branch(context,
161 *(unsigned int *)(os_context_pc(context)));
165 arch_internal_error_arguments(os_context_t *context)
167 if (os_context_bd_cause(context))
168 return (unsigned char *)(os_context_pc(context) + 8);
170 return (unsigned char *)(os_context_pc(context) + 4);
174 arch_pseudo_atomic_atomic(os_context_t *context)
176 return os_context_register(context, reg_ALLOC) & 1;
180 arch_set_pseudo_atomic_interrupted(os_context_t *context)
182 *os_context_register_addr(context, reg_NL4) |= -1LL<<31;
186 arch_install_breakpoint(void *pc)
188 unsigned int *ptr = (unsigned int *)pc;
189 unsigned long result;
191 /* Don't install over a branch/jump. */
192 switch (*ptr >> 26) {
193 case 0x0: /* immediate jumps */
194 switch (*ptr & 0x3f) {
200 /* branches and register jumps */
211 result = (unsigned long) *ptr;
212 *ptr = (trap_Breakpoint << 16) | 0xd;
213 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
219 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
221 unsigned int *ptr = (unsigned int *)pc;
223 *ptr = (unsigned int) orig_inst;
224 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
227 static unsigned int *skipped_break_addr, displaced_after_inst;
228 static sigset_t orig_sigmask;
231 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
233 unsigned int *pc = (unsigned int *)os_context_pc(context);
234 unsigned int *break_pc, *next_pc;
235 unsigned int next_inst;
237 orig_sigmask = *os_context_sigmask_addr(context);
238 sigaddset_blockable(os_context_sigmask_addr(context));
240 /* Figure out where the breakpoint is, and what happens next. */
241 if (os_context_bd_cause(context)) {
246 next_inst = orig_inst;
249 /* Put the original instruction back. */
250 arch_remove_breakpoint(break_pc, orig_inst);
251 skipped_break_addr = break_pc;
253 /* Figure out where it goes. */
254 next_pc = (unsigned int *)emulate_branch(context, next_inst);
256 displaced_after_inst = arch_install_breakpoint(next_pc);
260 sigill_handler(int signal, siginfo_t *info, void *void_context)
262 os_context_t *context = arch_os_get_context(&void_context);
264 fake_foreign_function_call(context);
265 monitor_or_something();
269 sigtrap_handler(int signal, siginfo_t *info, void *void_context)
271 os_context_t *context = arch_os_get_context(&void_context);
272 unsigned int code = (os_context_insn(context) >> 16) & 0x1f;
276 fake_foreign_function_call(context);
277 lose("%%primitive halt called; the party is over.\n");
279 case trap_PendingInterrupt:
280 arch_skip_instruction(context);
281 interrupt_handle_pending(context);
286 interrupt_internal_error(signal, info, context, code == trap_Cerror);
289 case trap_Breakpoint:
290 handle_breakpoint(signal, info, context);
293 case trap_FunEndBreakpoint:
294 *os_context_pc_addr(context)
295 = (os_context_register_t)(unsigned int)
296 handle_fun_end_breakpoint(signal, info, context);
299 case trap_AfterBreakpoint:
300 arch_remove_breakpoint(os_context_pc_addr(context), displaced_after_inst);
301 displaced_after_inst = arch_install_breakpoint(skipped_break_addr);
302 *os_context_sigmask_addr(context) = orig_sigmask;
306 /* Clear the pseudo-atomic flag */
307 *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
308 arch_skip_instruction(context);
309 interrupt_handle_pending(context);
313 interrupt_handle_now(signal, info, context);
318 #define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
321 sigfpe_handler(int signal, siginfo_t *info, void *void_context)
323 os_context_t *context = arch_os_get_context(&void_context);
324 unsigned int bad_inst = os_context_insn(context);
325 unsigned int op, rs, rt, rd, funct, dest = 32;
329 op = (bad_inst >> 26) & 0x3f;
330 rs = (bad_inst >> 21) & 0x1f;
331 rt = (bad_inst >> 16) & 0x1f;
332 rd = (bad_inst >> 11) & 0x1f;
333 funct = bad_inst & 0x3f;
334 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
337 case 0x0: /* SPECIAL */
340 result = FIXNUM_VALUE(os_context_register(context, rs))
341 + FIXNUM_VALUE(os_context_register(context, rt));
346 result = FIXNUM_VALUE(os_context_register(context, rs))
347 - FIXNUM_VALUE(os_context_register(context, rt));
352 interrupt_handle_now(signal, info, context);
358 result = FIXNUM_VALUE(os_context_register(context,rs))
359 + (immed >> N_FIXNUM_TAG_BITS);
364 interrupt_handle_now(signal, info, context);
368 dynamic_space_free_pointer =
369 (lispobj *)(unsigned int)*os_context_register_addr(context,reg_ALLOC);
371 *os_context_register_addr(context,dest) = alloc_number(result);
373 *os_context_register_addr(context, reg_ALLOC) =
374 (unsigned int) dynamic_space_free_pointer;
376 arch_skip_instruction(context);
380 arch_install_interrupt_handlers()
382 undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler);
383 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
384 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
387 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
390 funcall0(lispobj function)
392 lispobj *args = current_control_stack_pointer;
394 return call_into_lisp(function, args, 0);
398 funcall1(lispobj function, lispobj arg0)
400 lispobj *args = current_control_stack_pointer;
402 current_control_stack_pointer += 1;
405 return call_into_lisp(function, args, 1);
409 funcall2(lispobj function, lispobj arg0, lispobj arg1)
411 lispobj *args = current_control_stack_pointer;
413 current_control_stack_pointer += 2;
417 return call_into_lisp(function, args, 2);
421 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
423 lispobj *args = current_control_stack_pointer;
425 current_control_stack_pointer += 3;
430 return call_into_lisp(function, args, 3);