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);
234 code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
238 fake_foreign_function_call(context);
239 lose("%%primitive halt called; the party is over.\n");
241 case trap_PendingInterrupt:
242 arch_skip_instruction(context);
243 interrupt_handle_pending(context);
248 interrupt_internal_error(signal, info, context, code==trap_Cerror);
251 case trap_Breakpoint:
252 handle_breakpoint(signal, info, context);
255 case trap_FunEndBreakpoint:
256 *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
257 os_flush_icache((os_vm_address_t)*os_context_pc_addr(context), sizeof(unsigned int));
260 case trap_AfterBreakpoint:
261 arch_remove_breakpoint(os_context_pc_addr(context), displaced_after_inst);
262 displaced_after_inst = arch_install_breakpoint(skipped_break_addr);
263 *os_context_sigmask_addr(context) = orig_sigmask;
267 /* Clear the pseudo-atomic flag */
268 *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
269 arch_skip_instruction(context);
270 interrupt_handle_pending(context);
274 interrupt_handle_now(signal, info, context);
279 #define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
282 sigfpe_handler(int signal, siginfo_t *info, void *void_context)
284 unsigned int bad_inst;
285 unsigned int op, rs, rt, rd, funct, dest = 32;
288 os_context_t *context = arch_os_get_context(&void_context);
290 if (os_context_bd_cause(context))
291 bad_inst = *(unsigned int *)(*os_context_pc_addr(context) + 4);
293 bad_inst = *(unsigned int *)(*os_context_pc_addr(context));
295 op = (bad_inst >> 26) & 0x3f;
296 rs = (bad_inst >> 21) & 0x1f;
297 rt = (bad_inst >> 16) & 0x1f;
298 rd = (bad_inst >> 11) & 0x1f;
299 funct = bad_inst & 0x3f;
300 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
303 case 0x0: /* SPECIAL */
306 /* FIXME: Hopefully, this whole section can just go away,
307 with the rewrite of pseudo-atomic and the deletion of
309 /* Check to see if this is really a pa_interrupted hit */
310 if (rs == reg_ALLOC && rt == reg_NL4) {
311 *os_context_register_addr(context, reg_ALLOC)
312 += *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
313 arch_skip_instruction(context);
314 interrupt_handle_pending(context);
317 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
318 + FIXNUM_VALUE(*os_context_register_addr(context, rt));
323 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
324 - FIXNUM_VALUE(*os_context_register_addr(context, rt));
331 result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
337 dynamic_space_free_pointer =
338 (lispobj *) *os_context_register_addr(context,reg_ALLOC);
340 *os_context_register_addr(context,dest) = alloc_number(result);
342 *os_context_register_addr(context, reg_ALLOC) =
343 (unsigned int) dynamic_space_free_pointer;
345 arch_skip_instruction(context);
349 interrupt_handle_now(signal, info, context);
353 arch_install_interrupt_handlers()
355 undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler);
356 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
357 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
360 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
363 funcall0(lispobj function)
365 lispobj *args = current_control_stack_pointer;
367 return call_into_lisp(function, args, 0);
371 funcall1(lispobj function, lispobj arg0)
373 lispobj *args = current_control_stack_pointer;
375 current_control_stack_pointer += 1;
378 return call_into_lisp(function, args, 1);
382 funcall2(lispobj function, lispobj arg0, lispobj arg1)
384 lispobj *args = current_control_stack_pointer;
386 current_control_stack_pointer += 2;
390 return call_into_lisp(function, args, 2);
394 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
396 lispobj *args = current_control_stack_pointer;
398 current_control_stack_pointer += 3;
403 return call_into_lisp(function, args, 3);