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"
29 os_vm_address_t arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
31 /* Classic CMUCL comment:
33 Finding the bad address on the mips is easy. */
34 return (os_vm_address_t) siginfo->si_addr;
38 emulate_branch(os_context_t *context, unsigned long inst)
40 long opcode = inst >> 26;
41 long r1 = (inst >> 21) & 0x1f;
42 long r2 = (inst >> 16) & 0x1f;
43 long bdisp = (inst&(1<<15)) ? inst | (-1 << 16) : inst&0xffff;
44 long jdisp = (inst&(1<<25)) ? inst | (-1 << 26) : inst&0xffff;
48 case 0x1: /* bltz, bgez, bltzal, bgezal */
49 switch((inst >> 16) & 0x1f) {
51 if(*os_context_register_addr(context, r1) < 0)
55 if(*os_context_register_addr(context, r1) >= 0)
58 case 0x10: /* bltzal */
59 if(*os_context_register_addr(context, r1) < 0)
61 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
63 case 0x11: /* bgezal */
64 if(*os_context_register_addr(context, r1) >= 0)
66 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
71 if(*os_context_register_addr(context, r1)
72 == *os_context_register_addr(context, r2))
76 if(*os_context_register_addr(context, r1)
77 != *os_context_register_addr(context, r2))
81 if(*os_context_register_addr(context, r1)
82 /* FIXME: One has to assume that the CMUCL gods of old have
83 got the sign issues right... but it might be worth
85 <= *os_context_register_addr(context, r2))
89 if(*os_context_register_addr(context, r1)
90 >= *os_context_register_addr(context, r2))
98 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
101 return (*os_context_pc_addr(context) + disp * 4);
104 void arch_skip_instruction(os_context_t *context)
106 /* Skip the offending instruction */
107 if (os_context_bd_cause(context)) {
108 /* Currently, we never get here, because Linux' support for
109 bd_cause seems not terribly solid (c.f os_context_bd_cause
110 in mips-linux-os.c). If a port to Irix comes along, this
111 code will be executed, because presumably Irix' support is
112 better (it can hardly be worse). We lose() to remind the
113 porter to review this code. -- CSR, 2002-09-06 */
114 lose("bd_cause branch taken; review code for new OS?\n");
115 *os_context_pc_addr(context) =
116 emulate_branch(context,
117 *(unsigned long *) *os_context_pc_addr(context));
120 *os_context_pc_addr(context) += 4;
122 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
125 unsigned char *arch_internal_error_arguments(os_context_t *context)
127 if (os_context_bd_cause(context))
128 return (unsigned char *)(*os_context_pc_addr(context) + 8);
130 return (unsigned char *)(*os_context_pc_addr(context) + 4);
133 boolean arch_pseudo_atomic_atomic(os_context_t *context)
135 return *os_context_register_addr(context, reg_ALLOC) & 1;
138 #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
140 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
142 *os_context_register_addr(context, reg_NL4) |= 1<<31;
145 unsigned long arch_install_breakpoint(void *pc)
147 unsigned long *ptr = (unsigned long *)pc;
148 unsigned long result = *ptr;
149 *ptr = (trap_Breakpoint << 16) | 0xd;
151 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned long));
156 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
158 *(unsigned long *)pc = orig_inst;
160 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
163 static unsigned long *skipped_break_addr, displaced_after_inst;
164 static sigset_t orig_sigmask;
166 void arch_do_displaced_inst(os_context_t *context,
167 unsigned int orig_inst)
169 unsigned long *pc = (unsigned long *)*os_context_pc_addr(context);
170 unsigned long *break_pc, *next_pc;
171 unsigned long next_inst;
174 orig_sigmask = *os_context_sigmask_addr(context);
175 sigaddset_blockable(os_context_sigmask_addr(context));
177 /* Figure out where the breakpoint is, and what happens next. */
178 if (os_context_bd_cause(context)) {
184 next_inst = orig_inst;
187 /* Put the original instruction back. */
188 *break_pc = orig_inst;
189 os_flush_icache((os_vm_address_t)break_pc, sizeof(unsigned long));
190 skipped_break_addr = break_pc;
192 /* Figure out where it goes. */
193 opcode = next_inst >> 26;
194 if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000)) {
196 next_pc = emulate_branch(context, next_inst);
201 displaced_after_inst = *next_pc;
202 *next_pc = (trap_AfterBreakpoint << 16) | 0xd;
203 os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned long));
206 static void sigtrap_handler(int signal, siginfo_t *info, void *void_context)
208 os_context_t *context = arch_os_get_context(&void_context);
211 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
212 /* use debugger breakpoints anywhere in here. */
213 mask = os_context_sigmask_addr(context);
215 code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
218 case trap_PendingInterrupt:
219 arch_skip_instruction(context);
220 interrupt_handle_pending(context);
224 fake_foreign_function_call(context);
225 lose("%%primitive halt called; the party is over.\n");
229 interrupt_internal_error(signal, info, context, code==trap_Cerror);
232 case trap_Breakpoint:
233 handle_breakpoint(signal, info, context);
236 case trap_FunEndBreakpoint:
237 *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
240 case trap_AfterBreakpoint:
241 *skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
242 os_flush_icache((os_vm_address_t)skipped_break_addr,
243 sizeof(unsigned long));
244 skipped_break_addr = NULL;
245 *(unsigned long *)(*os_context_pc_addr(context)) = displaced_after_inst;
246 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
247 *os_context_sigmask_addr(context) = orig_sigmask;
252 *os_context_register_addr(context, reg_NL4) &= 0x7fffffff;
253 arch_skip_instruction(context);
254 interrupt_handle_pending(context);
258 interrupt_handle_now(signal, info, context);
263 /* FIXME: We must have one of these somewhere. Also, export
264 N-FIXNUM-TAG-BITS from Lispland and use it rather than 2 here. */
265 #define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
267 void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
269 unsigned long bad_inst;
270 unsigned int op, rs, rt, rd, funct, dest;
273 os_context_t *context = arch_os_get_context(&void_context);
275 if (os_context_bd_cause(context))
276 bad_inst = *(unsigned long *)(*os_context_pc_addr(context) + 4);
278 bad_inst = *(unsigned long *)(*os_context_pc_addr(context));
280 op = (bad_inst >> 26) & 0x3f;
281 rs = (bad_inst >> 21) & 0x1f;
282 rt = (bad_inst >> 16) & 0x1f;
283 rd = (bad_inst >> 11) & 0x1f;
284 funct = bad_inst & 0x3f;
285 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
288 case 0x0: /* SPECIAL */
291 /* FIXME: Hopefully, this whole section can just go away,
292 with the rewrite of pseudo-atomic and the deletion of
294 /* Check to see if this is really a pa_interrupted hit */
295 if (rs == reg_ALLOC && rt == reg_NL4) {
296 *os_context_register_addr(context, reg_ALLOC)
297 += (*os_context_register_addr(context, reg_NL4)
298 - PSEUDO_ATOMIC_INTERRUPTED_BIAS);
299 arch_skip_instruction(context);
300 interrupt_handle_pending(context);
303 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
304 + FIXNUM_VALUE(*os_context_register_addr(context, rt));
309 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
310 - FIXNUM_VALUE(*os_context_register_addr(context, rt));
321 result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
331 dynamic_space_free_pointer =
332 (lispobj *) *os_context_register_addr(context,reg_ALLOC);
334 *os_context_register_addr(context,dest) = alloc_number(result);
336 *os_context_register_addr(context, reg_ALLOC) =
337 (unsigned long) dynamic_space_free_pointer;
339 arch_skip_instruction(context);
343 interrupt_handle_now(signal, info, context);
346 void arch_install_interrupt_handlers()
348 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
349 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
352 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
354 lispobj funcall0(lispobj function)
356 lispobj *args = current_control_stack_pointer;
358 return call_into_lisp(function, args, 0);
361 lispobj funcall1(lispobj function, lispobj arg0)
363 lispobj *args = current_control_stack_pointer;
365 current_control_stack_pointer += 1;
368 return call_into_lisp(function, args, 1);
371 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
373 lispobj *args = current_control_stack_pointer;
375 current_control_stack_pointer += 2;
379 return call_into_lisp(function, args, 2);
382 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
384 lispobj *args = current_control_stack_pointer;
386 current_control_stack_pointer += 3;
391 return call_into_lisp(function, args, 3);