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.
9 #include <machine/trap.h>
18 #include "internals.h"
19 #include "breakpoint.h"
28 arch_get_bad_addr(int signal, int code, struct sigcontext * scp)
31 struct save_state *state;
34 state = (struct save_state *) (&(scp->sc_sl.sl_ss));
39 /* Check the instruction address first. */
40 addr = (os_vm_address_t) ((unsigned long) scp->sc_pcoq_head & ~3);
41 if (addr < (os_vm_address_t) 0x1000)
44 /* Otherwise, it must have been a data fault. */
45 return (os_vm_address_t) state->ss_cr21;
47 struct hp800_thread_state *state;
50 state = (struct hp800_thread_state *) (scp->sc_ap);
55 /* Check the instruction address first. */
56 addr = scp->sc_pcoqh & ~3;
60 /* Otherwise, it must have been a data fault. */
66 arch_internal_error_arguments(struct sigcontext *scp)
69 return (unsigned char *) ((scp->sc_pcoq_head & ~0x3) + 4);
71 return (unsigned char *) ((scp->sc_pcoqh & ~0x3) + 4);
76 arch_pseudo_atomic_atomic(struct sigcontext *scp)
78 /* Pseudo-atomic-atomic is implemented by oring 0x4 into ALLOC. */
80 if (SC_REG(scp, reg_ALLOC) & 0x4)
87 arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
89 /* Pseudo-atomic-atomic is implemented by oring 0x1 into ALLOC. */
91 SC_REG(scp, reg_ALLOC) |= 1;
95 arch_skip_instruction(struct sigcontext *scp)
97 /* Skip the offending instruction */
99 scp->sc_pcoq_head = scp->sc_pcoq_tail;
100 scp->sc_pcoq_tail += 4;
102 scp->sc_pcoqh = scp->sc_pcoqt;
108 arch_install_breakpoint(void *pc)
110 unsigned long *ulpc = (unsigned long *) pc;
111 unsigned long orig_inst = *ulpc;
113 *ulpc = trap_Breakpoint;
114 os_flush_icache((os_vm_address_t) pc, sizeof(*ulpc));
119 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
121 unsigned long *ulpc = (unsigned long *) pc;
124 os_flush_icache((os_vm_address_t) pc, sizeof(*ulpc));
128 extern void SingleStepTraps();
129 static unsigned long *BreakpointAddr = NULL;
130 static unsigned long NextPc = NULL;
134 arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
137 /* We change the next-pc to point to a breakpoint instruction, restore */
138 /* the original instruction, and exit. We would like to be able to */
139 /* sigreturn, but we can't, because this is hpux. */
140 unsigned long *pc = (unsigned long *) (SC_PC(scp) & ~3);
142 NextPc = SC_NPC(scp);
143 SC_NPC(scp) = (unsigned) SingleStepTraps | (SC_NPC(scp) & 3);
147 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
149 /* We set the recovery counter to cover one instruction, put the */
150 /* original instruction back in, and then resume. We will then trap */
151 /* after executing that one instruction, at which time we can put */
152 /* the breakpoint back in. */
154 ((struct hp800_thread_state *) scp->sc_ap)->cr0 = 1;
156 *(unsigned long *) SC_PC(scp) = orig_inst;
164 restore_breakpoint(struct sigcontext *scp)
166 /* We just single-stepped over an instruction that we want to replace */
167 /* with a breakpoint. So we put the breakpoint back in, and tweek the */
168 /* state so that we will continue as if nothing happened. */
171 lose("SingleStepBreakpoint trap at strange time.");
173 if ((SC_PC(scp) & ~3) == (unsigned long) SingleStepTraps) {
174 /* The next instruction was not nullified. */
176 if ((SC_NPC(scp) & ~3) == (unsigned long) SingleStepTraps + 4) {
177 /* The instruction we just stepped over was not a branch, so */
178 /* we need to fix it up. If it was a branch, it will point to */
179 /* the correct place. */
180 SC_NPC(scp) = NextPc + 4;
183 /* The next instruction was nullified, so we want to skip it. */
184 SC_PC(scp) = NextPc + 4;
185 SC_NPC(scp) = NextPc + 8;
189 if (BreakpointAddr) {
190 *BreakpointAddr = trap_Breakpoint;
191 os_flush_icache((os_vm_address_t) BreakpointAddr,
193 sizeof(unsigned long));
194 BreakpointAddr = NULL;
200 sigtrap_handler(int signal, int code, struct sigcontext *scp)
202 unsigned long bad_inst;
204 sigsetmask(scp->sc_mask);
207 printf("sigtrap_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
208 SC_REG(scp, reg_ALLOC));
212 bad_inst = *(unsigned long *) (scp->sc_pcoq_head & ~3);
214 bad_inst = *(unsigned long *) (scp->sc_pcoqh & ~3);
217 if (bad_inst & 0xfc001fe0)
218 interrupt_handle_now(signal, code, scp);
220 int im5 = bad_inst & 0x1f;
224 fake_foreign_function_call(scp);
225 lose("%%primitive halt called; the party is over.\n");
227 case trap_PendingInterrupt:
228 arch_skip_instruction(scp);
229 interrupt_handle_pending(scp);
234 interrupt_internal_error(signal, code, scp, im5 == trap_Cerror);
237 case trap_Breakpoint:
238 sigsetmask(scp->sc_mask);
239 handle_breakpoint(signal, code, scp);
242 case trap_FunctionEndBreakpoint:
243 sigsetmask(scp->sc_mask);
248 handle_function_end_breakpoint(signal, code, scp);
250 scp->sc_pcoq_head = pc;
251 scp->sc_pcoq_tail = pc + 4;
254 scp->sc_pcoqt = pc + 4;
259 case trap_SingleStepBreakpoint:
260 restore_breakpoint(scp);
264 interrupt_handle_now(signal, code, scp);
271 sigfpe_handler(int signal, int code, struct sigcontext *scp)
273 unsigned long badinst;
274 int opcode, r1, r2, t;
278 printf("sigfpe_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
279 SC_REG(scp, reg_ALLOC));
284 badinst = *(unsigned long *) (SC_PC(scp) & ~3);
285 opcode = badinst >> 26;
289 r1 = (badinst >> 16) & 0x1f;
290 op1 = fixnum_value(SC_REG(scp, r1));
291 r2 = (badinst >> 21) & 0x1f;
292 op2 = fixnum_value(SC_REG(scp, r2));
295 switch ((badinst >> 5) & 0x7f) {
297 /* Add and trap on overflow. */
302 /* Subtract and trap on overflow. */
307 goto not_interesting;
309 } else if ((opcode & 0x37) == 0x25 && (badinst & (1 << 11))) {
310 /* Add or subtract immediate. */
311 op1 = ((badinst >> 3) & 0xff) | ((-badinst & 1) << 8);
312 r2 = (badinst >> 16) & 0x1f;
313 op2 = fixnum_value(SC_REG(scp, r1));
314 t = (badinst >> 21) & 0x1f;
320 goto not_interesting;
322 current_dynamic_space_free_pointer =
323 (lispobj *) SC_REG(scp, reg_ALLOC);
324 SC_REG(scp, t) = alloc_number(res);
325 SC_REG(scp, reg_ALLOC)
326 = (unsigned long) current_dynamic_space_free_pointer;
327 arch_skip_instruction(scp);
332 badinst = *(unsigned long *) (SC_PC(scp) & ~3);
333 if ((badinst & 0xfffff800) ==
334 (0xb000e000 | reg_ALLOC << 21 | reg_ALLOC << 16)) {
335 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. */
336 /* That means that it is the end of a pseudo-atomic. So do the */
337 /* add stripping off the pseudo-atomic-interrupted bit, and then */
338 /* tell the machine-independent code to process the pseudo- */
340 int immed = (badinst >> 1) & 0x3ff;
344 SC_REG(scp, reg_ALLOC) += (immed - 1);
345 arch_skip_instruction(scp);
346 interrupt_handle_pending(scp);
349 /* else drop-through. */
352 interrupt_handle_now(signal, code, scp);
357 arch_install_interrupt_handlers(void)
360 interrupt_install_low_level_handler(SIGILL, sigtrap_handler);
362 interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
363 interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
367 funcall0(lispobj function)
369 lispobj *args = current_control_stack_pointer;
371 return call_into_lisp(function, args, 0);
375 funcall1(lispobj function, lispobj arg0)
377 lispobj *args = current_control_stack_pointer;
379 current_control_stack_pointer += 1;
382 return call_into_lisp(function, args, 1);
386 funcall2(lispobj function, lispobj arg0, lispobj arg1)
388 lispobj *args = current_control_stack_pointer;
390 current_control_stack_pointer += 2;
394 return call_into_lisp(function, args, 2);
398 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
400 lispobj *args = current_control_stack_pointer;
402 current_control_stack_pointer += 3;
407 return call_into_lisp(function, args, 3);