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"
35 arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
37 /* Classic CMUCL comment:
39 Finding the bad address on the mips is easy. */
40 return (os_vm_address_t)siginfo->si_addr;
43 static inline unsigned int
44 os_context_register(os_context_t *context, int offset)
46 return (unsigned int)(*os_context_register_addr(context, offset));
49 static inline unsigned int
50 os_context_pc(os_context_t *context)
52 return (unsigned int)(*os_context_pc_addr(context));
55 static inline unsigned int
56 os_context_insn(os_context_t *context)
58 if (os_context_bd_cause(context))
59 return *(unsigned int *)(os_context_pc(context) + INSN_LEN);
61 return *(unsigned int *)(os_context_pc(context));
65 arch_insn_with_bdelay_p(unsigned int insn)
69 switch (insn & 0x3f) {
76 /* branches and immediate jumps */
78 switch ((insn >> 16) & 0x1f) {
100 switch ((insn >> 21) & 0x1f) {
101 /* CP0/CP1/CP2 branches */
106 /* branch likely (MIPS II) */
116 /* This function is somewhat misnamed, it actually just jumps to the
117 correct target address without attempting to execute the delay slot.
118 For other instructions it just increments the returned PC value. */
120 emulate_branch(os_context_t *context, unsigned int inst)
122 unsigned int opcode = inst >> 26;
123 unsigned int r1 = (inst >> 21) & 0x1f;
124 unsigned int r2 = (inst >> 16) & 0x1f;
125 unsigned int r3 = (inst >> 11) & 0x1f;
126 unsigned int disp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2;
127 unsigned int jtgt = (os_context_pc(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2;
128 unsigned int tgt = os_context_pc(context);
131 case 0x0: /* jr, jalr */
132 switch(inst & 0x3f) {
134 tgt = os_context_register(context, r1);
136 case 0x09: /* jalr */
137 tgt = os_context_register(context, r1);
138 *os_context_register_addr(context, r3)
139 = os_context_pc(context) + INSN_LEN;
146 case 0x1: /* bltz, bgez, bltzal, bgezal */
147 switch((inst >> 16) & 0x1f) {
148 case 0x00: /* bltz */
149 if(os_context_register(context, r1) < 0)
152 case 0x01: /* bgez */
153 if(os_context_register(context, r1) >= 0)
156 case 0x10: /* bltzal */
157 if(os_context_register(context, r1) < 0)
159 *os_context_register_addr(context, 31)
160 = os_context_pc(context) + INSN_LEN;
162 case 0x11: /* bgezal */
163 if(os_context_register(context, r1) >= 0)
165 *os_context_register_addr(context, 31)
166 = os_context_pc(context) + INSN_LEN;
168 default: /* conditional branches/traps for > MIPS I, ignore for now. */
173 if(os_context_register(context, r1)
174 == os_context_register(context, r2))
178 if(os_context_register(context, r1)
179 != os_context_register(context, r2))
183 if(os_context_register(context, r1)
184 <= os_context_register(context, r2))
188 if(os_context_register(context, r1)
189 > os_context_register(context, r2))
197 *os_context_register_addr(context, 31)
198 = os_context_pc(context) + INSN_LEN;
208 arch_skip_instruction(os_context_t *context)
210 /* Skip the offending instruction. Don't use os_context_insn here,
211 since in case of a branch we want the branch insn, not the delay
213 *os_context_pc_addr(context)
214 = emulate_branch(context,
215 *(unsigned int *)(os_context_pc(context)));
219 arch_internal_error_arguments(os_context_t *context)
221 if (os_context_bd_cause(context))
222 return (unsigned char *)(os_context_pc(context) + (INSN_LEN * 2));
224 return (unsigned char *)(os_context_pc(context) + INSN_LEN);
228 arch_pseudo_atomic_atomic(os_context_t *context)
230 return os_context_register(context, reg_ALLOC) & 1;
234 arch_set_pseudo_atomic_interrupted(os_context_t *context)
236 *os_context_register_addr(context, reg_NL4) |= -1LL<<31;
240 arch_install_breakpoint(void *pc)
242 unsigned int *ptr = (unsigned int *)pc;
243 unsigned int insn = *ptr;
244 unsigned long result;
246 /* Don't install over a branch/jump with delay slot. */
247 if (arch_insn_with_bdelay_p(insn))
250 result = (unsigned long)insn;
251 *ptr = (trap_Breakpoint << 6) | 0xd;
252 os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
258 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
260 unsigned int *ptr = (unsigned int *)pc;
262 *ptr = (unsigned int) orig_inst;
263 os_flush_icache((os_vm_address_t)ptr, INSN_LEN);
266 static unsigned int *skipped_break_addr, displaced_after_inst;
267 static sigset_t orig_sigmask;
270 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
272 unsigned int *pc = (unsigned int *)os_context_pc(context);
273 unsigned int *break_pc, *next_pc;
274 unsigned int next_inst;
276 orig_sigmask = *os_context_sigmask_addr(context);
277 sigaddset_blockable(os_context_sigmask_addr(context));
279 /* Figure out where the breakpoint is, and what happens next. */
280 if (os_context_bd_cause(context)) {
285 next_inst = orig_inst;
288 /* Put the original instruction back. */
289 arch_remove_breakpoint(break_pc, orig_inst);
290 skipped_break_addr = break_pc;
292 /* Figure out where it goes. */
293 next_pc = (unsigned int *)emulate_branch(context, next_inst);
295 displaced_after_inst = arch_install_breakpoint(next_pc);
299 sigtrap_handler(int signal, siginfo_t *info, void *void_context)
301 os_context_t *context = arch_os_get_context(&void_context);
302 unsigned int code = (os_context_insn(context) >> 6) & 0xfffff;
306 fake_foreign_function_call(context);
307 lose("%%primitive halt called; the party is over.\n");
309 case trap_PendingInterrupt:
310 arch_skip_instruction(context);
311 interrupt_handle_pending(context);
316 interrupt_internal_error(signal, info, context, code == trap_Cerror);
319 case trap_Breakpoint:
320 handle_breakpoint(signal, info, context);
323 case trap_FunEndBreakpoint:
324 *os_context_pc_addr(context)
325 = (os_context_register_t)(unsigned int)
326 handle_fun_end_breakpoint(signal, info, context);
329 case trap_AfterBreakpoint:
330 arch_remove_breakpoint(os_context_pc_addr(context), displaced_after_inst);
331 displaced_after_inst = arch_install_breakpoint(skipped_break_addr);
332 *os_context_sigmask_addr(context) = orig_sigmask;
336 /* Clear the pseudo-atomic flag */
337 *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31);
338 arch_skip_instruction(context);
339 interrupt_handle_pending(context);
343 interrupt_handle_now(signal, info, context);
348 #define FIXNUM_VALUE(lispobj) (((int)lispobj) >> N_FIXNUM_TAG_BITS)
351 sigfpe_handler(int signal, siginfo_t *info, void *void_context)
353 os_context_t *context = arch_os_get_context(&void_context);
354 unsigned int bad_inst = os_context_insn(context);
355 unsigned int op, rs, rt, rd, funct, dest = 32;
359 op = (bad_inst >> 26) & 0x3f;
360 rs = (bad_inst >> 21) & 0x1f;
361 rt = (bad_inst >> 16) & 0x1f;
362 rd = (bad_inst >> 11) & 0x1f;
363 funct = bad_inst & 0x3f;
364 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
367 case 0x0: /* SPECIAL */
370 result = FIXNUM_VALUE(os_context_register(context, rs))
371 + FIXNUM_VALUE(os_context_register(context, rt));
376 result = FIXNUM_VALUE(os_context_register(context, rs))
377 - FIXNUM_VALUE(os_context_register(context, rt));
382 interrupt_handle_now(signal, info, context);
388 result = FIXNUM_VALUE(os_context_register(context,rs))
389 + (immed >> N_FIXNUM_TAG_BITS);
394 interrupt_handle_now(signal, info, context);
398 dynamic_space_free_pointer =
399 (lispobj *)(unsigned int)*os_context_register_addr(context,reg_ALLOC);
401 *os_context_register_addr(context,dest) = alloc_number(result);
403 *os_context_register_addr(context, reg_ALLOC) =
404 (unsigned int) dynamic_space_free_pointer;
406 arch_skip_instruction(context);
410 arch_install_interrupt_handlers()
412 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
413 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
416 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
419 funcall0(lispobj function)
421 lispobj *args = current_control_stack_pointer;
423 return call_into_lisp(function, args, 0);
427 funcall1(lispobj function, lispobj arg0)
429 lispobj *args = current_control_stack_pointer;
431 current_control_stack_pointer += 1;
434 return call_into_lisp(function, args, 1);
438 funcall2(lispobj function, lispobj arg0, lispobj arg1)
440 lispobj *args = current_control_stack_pointer;
442 current_control_stack_pointer += 2;
446 return call_into_lisp(function, args, 2);
450 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
452 lispobj *args = current_control_stack_pointer;
454 current_control_stack_pointer += 3;
459 return call_into_lisp(function, args, 3);