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;
42 emulate_branch(os_context_t *context, unsigned int inst)
44 unsigned int opcode = inst >> 26;
45 unsigned int r1 = (inst >> 21) & 0x1f;
46 unsigned int r2 = (inst >> 16) & 0x1f;
47 unsigned int bdisp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
48 unsigned int jdisp = (inst&0x3ffffff) << 2;
49 unsigned int disp = 0;
52 case 0x1: /* bltz, bgez, bltzal, bgezal */
53 switch((inst >> 16) & 0x1f) {
55 if(*os_context_register_addr(context, r1) < 0)
59 if(*os_context_register_addr(context, r1) >= 0)
62 case 0x10: /* bltzal */
63 if(*os_context_register_addr(context, r1) < 0)
65 *os_context_register_addr(context, 31)
66 = *os_context_pc_addr(context) + 4;
68 case 0x11: /* bgezal */
69 if(*os_context_register_addr(context, r1) >= 0)
71 *os_context_register_addr(context, 31)
72 = *os_context_pc_addr(context) + 4;
77 if(*os_context_register_addr(context, r1)
78 == *os_context_register_addr(context, r2))
82 if(*os_context_register_addr(context, r1)
83 != *os_context_register_addr(context, r2))
87 if(*os_context_register_addr(context, r1)
88 <= *os_context_register_addr(context, r2))
92 if(*os_context_register_addr(context, r1)
93 > *os_context_register_addr(context, r2))
101 *os_context_register_addr(context, 31)
102 = *os_context_pc_addr(context) + 4;
105 return *os_context_pc_addr(context) + disp;
109 arch_skip_instruction(os_context_t *context)
111 /* Skip the offending instruction */
112 if (os_context_bd_cause(context)) {
113 /* Currently, we never get here, because Linux' support for
114 bd_cause seems not terribly solid (c.f os_context_bd_cause
115 in mips-linux-os.c). If a port to Irix comes along, this
116 code will be executed, because presumably Irix' support is
117 better (it can hardly be worse). We lose() to remind the
118 porter to review this code. -- CSR, 2002-09-06 */
119 lose("bd_cause branch taken; review code for new OS?\n");
120 *os_context_pc_addr(context)
121 = emulate_branch(context, *os_context_pc_addr(context));
123 *os_context_pc_addr(context) += 4;
125 os_flush_icache((os_vm_address_t)*os_context_pc_addr(context),
126 sizeof(unsigned int));
130 arch_internal_error_arguments(os_context_t *context)
132 if (os_context_bd_cause(context))
133 return (unsigned char *)(*os_context_pc_addr(context) + 8);
135 return (unsigned char *)(*os_context_pc_addr(context) + 4);
139 arch_pseudo_atomic_atomic(os_context_t *context)
141 return *os_context_register_addr(context, reg_ALLOC) & 1;
145 arch_set_pseudo_atomic_interrupted(os_context_t *context)
147 *os_context_register_addr(context, reg_NL4) |= -1LL<<31;
151 arch_install_breakpoint(void *pc)
153 unsigned int *ptr = (unsigned int *)pc;
154 unsigned long result = (unsigned long) *ptr;
156 *ptr = (trap_Breakpoint << 16) | 0xd;
157 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
163 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
165 unsigned int *ptr = (unsigned int *)pc;
167 *ptr = (unsigned int) orig_inst;
168 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
171 static unsigned int *skipped_break_addr, displaced_after_inst;
172 static sigset_t orig_sigmask;
175 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
177 unsigned int *pc = (unsigned int *)*os_context_pc_addr(context);
178 unsigned int *break_pc, *next_pc;
179 unsigned int next_inst;
182 orig_sigmask = *os_context_sigmask_addr(context);
183 sigaddset_blockable(os_context_sigmask_addr(context));
185 /* Figure out where the breakpoint is, and what happens next. */
186 if (os_context_bd_cause(context)) {
192 next_inst = orig_inst;
195 /* Put the original instruction back. */
196 arch_remove_breakpoint(break_pc, orig_inst);
197 skipped_break_addr = break_pc;
199 /* Figure out where it goes. */
200 opcode = next_inst >> 26;
201 if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000))
202 next_pc = (unsigned int *)emulate_branch(context, next_inst);
206 displaced_after_inst = arch_install_breakpoint(next_pc);
210 sigill_handler(int signal, siginfo_t *info, void *void_context)
212 os_context_t *context = arch_os_get_context(&void_context);
214 fake_foreign_function_call(context);
215 monitor_or_something();
219 sigtrap_handler(int signal, siginfo_t *info, void *void_context)
221 os_context_t *context = arch_os_get_context(&void_context);
226 /* Don't disallow recursive breakpoint traps. Otherwise, we can't
227 use debugger breakpoints anywhere in here. */
228 mask = os_context_sigmask_addr(context);
229 sigprocmask(SIG_SETMASK, mask, NULL);
230 code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
234 fake_foreign_function_call(context);
235 lose("%%primitive halt called; the party is over.\n");
237 case trap_PendingInterrupt:
238 arch_skip_instruction(context);
240 sigaddset(&ss,SIGTRAP);
241 sigprocmask(SIG_UNBLOCK,&ss,0);
242 interrupt_handle_pending(context);
247 interrupt_internal_error(signal, info, context, code==trap_Cerror);
250 case trap_Breakpoint:
251 handle_breakpoint(signal, info, context);
254 case trap_FunEndBreakpoint:
255 *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
256 os_flush_icache((os_vm_address_t)*os_context_pc_addr(context), sizeof(unsigned int));
259 case trap_AfterBreakpoint:
260 arch_remove_breakpoint(os_context_pc_addr(context), displaced_after_inst);
261 displaced_after_inst = arch_install_breakpoint(skipped_break_addr);
262 *os_context_sigmask_addr(context) = orig_sigmask;
266 /* Clear the pseudo-atomic flag */
267 *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
268 arch_skip_instruction(context);
269 interrupt_handle_pending(context);
273 interrupt_handle_now(signal, info, context);
278 #define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
281 sigfpe_handler(int signal, siginfo_t *info, void *void_context)
283 unsigned int bad_inst;
284 unsigned int op, rs, rt, rd, funct, dest = 32;
287 os_context_t *context = arch_os_get_context(&void_context);
289 if (os_context_bd_cause(context))
290 bad_inst = *(unsigned int *)(*os_context_pc_addr(context) + 4);
292 bad_inst = *(unsigned int *)(*os_context_pc_addr(context));
294 op = (bad_inst >> 26) & 0x3f;
295 rs = (bad_inst >> 21) & 0x1f;
296 rt = (bad_inst >> 16) & 0x1f;
297 rd = (bad_inst >> 11) & 0x1f;
298 funct = bad_inst & 0x3f;
299 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
302 case 0x0: /* SPECIAL */
305 /* FIXME: Hopefully, this whole section can just go away,
306 with the rewrite of pseudo-atomic and the deletion of
308 /* Check to see if this is really a pa_interrupted hit */
309 if (rs == reg_ALLOC && rt == reg_NL4) {
310 *os_context_register_addr(context, reg_ALLOC)
311 += *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
312 arch_skip_instruction(context);
313 interrupt_handle_pending(context);
316 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
317 + FIXNUM_VALUE(*os_context_register_addr(context, rt));
322 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
323 - FIXNUM_VALUE(*os_context_register_addr(context, rt));
330 result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
336 dynamic_space_free_pointer =
337 (lispobj *) *os_context_register_addr(context,reg_ALLOC);
339 *os_context_register_addr(context,dest) = alloc_number(result);
341 *os_context_register_addr(context, reg_ALLOC) =
342 (unsigned int) dynamic_space_free_pointer;
344 arch_skip_instruction(context);
348 interrupt_handle_now(signal, info, context);
352 arch_install_interrupt_handlers()
354 undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler);
355 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
356 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
359 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
362 funcall0(lispobj function)
364 lispobj *args = current_control_stack_pointer;
366 return call_into_lisp(function, args, 0);
370 funcall1(lispobj function, lispobj arg0)
372 lispobj *args = current_control_stack_pointer;
374 current_control_stack_pointer += 1;
377 return call_into_lisp(function, args, 1);
381 funcall2(lispobj function, lispobj arg0, lispobj arg1)
383 lispobj *args = current_control_stack_pointer;
385 current_control_stack_pointer += 2;
389 return call_into_lisp(function, args, 2);
393 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
395 lispobj *args = current_control_stack_pointer;
397 current_control_stack_pointer += 3;
402 return call_into_lisp(function, args, 3);