2 * This software is part of the SBCL system. See the README file for
5 * This software is derived from the CMU CL system, which was
6 * written at Carnegie Mellon University and released into the
7 * public domain. The software is in the public domain and is
8 * provided with absolutely no warranty. See the COPYING and CREDITS
9 * files for more information.
13 /* Copied from sparc-arch.c. Not all of these are necessary, probably */
23 #include "interrupt.h"
25 #include "breakpoint.h"
33 os_vm_address_t arch_get_bad_addr(int signal, siginfo_t *siginfo, os_context_t *context)
35 return siginfo->si_addr;
38 struct save_state *state;
41 state = (struct save_state *)(&(scp->sc_sl.sl_ss));
46 /* Check the instruction address first. */
47 addr = (os_vm_address_t)((unsigned long)scp->sc_pcoq_head & ~3);
48 if (addr < (os_vm_address_t)0x1000)
51 /* Otherwise, it must have been a data fault. */
52 return (os_vm_address_t)state->ss_cr21;
54 struct hp800_thread_state *state;
57 state = (struct hp800_thread_state *)(scp->sc_ap);
62 /* Check the instruction address first. */
63 addr = scp->sc_pcoqh & ~3;
67 /* Otherwise, it must have been a data fault. */
73 unsigned char *arch_internal_error_arguments(os_context_t *context)
75 return (unsigned char *)((*os_context_pc_addr(context) & ~3) + 4);
78 boolean arch_pseudo_atomic_atomic(os_context_t *context)
80 return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
83 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
85 *os_context_register_addr(context,reg_ALLOC) |= 1;
88 void arch_skip_instruction(os_context_t *context)
90 ((char *) *os_context_pc_addr(context)) = ((char *) *os_context_npc_addr(context));
91 ((char *) *os_context_npc_addr(context)) += 4;
94 unsigned long arch_install_breakpoint(void *pc)
96 unsigned long *ulpc = (unsigned long *)pc;
97 unsigned long orig_inst = *ulpc;
99 *ulpc = trap_Breakpoint;
100 os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
104 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
106 unsigned long *ulpc = (unsigned long *)pc;
109 os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
112 void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
114 /* FIXME: Fill this in */
117 /* We change the next-pc to point to a breakpoint instruction, restore */
118 /* the original instruction, and exit. We would like to be able to */
119 /* sigreturn, but we can't, because this is hpux. */
120 unsigned long *pc = (unsigned long *)(SC_PC(scp) & ~3);
122 NextPc = SC_NPC(scp);
123 SC_NPC(scp) = (unsigned)SingleStepTraps | (SC_NPC(scp)&3);
127 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
129 /* We set the recovery counter to cover one instruction, put the */
130 /* original instruction back in, and then resume. We will then trap */
131 /* after executing that one instruction, at which time we can put */
132 /* the breakpoint back in. */
134 ((struct hp800_thread_state *)scp->sc_ap)->cr0 = 1;
136 *(unsigned long *)SC_PC(scp) = orig_inst;
144 static void restore_breakpoint(struct sigcontext *scp)
146 /* We just single-stepped over an instruction that we want to replace */
147 /* with a breakpoint. So we put the breakpoint back in, and tweek the */
148 /* state so that we will continue as if nothing happened. */
151 lose("SingleStepBreakpoint trap at strange time.");
153 if ((SC_PC(scp)&~3) == (unsigned long)SingleStepTraps) {
154 /* The next instruction was not nullified. */
156 if ((SC_NPC(scp)&~3) == (unsigned long)SingleStepTraps + 4) {
157 /* The instruction we just stepped over was not a branch, so */
158 /* we need to fix it up. If it was a branch, it will point to */
159 /* the correct place. */
160 SC_NPC(scp) = NextPc + 4;
164 /* The next instruction was nullified, so we want to skip it. */
165 SC_PC(scp) = NextPc + 4;
166 SC_NPC(scp) = NextPc + 8;
170 if (BreakpointAddr) {
171 *BreakpointAddr = trap_Breakpoint;
172 os_flush_icache((os_vm_address_t)BreakpointAddr,
173 sizeof(unsigned long));
174 BreakpointAddr = NULL;
179 static void sigtrap_handler(int signal, siginfo_t *siginfo, void *void_context)
181 os_context_t *context = arch_os_get_context(&void_context);
182 unsigned long bad_inst;
185 printf("sigtrap_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
186 SC_REG(scp,reg_ALLOC));
189 bad_inst = *(unsigned long *)(*os_context_pc_addr(context) & ~3);
190 if (bad_inst & 0xfc001fe0)
191 interrupt_handle_now(signal, siginfo, context);
193 int im5 = bad_inst & 0x1f;
197 fake_foreign_function_call(context);
198 lose("%%primitive halt called; the party is over.\n");
200 case trap_PendingInterrupt:
201 arch_skip_instruction(context);
202 interrupt_handle_pending(context);
207 interrupt_internal_error(signal, siginfo, context, im5==trap_Cerror);
210 case trap_Breakpoint:
211 /*sigsetmask(scp->sc_mask); */
212 handle_breakpoint(signal, siginfo, context);
215 case trap_FunEndBreakpoint:
216 /*sigsetmask(scp->sc_mask); */
220 handle_fun_end_breakpoint(signal, siginfo, context);
221 *os_context_pc_addr(context) = pc;
222 *os_context_npc_addr(context) = pc + 4;
226 case trap_SingleStepBreakpoint:
229 restore_breakpoint(context);
234 interrupt_handle_now(signal, siginfo, context);
240 static void sigfpe_handler(int signal, siginfo_t *siginfo, void *void_context)
242 os_context_t *context = arch_os_get_context(&void_context);
243 unsigned long badinst;
244 int opcode, r1, r2, t;
248 printf("sigfpe_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
249 SC_REG(scp,reg_ALLOC));
252 switch (siginfo->si_code) {
253 case FPE_INTOVF: /*I_OVFLO: */
254 badinst = *(unsigned long *)(*os_context_pc_addr(context) & ~3);
255 opcode = badinst >> 26;
259 r1 = (badinst >> 16) & 0x1f;
260 op1 = fixnum_value(*os_context_register_addr(context, r1));
261 r2 = (badinst >> 21) & 0x1f;
262 op2 = fixnum_value(*os_context_register_addr(context, r2));
265 switch ((badinst >> 5) & 0x7f) {
267 /* Add and trap on overflow. */
272 /* Subtract and trap on overflow. */
277 goto not_interesting;
280 else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
281 /* Add or subtract immediate. */
282 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
283 r2 = (badinst >> 16) & 0x1f;
284 op2 = fixnum_value(*os_context_register_addr(context, r1));
285 t = (badinst >> 21) & 0x1f;
292 goto not_interesting;
294 /* ?? What happens here if we hit the end of dynamic space? */
295 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
296 *os_context_register_addr(context, t) = alloc_number(res);
297 *os_context_register_addr(context, reg_ALLOC)
298 = (unsigned long) dynamic_space_free_pointer;
299 arch_skip_instruction(context);
303 case 0: /* I_COND: ?? Maybe tagged add?? FIXME */
304 badinst = *(unsigned long *)(*os_context_pc_addr(context) & ~3);
305 if ((badinst&0xfffff800) == (0xb000e000|reg_ALLOC<<21|reg_ALLOC<<16)) {
306 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. */
307 /* That means that it is the end of a pseudo-atomic. So do the */
308 /* add stripping off the pseudo-atomic-interrupted bit, and then */
309 /* tell the machine-independent code to process the pseudo- */
311 int immed = (badinst>>1)&0x3ff;
314 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
315 arch_skip_instruction(context);
316 interrupt_handle_pending(context);
319 /* else drop-through. */
322 interrupt_handle_now(signal, siginfo, context);
326 /* Merrily cut'n'pasted from sigfpe_handler. On Linux, until
327 2.4.19-pa4 (hopefully), the overflow_trap wasn't implemented,
328 resulting in a SIGBUS instead. We adapt the sigfpe_handler here, in
329 the hope that it will do as a replacement until the new kernel sees
330 the light of day. Since the instructions that we need to fix up
331 tend not to be doing unaligned memory access, this should be a safe
332 workaround. -- CSR, 2002-08-17 */
333 static void sigbus_handler(int signal, siginfo_t *siginfo, void *void_context)
335 os_context_t *context = arch_os_get_context(&void_context);
336 unsigned long badinst;
337 int opcode, r1, r2, t;
340 badinst = *(unsigned long *)(*os_context_pc_addr(context) & ~3);
341 /* First, test for the pseudo-atomic instruction */
342 if ((badinst & 0xfffff800) == (0xb000e000 |
345 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped.
346 That means that it is the end of a pseudo-atomic. So do
347 the add stripping off the pseudo-atomic-interrupted bit,
348 and then tell the machine-independent code to process the
350 int immed = (badinst>>1) & 0x3ff;
353 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
354 arch_skip_instruction(context);
355 interrupt_handle_pending(context);
358 opcode = badinst >> 26;
361 r1 = (badinst >> 16) & 0x1f;
362 op1 = fixnum_value(*os_context_register_addr(context, r1));
363 r2 = (badinst >> 21) & 0x1f;
364 op2 = fixnum_value(*os_context_register_addr(context, r2));
367 switch ((badinst >> 5) & 0x7f) {
369 /* Add and trap on overflow. */
374 /* Subtract and trap on overflow. */
379 goto not_interesting;
381 } else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
382 /* Add or subtract immediate. */
383 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
384 r2 = (badinst >> 16) & 0x1f;
385 op2 = fixnum_value(*os_context_register_addr(context, r1));
386 t = (badinst >> 21) & 0x1f;
393 goto not_interesting;
395 /* ?? What happens here if we hit the end of dynamic space? */
396 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
397 *os_context_register_addr(context, t) = alloc_number(res);
398 *os_context_register_addr(context, reg_ALLOC)
399 = (unsigned long) dynamic_space_free_pointer;
400 arch_skip_instruction(context);
405 interrupt_handle_now(signal, siginfo, context);
410 void arch_install_interrupt_handlers(void)
412 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
413 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
414 /* FIXME: beyond 2.4.19-pa4 this shouldn't be necessary. */
415 undoably_install_low_level_interrupt_handler(SIGBUS,sigbus_handler);
419 lispobj funcall0(lispobj function)
421 lispobj *args = current_control_stack_pointer;
423 return call_into_lisp(function, args, 0);
426 lispobj funcall1(lispobj function, lispobj arg0)
428 lispobj *args = current_control_stack_pointer;
430 current_control_stack_pointer += 1;
433 return call_into_lisp(function, args, 1);
436 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
438 lispobj *args = current_control_stack_pointer;
440 current_control_stack_pointer += 2;
444 return call_into_lisp(function, args, 2);
447 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
449 lispobj *args = current_control_stack_pointer;
451 current_control_stack_pointer += 3;
456 return call_into_lisp(function, args, 3);