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 *os_context_pc_addr(context) =
111 emulate_branch(context,
112 *(unsigned long *) *os_context_pc_addr(context));
114 *os_context_pc_addr(context) += 4;
116 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
119 unsigned char *arch_internal_error_arguments(os_context_t *context)
121 if (os_context_bd_cause(context))
122 return (unsigned char *)(*os_context_pc_addr(context) + 8);
124 return (unsigned char *)(*os_context_pc_addr(context) + 4);
127 boolean arch_pseudo_atomic_atomic(os_context_t *context)
129 return *os_context_register_addr(context, reg_ALLOC) & 1;
132 #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
134 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
136 *os_context_register_addr(context, reg_NL4) |= 1<<31;
139 unsigned long arch_install_breakpoint(void *pc)
141 unsigned long *ptr = (unsigned long *)pc;
142 unsigned long result = *ptr;
143 *ptr = (trap_Breakpoint << 16) | 0xd;
145 os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned long));
150 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
152 *(unsigned long *)pc = orig_inst;
154 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
157 static unsigned long *skipped_break_addr, displaced_after_inst;
158 static sigset_t orig_sigmask;
160 void arch_do_displaced_inst(os_context_t *context,
161 unsigned int orig_inst)
163 unsigned long *pc = (unsigned long *)*os_context_pc_addr(context);
164 unsigned long *break_pc, *next_pc;
165 unsigned long next_inst;
168 orig_sigmask = *os_context_sigmask_addr(context);
169 sigaddset_blockable(os_context_sigmask_addr(context));
171 /* Figure out where the breakpoint is, and what happens next. */
172 if (os_context_bd_cause(context)) {
178 next_inst = orig_inst;
181 /* Put the original instruction back. */
182 *break_pc = orig_inst;
183 os_flush_icache((os_vm_address_t)break_pc, sizeof(unsigned long));
184 skipped_break_addr = break_pc;
186 /* Figure out where it goes. */
187 opcode = next_inst >> 26;
188 if (opcode == 1 || ((opcode & 0x3c) == 0x4) || ((next_inst & 0xf00e0000) == 0x80000000)) {
190 next_pc = emulate_branch(context, next_inst);
195 displaced_after_inst = *next_pc;
196 *next_pc = (trap_AfterBreakpoint << 16) | 0xd;
197 os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned long));
200 static void sigtrap_handler(int signal, siginfo_t *info, void *void_context)
202 os_context_t *context = arch_os_get_context(&void_context);
205 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
206 /* use debugger breakpoints anywhere in here. */
207 mask = os_context_sigmask_addr(context);
209 code = ((*(int *) (*os_context_pc_addr(context))) >> 16) & 0x1f;
212 case trap_PendingInterrupt:
213 arch_skip_instruction(context);
214 interrupt_handle_pending(context);
218 fake_foreign_function_call(context);
219 lose("%%primitive halt called; the party is over.\n");
223 interrupt_internal_error(signal, info, context, code==trap_Cerror);
226 case trap_Breakpoint:
227 handle_breakpoint(signal, info, context);
230 case trap_FunEndBreakpoint:
231 *os_context_pc_addr(context) = (int)handle_fun_end_breakpoint(signal, info, context);
234 case trap_AfterBreakpoint:
235 *skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
236 os_flush_icache((os_vm_address_t)skipped_break_addr,
237 sizeof(unsigned long));
238 skipped_break_addr = NULL;
239 *(unsigned long *)(*os_context_pc_addr(context)) = displaced_after_inst;
240 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), sizeof(unsigned long));
241 *os_context_sigmask_addr(context) = orig_sigmask;
246 *os_context_register_addr(context, reg_NL4) &= 0x7fffffff;
247 arch_skip_instruction(context);
248 interrupt_handle_pending(context);
252 interrupt_handle_now(signal, info, context);
257 /* FIXME: We must have one of these somewhere. Also, export
258 N-FIXNUM-TAG-BITS from Lispland and use it rather than 2 here. */
259 #define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
261 void sigfpe_handler(int signal, siginfo_t *info, void *void_context)
263 unsigned long bad_inst;
264 unsigned int op, rs, rt, rd, funct, dest;
267 os_context_t *context = arch_os_get_context(&void_context);
269 if (os_context_bd_cause(context))
270 bad_inst = *(unsigned long *)(*os_context_pc_addr(context) + 4);
272 bad_inst = *(unsigned long *)(*os_context_pc_addr(context));
274 op = (bad_inst >> 26) & 0x3f;
275 rs = (bad_inst >> 21) & 0x1f;
276 rt = (bad_inst >> 16) & 0x1f;
277 rd = (bad_inst >> 11) & 0x1f;
278 funct = bad_inst & 0x3f;
279 immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
282 case 0x0: /* SPECIAL */
285 /* FIXME: Hopefully, this whole section can just go away,
286 with the rewrite of pseudo-atomic and the deletion of
288 /* Check to see if this is really a pa_interrupted hit */
289 if (rs == reg_ALLOC && rt == reg_NL4) {
290 *os_context_register_addr(context, reg_ALLOC)
291 += (*os_context_register_addr(context, reg_NL4)
292 - PSEUDO_ATOMIC_INTERRUPTED_BIAS);
293 arch_skip_instruction(context);
294 interrupt_handle_pending(context);
297 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
298 + FIXNUM_VALUE(*os_context_register_addr(context, rt));
303 result = FIXNUM_VALUE(*os_context_register_addr(context, rs))
304 - FIXNUM_VALUE(*os_context_register_addr(context, rt));
315 result = FIXNUM_VALUE(*os_context_register_addr(context,rs)) + (immed>>2);
325 dynamic_space_free_pointer =
326 (lispobj *) *os_context_register_addr(context,reg_ALLOC);
328 *os_context_register_addr(context,dest) = alloc_number(result);
330 *os_context_register_addr(context, reg_ALLOC) =
331 (unsigned long) dynamic_space_free_pointer;
333 arch_skip_instruction(context);
337 interrupt_handle_now(signal, info, context);
340 void arch_install_interrupt_handlers()
342 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
343 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
346 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
348 lispobj funcall0(lispobj function)
350 lispobj *args = current_control_stack_pointer;
352 return call_into_lisp(function, args, 0);
355 lispobj funcall1(lispobj function, lispobj arg0)
357 lispobj *args = current_control_stack_pointer;
359 current_control_stack_pointer += 1;
362 return call_into_lisp(function, args, 1);
365 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
367 lispobj *args = current_control_stack_pointer;
369 current_control_stack_pointer += 2;
373 return call_into_lisp(function, args, 2);
376 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
378 lispobj *args = current_control_stack_pointer;
380 current_control_stack_pointer += 3;
385 return call_into_lisp(function, args, 3);