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&0x7fff) << 2;
44 long jdisp = (inst&0x3ffffff) << 2;
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 <= *os_context_register_addr(context, r2))
86 if(*os_context_register_addr(context, r1)
87 > *os_context_register_addr(context, r2))
95 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
98 return (*os_context_pc_addr(context) + disp);
101 void arch_skip_instruction(os_context_t *context)
103 /* Skip the offending instruction */
104 if (os_context_bd_cause(context)) {
105 /* Currently, we never get here, because Linux' support for
106 bd_cause seems not terribly solid (c.f os_context_bd_cause
107 in mips-linux-os.c). If a port to Irix comes along, this
108 code will be executed, because presumably Irix' support is
109 better (it can hardly be worse). We lose() to remind the
110 porter to review this code. -- CSR, 2002-09-06 */
111 lose("bd_cause branch taken; review code for new OS?\n");
112 *os_context_pc_addr(context) =
113 emulate_branch(context,
114 *(unsigned long *) *os_context_pc_addr(context));
117 *os_context_pc_addr(context) += 4;
119 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
122 unsigned char *arch_internal_error_arguments(os_context_t *context)
124 if (os_context_bd_cause(context))
125 return (unsigned char *)(*os_context_pc_addr(context) + 8);
127 return (unsigned char *)(*os_context_pc_addr(context) + 4);
130 boolean arch_pseudo_atomic_atomic(os_context_t *context)
132 return *os_context_register_addr(context, reg_ALLOC) & 1;
135 #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
137 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
139 *os_context_register_addr(context, reg_NL4) |= 1<<31;
142 unsigned long arch_install_breakpoint(void *pc)
144 unsigned long *ptr = (unsigned long *)pc;
145 unsigned long result = *ptr;
146 *ptr = (trap_Breakpoint << 16) | 0xd;
148 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned long));
153 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
155 *(unsigned long *)pc = orig_inst;
157 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
160 static unsigned long *skipped_break_addr, displaced_after_inst;
161 static sigset_t orig_sigmask;
163 void arch_do_displaced_inst(os_context_t *context,
164 unsigned int orig_inst)
166 unsigned int *pc = (unsigned int *)*os_context_pc_addr(context);
167 unsigned int *break_pc, *next_pc;
168 unsigned int next_inst;
171 orig_sigmask = *os_context_sigmask_addr(context);
172 sigaddset_blockable(os_context_sigmask_addr(context));
174 /* Figure out where the breakpoint is, and what happens next. */
175 if (os_context_bd_cause(context)) {
181 next_inst = orig_inst;
184 /* Put the original instruction back. */
185 *break_pc = orig_inst;
186 os_flush_icache((os_vm_address_t)break_pc, sizeof(unsigned int));
187 skipped_break_addr = break_pc;
189 /* Figure out where it goes. */
190 opcode = next_inst >> 26;
191 if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000)) {
193 next_pc = emulate_branch(context, next_inst);
198 displaced_after_inst = *next_pc;
199 *next_pc = (trap_AfterBreakpoint << 16) | 0xd;
200 os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned int));
203 static void sigtrap_handler(int signal, siginfo_t *info, void *void_context)
205 os_context_t *context = arch_os_get_context(&void_context);
208 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
209 /* use debugger breakpoints anywhere in here. */
210 mask = os_context_sigmask_addr(context);
211 sigprocmask(SIG_SETMASK, mask, NULL);
212 code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
215 case trap_PendingInterrupt:
216 arch_skip_instruction(context);
217 interrupt_handle_pending(context);
221 fake_foreign_function_call(context);
222 lose("%%primitive halt called; the party is over.\n");
226 interrupt_internal_error(signal, info, context, code==trap_Cerror);
229 case trap_Breakpoint:
230 handle_breakpoint(signal, info, context);
233 case trap_FunEndBreakpoint:
234 *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
237 case trap_AfterBreakpoint:
238 *skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
239 os_flush_icache((os_vm_address_t)skipped_break_addr,
240 sizeof(unsigned long));
241 skipped_break_addr = NULL;
242 *(unsigned long *)(*os_context_pc_addr(context)) = displaced_after_inst;
243 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned int));
244 *os_context_sigmask_addr(context) = orig_sigmask;
249 *os_context_register_addr(context, reg_NL4) &= 0x7fffffff;
250 arch_skip_instruction(context);
251 interrupt_handle_pending(context);
255 interrupt_handle_now(signal, info, context);
260 /* FIXME: We must have one of these somewhere. Also, export
261 N-FIXNUM-TAG-BITS from Lispland and use it rather than 2 here. */
262 #define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
264 void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
266 unsigned long bad_inst;
267 unsigned int op, rs, rt, rd, funct, dest;
270 os_context_t *context = arch_os_get_context(&void_context);
272 if (os_context_bd_cause(context))
273 bad_inst = *(unsigned long *)(*os_context_pc_addr(context) + 4);
275 bad_inst = *(unsigned long *)(*os_context_pc_addr(context));
277 op = (bad_inst >> 26) & 0x3f;
278 rs = (bad_inst >> 21) & 0x1f;
279 rt = (bad_inst >> 16) & 0x1f;
280 rd = (bad_inst >> 11) & 0x1f;
281 funct = bad_inst & 0x3f;
282 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
285 case 0x0: /* SPECIAL */
288 /* FIXME: Hopefully, this whole section can just go away,
289 with the rewrite of pseudo-atomic and the deletion of
291 /* Check to see if this is really a pa_interrupted hit */
292 if (rs == reg_ALLOC && rt == reg_NL4) {
293 *os_context_register_addr(context, reg_ALLOC)
294 += (*os_context_register_addr(context, reg_NL4)
295 - PSEUDO_ATOMIC_INTERRUPTED_BIAS);
296 arch_skip_instruction(context);
297 interrupt_handle_pending(context);
300 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
301 + FIXNUM_VALUE(*os_context_register_addr(context, rt));
306 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
307 - FIXNUM_VALUE(*os_context_register_addr(context, rt));
318 result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
328 dynamic_space_free_pointer =
329 (lispobj *) *os_context_register_addr(context,reg_ALLOC);
331 *os_context_register_addr(context,dest) = alloc_number(result);
333 *os_context_register_addr(context, reg_ALLOC) =
334 (unsigned long) dynamic_space_free_pointer;
336 arch_skip_instruction(context);
340 interrupt_handle_now(signal, info, context);
343 void arch_install_interrupt_handlers()
345 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
346 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
349 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
351 lispobj funcall0(lispobj function)
353 lispobj *args = current_control_stack_pointer;
355 return call_into_lisp(function, args, 0);
358 lispobj funcall1(lispobj function, lispobj arg0)
360 lispobj *args = current_control_stack_pointer;
362 current_control_stack_pointer += 1;
365 return call_into_lisp(function, args, 1);
368 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
370 lispobj *args = current_control_stack_pointer;
372 current_control_stack_pointer += 2;
376 return call_into_lisp(function, args, 2);
379 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
381 lispobj *args = current_control_stack_pointer;
383 current_control_stack_pointer += 3;
388 return call_into_lisp(function, args, 3);