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.
22 #include "internals.h"
27 #include "interrupt.h"
29 #include "breakpoint.h"
38 arch_get_bad_addr(int sig, int code, struct sigcontext * scp)
40 /* Finding the bad address on the mips is easy. */
41 return (os_vm_address_t) scp->sc_badvaddr;
46 emulate_branch(struct sigcontext *scp, unsigned long inst)
48 long opcode = inst >> 26;
49 long r1 = (inst >> 21) & 0x1f;
50 long r2 = (inst >> 16) & 0x1f;
51 long bdisp = (inst & (1 << 15)) ? inst | (-1 << 16) : inst & 0xffff;
52 long jdisp = (inst & (1 << 25)) ? inst | (-1 << 26) : inst & 0xffff;
56 case 0x1: /* bltz, bgez, bltzal, bgezal */
57 switch ((inst >> 16) & 0x1f) {
59 if (scp->sc_regs[r1] < 0)
63 if (scp->sc_regs[r1] >= 0)
66 case 0x10: /* bltzal */
67 if (scp->sc_regs[r1] < 0)
69 scp->sc_regs[31] = scp->sc_pc + 4;
71 case 0x11: /* bgezal */
72 if (scp->sc_regs[r1] >= 0)
74 scp->sc_regs[31] = scp->sc_pc + 4;
79 if (scp->sc_regs[r1] == scp->sc_regs[r2])
83 if (scp->sc_regs[r1] != scp->sc_regs[r2])
87 if (scp->sc_regs[r1] <= scp->sc_regs[r2])
91 if (scp->sc_regs[r1] >= scp->sc_regs[r2])
99 scp->sc_regs[31] = scp->sc_pc + 4;
102 scp->sc_pc += disp * 4;
107 arch_skip_instruction(scp)
108 struct sigcontext *scp;
110 /* Skip the offending instruction */
111 if (scp->sc_cause & CAUSE_BD)
112 emulate_branch(scp, *(unsigned long *) scp->sc_pc);
118 arch_internal_error_arguments(struct sigcontext *scp)
120 if (scp->sc_cause & CAUSE_BD)
121 return (unsigned char *) (scp->sc_pc + 8);
123 return (unsigned char *) (scp->sc_pc + 4);
127 arch_pseudo_atomic_atomic(struct sigcontext *scp)
129 return (scp->sc_regs[reg_ALLOC] & 1);
132 #define PSEUDO_ATOMIC_INTERRUPTED_BIAS 0x7f000000
135 arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
137 scp->sc_regs[reg_NL4] += PSEUDO_ATOMIC_INTERRUPTED_BIAS;
141 arch_install_breakpoint(void *pc)
143 unsigned long *ptr = (unsigned long *) pc;
144 unsigned long result = *ptr;
146 *ptr = (trap_Breakpoint << 16) | 0xd;
148 os_flush_icache((os_vm_address_t) ptr, sizeof(unsigned long));
154 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
156 *(unsigned long *) pc = orig_inst;
158 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
161 static unsigned long *skipped_break_addr, displaced_after_inst;
162 static int orig_sigmask;
165 arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
167 unsigned long *pc = (unsigned long *) scp->sc_pc;
168 unsigned long *break_pc, *next_pc;
169 unsigned long next_inst;
171 struct sigcontext tmp;
173 orig_sigmask = scp->sc_mask;
174 scp->sc_mask = BLOCKABLE;
176 /* Figure out where the breakpoint is, and what happens next. */
177 if (scp->sc_cause & CAUSE_BD) {
182 next_inst = orig_inst;
185 /* Put the original instruction back. */
186 *break_pc = orig_inst;
187 os_flush_icache((os_vm_address_t) break_pc, sizeof(unsigned long));
189 skipped_break_addr = break_pc;
191 /* Figure out where it goes. */
192 opcode = next_inst >> 26;
193 if (opcode == 1 || ((opcode & 0x3c) == 0x4)
194 || ((next_inst & 0xf00e0000) == 0x80000000)) {
196 emulate_branch(&tmp, next_inst);
197 next_pc = (unsigned long *) tmp.sc_pc;
201 displaced_after_inst = *next_pc;
202 *next_pc = (trap_AfterBreakpoint << 16) | 0xd;
203 os_flush_icache((os_vm_address_t) next_pc, sizeof(unsigned long));
211 sigtrap_handler(int signal, int code, struct sigcontext *scp)
213 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
214 /* use debugger breakpoints anywhere in here. */
215 sigsetmask(scp->sc_mask);
218 case trap_PendingInterrupt:
219 arch_skip_instruction(scp);
220 interrupt_handle_pending(scp);
224 fake_foreign_function_call(scp);
225 lose("%%primitive halt called; the party is over.\n");
229 interrupt_internal_error(signal, code, scp, code == trap_Cerror);
232 case trap_Breakpoint:
233 handle_breakpoint(signal, code, scp);
236 case trap_FunctionEndBreakpoint:
237 scp->sc_pc = (int) handle_function_end_breakpoint(signal, code, scp);
240 case trap_AfterBreakpoint:
241 *skipped_break_addr = (trap_Breakpoint << 16) | 0xd;
242 os_flush_icache((os_vm_address_t) skipped_break_addr,
244 sizeof(unsigned long));
245 skipped_break_addr = NULL;
246 *(unsigned long *) scp->sc_pc = displaced_after_inst;
247 os_flush_icache((os_vm_address_t) scp->sc_pc, sizeof(unsigned long));
249 scp->sc_mask = orig_sigmask;
253 interrupt_handle_now(signal, code, scp);
259 sigfpe_handler(int signal, int code, struct sigcontext *scp)
261 unsigned long bad_inst;
262 unsigned int op, rs, rt, rd, funct, dest;
266 if (scp->sc_cause & CAUSE_BD)
267 bad_inst = *(unsigned long *) (scp->sc_pc + 4);
269 bad_inst = *(unsigned long *) (scp->sc_pc);
271 op = (bad_inst >> 26) & 0x3f;
272 rs = (bad_inst >> 21) & 0x1f;
273 rt = (bad_inst >> 16) & 0x1f;
274 rd = (bad_inst >> 11) & 0x1f;
275 funct = bad_inst & 0x3f;
276 immed = (((int) (bad_inst & 0xffff)) << 16) >> 16;
279 case 0x0: /* SPECIAL */
282 /* Check to see if this is really a pa_interrupted hit */
283 if (rs == reg_ALLOC && rt == reg_NL4) {
284 scp->sc_regs[reg_ALLOC] +=
285 (scp->sc_regs[reg_NL4] -
286 PSEUDO_ATOMIC_INTERRUPTED_BIAS);
287 arch_skip_instruction(scp);
288 interrupt_handle_pending(scp);
292 fixnum_value(scp->sc_regs[rs]) +
293 fixnum_value(scp->sc_regs[rt]);
299 fixnum_value(scp->sc_regs[rs]) -
300 fixnum_value(scp->sc_regs[rt]);
311 result = fixnum_value(scp->sc_regs[rs]) + (immed >> 2);
321 current_dynamic_space_free_pointer =
322 (lispobj *) scp->sc_regs[reg_ALLOC];
324 scp->sc_regs[dest] = alloc_number(result);
326 scp->sc_regs[reg_ALLOC] =
327 (unsigned long) current_dynamic_space_free_pointer;
329 arch_skip_instruction(scp);
332 interrupt_handle_now(signal, code, scp);
336 arch_install_interrupt_handlers(void)
338 interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
339 interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
342 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
345 funcall0(lispobj function)
347 lispobj *args = current_control_stack_pointer;
349 return call_into_lisp(function, args, 0);
353 funcall1(lispobj function, lispobj arg0)
355 lispobj *args = current_control_stack_pointer;
357 current_control_stack_pointer += 1;
360 return call_into_lisp(function, args, 1);
364 funcall2(lispobj function, lispobj arg0, lispobj arg1)
366 lispobj *args = current_control_stack_pointer;
368 current_control_stack_pointer += 2;
372 return call_into_lisp(function, args, 2);
376 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);
389 /* This is apparently called by emulate_branch, but isn't defined. So */
390 /* just do nothing and hope it works... */