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 r3 = (inst >> 11) & 0x1f;
48 unsigned int disp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
49 unsigned int jtgt = (*os_context_pc_addr(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2;
50 unsigned int tgt = *os_context_pc_addr(context);
53 case 0x0: /* jr, jalr */
56 tgt = *os_context_register_addr(context, r1);
59 tgt = *os_context_register_addr(context, r1);
60 *os_context_register_addr(context, r3)
61 = *os_context_pc_addr(context) + 4;
65 case 0x1: /* bltz, bgez, bltzal, bgezal */
66 switch((inst >> 16) & 0x1f) {
68 if(*os_context_register_addr(context, r1) < 0)
72 if(*os_context_register_addr(context, r1) >= 0)
75 case 0x10: /* bltzal */
76 if(*os_context_register_addr(context, r1) < 0)
78 *os_context_register_addr(context, 31)
79 = *os_context_pc_addr(context) + 4;
81 case 0x11: /* bgezal */
82 if(*os_context_register_addr(context, r1) >= 0)
84 *os_context_register_addr(context, 31)
85 = *os_context_pc_addr(context) + 4;
90 if(*os_context_register_addr(context, r1)
91 == *os_context_register_addr(context, r2))
95 if(*os_context_register_addr(context, r1)
96 != *os_context_register_addr(context, r2))
100 if(*os_context_register_addr(context, r1)
101 <= *os_context_register_addr(context, r2))
105 if(*os_context_register_addr(context, r1)
106 > *os_context_register_addr(context, r2))
114 *os_context_register_addr(context, 31)
115 = *os_context_pc_addr(context) + 4;
122 arch_skip_instruction(os_context_t *context)
124 /* Skip the offending instruction */
125 if (os_context_bd_cause(context)) {
126 /* Currently, we never get here, because Linux' support for
127 bd_cause seems not terribly solid (c.f os_context_bd_cause
128 in mips-linux-os.c). If a port to Irix comes along, this
129 code will be executed, because presumably Irix' support is
130 better (it can hardly be worse). We lose() to remind the
131 porter to review this code. -- CSR, 2002-09-06 */
132 lose("bd_cause branch taken; review code for new OS?\n");
133 *os_context_pc_addr(context)
134 = emulate_branch(context, *os_context_pc_addr(context));
136 *os_context_pc_addr(context) += 4;
140 arch_internal_error_arguments(os_context_t *context)
142 if (os_context_bd_cause(context))
143 return (unsigned char *)(*os_context_pc_addr(context) + 8);
145 return (unsigned char *)(*os_context_pc_addr(context) + 4);
149 arch_pseudo_atomic_atomic(os_context_t *context)
151 return *os_context_register_addr(context, reg_ALLOC) & 1;
155 arch_set_pseudo_atomic_interrupted(os_context_t *context)
157 *os_context_register_addr(context, reg_NL4) |= -1LL<<31;
161 arch_install_breakpoint(void *pc)
163 unsigned int *ptr = (unsigned int *)pc;
164 unsigned long result = (unsigned long) *ptr;
166 *ptr = (trap_Breakpoint << 16) | 0xd;
167 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
173 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
175 unsigned int *ptr = (unsigned int *)pc;
177 *ptr = (unsigned int) orig_inst;
178 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int));
181 static unsigned int *skipped_break_addr, displaced_after_inst;
182 static sigset_t orig_sigmask;
185 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
187 unsigned int *pc = (unsigned int *)*os_context_pc_addr(context);
188 unsigned int *break_pc, *next_pc;
189 unsigned int next_inst;
192 orig_sigmask = *os_context_sigmask_addr(context);
193 sigaddset_blockable(os_context_sigmask_addr(context));
195 /* Figure out where the breakpoint is, and what happens next. */
196 if (os_context_bd_cause(context)) {
202 next_inst = orig_inst;
205 /* Put the original instruction back. */
206 arch_remove_breakpoint(break_pc, orig_inst);
207 skipped_break_addr = break_pc;
209 /* Figure out where it goes. */
210 opcode = next_inst >> 26;
211 if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000))
212 next_pc = (unsigned int *)emulate_branch(context, next_inst);
216 displaced_after_inst = arch_install_breakpoint(next_pc);
220 sigill_handler(int signal, siginfo_t *info, void *void_context)
222 os_context_t *context = arch_os_get_context(&void_context);
224 fake_foreign_function_call(context);
225 monitor_or_something();
229 sigtrap_handler(int signal, siginfo_t *info, void *void_context)
231 os_context_t *context = arch_os_get_context(&void_context);
236 /* Don't disallow recursive breakpoint traps. Otherwise, we can't
237 use debugger breakpoints anywhere in here. */
238 mask = os_context_sigmask_addr(context);
239 sigprocmask(SIG_SETMASK, mask, NULL);
240 code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
244 fake_foreign_function_call(context);
245 lose("%%primitive halt called; the party is over.\n");
247 case trap_PendingInterrupt:
248 arch_skip_instruction(context);
250 sigaddset(&ss,SIGTRAP);
251 sigprocmask(SIG_UNBLOCK,&ss,0);
252 interrupt_handle_pending(context);
257 interrupt_internal_error(signal, info, context, code==trap_Cerror);
260 case trap_Breakpoint:
261 handle_breakpoint(signal, info, context);
264 case trap_FunEndBreakpoint:
265 *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
266 os_flush_icache((os_vm_address_t)*os_context_pc_addr(context), sizeof(unsigned int));
269 case trap_AfterBreakpoint:
270 arch_remove_breakpoint(os_context_pc_addr(context), displaced_after_inst);
271 displaced_after_inst = arch_install_breakpoint(skipped_break_addr);
272 *os_context_sigmask_addr(context) = orig_sigmask;
276 /* Clear the pseudo-atomic flag */
277 *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
278 arch_skip_instruction(context);
279 interrupt_handle_pending(context);
283 interrupt_handle_now(signal, info, context);
288 #define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
291 sigfpe_handler(int signal, siginfo_t *info, void *void_context)
293 unsigned int bad_inst;
294 unsigned int op, rs, rt, rd, funct, dest = 32;
297 os_context_t *context = arch_os_get_context(&void_context);
299 if (os_context_bd_cause(context))
300 bad_inst = *(unsigned int *)(*os_context_pc_addr(context) + 4);
302 bad_inst = *(unsigned int *)(*os_context_pc_addr(context));
304 op = (bad_inst >> 26) & 0x3f;
305 rs = (bad_inst >> 21) & 0x1f;
306 rt = (bad_inst >> 16) & 0x1f;
307 rd = (bad_inst >> 11) & 0x1f;
308 funct = bad_inst & 0x3f;
309 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
312 case 0x0: /* SPECIAL */
315 /* FIXME: Hopefully, this whole section can just go away,
316 with the rewrite of pseudo-atomic and the deletion of
318 /* Check to see if this is really a pa_interrupted hit */
319 if (rs == reg_ALLOC && rt == reg_NL4) {
320 *os_context_register_addr(context, reg_ALLOC)
321 += *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
322 arch_skip_instruction(context);
323 interrupt_handle_pending(context);
326 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
327 + FIXNUM_VALUE(*os_context_register_addr(context, rt));
332 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
333 - FIXNUM_VALUE(*os_context_register_addr(context, rt));
340 result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
346 dynamic_space_free_pointer =
347 (lispobj *) *os_context_register_addr(context,reg_ALLOC);
349 *os_context_register_addr(context,dest) = alloc_number(result);
351 *os_context_register_addr(context, reg_ALLOC) =
352 (unsigned int) dynamic_space_free_pointer;
354 arch_skip_instruction(context);
358 interrupt_handle_now(signal, info, context);
362 arch_install_interrupt_handlers()
364 undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler);
365 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
366 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
369 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
372 funcall0(lispobj function)
374 lispobj *args = current_control_stack_pointer;
376 return call_into_lisp(function, args, 0);
380 funcall1(lispobj function, lispobj arg0)
382 lispobj *args = current_control_stack_pointer;
384 current_control_stack_pointer += 1;
387 return call_into_lisp(function, args, 1);
391 funcall2(lispobj function, lispobj arg0, lispobj arg1)
393 lispobj *args = current_control_stack_pointer;
395 current_control_stack_pointer += 2;
399 return call_into_lisp(function, args, 2);
403 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
405 lispobj *args = current_control_stack_pointer;
407 current_control_stack_pointer += 3;
412 return call_into_lisp(function, args, 3);