5 This code was written as part of the CMU Common Lisp project at
6 Carnegie Mellon University, and has been placed in the public domain.
21 #include "interrupt.h"
23 #include "breakpoint.h"
31 os_vm_address_t arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
33 /* Classic CMUCL comment:
35 Finding the bad address on the mips is easy. */
36 return (os_vm_address_t) siginfo->si_addr;
40 emulate_branch(os_context_t *context, unsigned long inst)
42 long opcode = inst >> 26;
43 long r1 = (inst >> 21) & 0x1f;
44 long r2 = (inst >> 16) & 0x1f;
45 long bdisp = (inst&(1<<15)) ? inst | (-1 << 16) : inst&0xffff;
46 long jdisp = (inst&(1<<25)) ? inst | (-1 << 26) : inst&0xffff;
50 case 0x1: /* bltz, bgez, bltzal, bgezal */
51 switch((inst >> 16) & 0x1f) {
53 if(*os_context_register_addr(context, r1) < 0)
57 if(*os_context_register_addr(context, r1) >= 0)
60 case 0x10: /* bltzal */
61 if(*os_context_register_addr(context, r1) < 0)
63 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
65 case 0x11: /* bgezal */
66 if(*os_context_register_addr(context, r1) >= 0)
68 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
73 if(*os_context_register_addr(context, r1)
74 == *os_context_register_addr(context, r2))
78 if(*os_context_register_addr(context, r1)
79 != *os_context_register_addr(context, r2))
83 if(*os_context_register_addr(context, r1)
84 /* FIXME: One has to assume that the CMUCL gods of old have
85 got the sign issues right... but it might be worth
87 <= *os_context_register_addr(context, r2))
91 if(*os_context_register_addr(context, r1)
92 >= *os_context_register_addr(context, r2))
100 *os_context_register_addr(context, 31) = *os_context_pc_addr(context) + 4;
103 return (*os_context_pc_addr(context) + disp * 4);
106 void arch_skip_instruction(os_context_t *context)
108 /* Skip the offending instruction */
109 if (os_context_bd_cause(context)) {
110 /* Currently, we never get here, because Linux' support for
111 bd_cause seems not terribly solid (c.f os_context_bd_cause
112 in mips-linux-os.c). If a port to Irix comes along, this
113 code will be executed, because presumably Irix' support is
114 better (it can hardly be worse). We lose() to remind the
115 porter to review this code. -- CSR, 2002-09-06 */
116 lose("bd_cause branch taken; review code for new OS?\n");
117 *os_context_pc_addr(context) =
118 emulate_branch(context,
119 *(unsigned long *) *os_context_pc_addr(context));
122 *os_context_pc_addr(context) += 4;
124 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
127 unsigned char *arch_internal_error_arguments(os_context_t *context)
129 if (os_context_bd_cause(context))
130 return (unsigned char *)(*os_context_pc_addr(context) + 8);
132 return (unsigned char *)(*os_context_pc_addr(context) + 4);
135 boolean arch_pseudo_atomic_atomic(os_context_t *context)
137 return *os_context_register_addr(context, reg_ALLOC) & 1;
140 #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
142 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
144 *os_context_register_addr(context, reg_NL4) |= 1<<31;
147 unsigned long arch_install_breakpoint(void *pc)
149 unsigned long *ptr = (unsigned long *)pc;
150 unsigned long result = *ptr;
151 *ptr = (trap_Breakpoint << 16) | 0xd;
153 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned long));
158 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
160 *(unsigned long *)pc = orig_inst;
162 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
165 static unsigned long *skipped_break_addr, displaced_after_inst;
166 static sigset_t orig_sigmask;
168 void arch_do_displaced_inst(os_context_t *context,
169 unsigned int orig_inst)
171 unsigned long *pc = (unsigned long *)*os_context_pc_addr(context);
172 unsigned long *break_pc, *next_pc;
173 unsigned long next_inst;
176 orig_sigmask = *os_context_sigmask_addr(context);
177 sigaddset_blockable(os_context_sigmask_addr(context));
179 /* Figure out where the breakpoint is, and what happens next. */
180 if (os_context_bd_cause(context)) {
186 next_inst = orig_inst;
189 /* Put the original instruction back. */
190 *break_pc = orig_inst;
191 os_flush_icache((os_vm_address_t)break_pc, sizeof(unsigned long));
192 skipped_break_addr = break_pc;
194 /* Figure out where it goes. */
195 opcode = next_inst >> 26;
196 if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000)) {
198 next_pc = emulate_branch(context, next_inst);
203 displaced_after_inst = *next_pc;
204 *next_pc = (trap_AfterBreakpoint << 16) | 0xd;
205 os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned long));
208 static void sigtrap_handler(int signal, siginfo_t *info, void *void_context)
210 os_context_t *context = arch_os_get_context(&void_context);
213 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
214 /* use debugger breakpoints anywhere in here. */
215 mask = os_context_sigmask_addr(context);
217 code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
220 case trap_PendingInterrupt:
221 arch_skip_instruction(context);
222 interrupt_handle_pending(context);
226 fake_foreign_function_call(context);
227 lose("%%primitive halt called; the party is over.\n");
231 interrupt_internal_error(signal, info, context, code==trap_Cerror);
234 case trap_Breakpoint:
235 handle_breakpoint(signal, info, context);
238 case trap_FunEndBreakpoint:
239 *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
242 case trap_AfterBreakpoint:
243 *skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
244 os_flush_icache((os_vm_address_t)skipped_break_addr,
245 sizeof(unsigned long));
246 skipped_break_addr = NULL;
247 *(unsigned long *)(*os_context_pc_addr(context)) = displaced_after_inst;
248 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
249 *os_context_sigmask_addr(context) = orig_sigmask;
254 *os_context_register_addr(context, reg_NL4) &= 0x7fffffff;
255 arch_skip_instruction(context);
256 interrupt_handle_pending(context);
260 interrupt_handle_now(signal, info, context);
265 /* FIXME: We must have one of these somewhere. Also, export
266 N-FIXNUM-TAG-BITS from Lispland and use it rather than 2 here. */
267 #define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
269 void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
271 unsigned long bad_inst;
272 unsigned int op, rs, rt, rd, funct, dest;
275 os_context_t *context = arch_os_get_context(&void_context);
277 if (os_context_bd_cause(context))
278 bad_inst = *(unsigned long *)(*os_context_pc_addr(context) + 4);
280 bad_inst = *(unsigned long *)(*os_context_pc_addr(context));
282 op = (bad_inst >> 26) & 0x3f;
283 rs = (bad_inst >> 21) & 0x1f;
284 rt = (bad_inst >> 16) & 0x1f;
285 rd = (bad_inst >> 11) & 0x1f;
286 funct = bad_inst & 0x3f;
287 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
290 case 0x0: /* SPECIAL */
293 /* FIXME: Hopefully, this whole section can just go away,
294 with the rewrite of pseudo-atomic and the deletion of
296 /* Check to see if this is really a pa_interrupted hit */
297 if (rs == reg_ALLOC && rt == reg_NL4) {
298 *os_context_register_addr(context, reg_ALLOC)
299 += (*os_context_register_addr(context, reg_NL4)
300 - PSEUDO_ATOMIC_INTERRUPTED_BIAS);
301 arch_skip_instruction(context);
302 interrupt_handle_pending(context);
305 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
306 + FIXNUM_VALUE(*os_context_register_addr(context, rt));
311 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
312 - FIXNUM_VALUE(*os_context_register_addr(context, rt));
323 result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
333 dynamic_space_free_pointer =
334 (lispobj *) *os_context_register_addr(context,reg_ALLOC);
336 *os_context_register_addr(context,dest) = alloc_number(result);
338 *os_context_register_addr(context, reg_ALLOC) =
339 (unsigned long) dynamic_space_free_pointer;
341 arch_skip_instruction(context);
345 interrupt_handle_now(signal, info, context);
348 void arch_install_interrupt_handlers()
350 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
351 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
354 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
356 lispobj funcall0(lispobj function)
358 lispobj *args = current_control_stack_pointer;
360 return call_into_lisp(function, args, 0);
363 lispobj funcall1(lispobj function, lispobj arg0)
365 lispobj *args = current_control_stack_pointer;
367 current_control_stack_pointer += 1;
370 return call_into_lisp(function, args, 1);
373 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
375 lispobj *args = current_control_stack_pointer;
377 current_control_stack_pointer += 2;
381 return call_into_lisp(function, args, 2);
384 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
386 lispobj *args = current_control_stack_pointer;
388 current_control_stack_pointer += 3;
393 return call_into_lisp(function, args, 3);