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"
32 os_vm_address_t arch_get_bad_addr(int signal, siginfo_t *siginfo, os_context_t *context)
34 return siginfo->si_addr;
37 struct save_state *state;
40 state = (struct save_state *)(&(scp->sc_sl.sl_ss));
45 /* Check the instruction address first. */
46 addr = (os_vm_address_t)((unsigned long)scp->sc_pcoq_head & ~3);
47 if (addr < (os_vm_address_t)0x1000)
50 /* Otherwise, it must have been a data fault. */
51 return (os_vm_address_t)state->ss_cr21;
53 struct hp800_thread_state *state;
56 state = (struct hp800_thread_state *)(scp->sc_ap);
61 /* Check the instruction address first. */
62 addr = scp->sc_pcoqh & ~3;
66 /* Otherwise, it must have been a data fault. */
72 unsigned char *arch_internal_error_arguments(os_context_t *context)
74 return (unsigned char *)((*os_context_pc_addr(context) & ~3) + 4);
77 boolean arch_pseudo_atomic_atomic(os_context_t *context)
79 return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
82 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
84 *os_context_register_addr(context,reg_ALLOC) |= 1;
88 void arch_clear_pseudo_atomic_interrupted(os_context_t *context)
90 *os_context_register_addr(context,reg_ALLOC) &= ~1;
93 void arch_skip_instruction(os_context_t *context)
95 ((char *) *os_context_pc_addr(context)) = ((char *) *os_context_npc_addr(context));
96 ((char *) *os_context_npc_addr(context)) += 4;
99 unsigned int arch_install_breakpoint(void *pc)
101 unsigned int *ulpc = (unsigned int *)pc;
102 unsigned int orig_inst = *ulpc;
104 *ulpc = trap_Breakpoint;
105 os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
109 void arch_remove_breakpoint(void *pc, unsigned int orig_inst)
111 unsigned int *ulpc = (unsigned int *)pc;
114 os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
117 void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
119 /* FIXME: Fill this in */
122 /* We change the next-pc to point to a breakpoint instruction, restore */
123 /* the original instruction, and exit. We would like to be able to */
124 /* sigreturn, but we can't, because this is hpux. */
125 unsigned int *pc = (unsigned int *)(SC_PC(scp) & ~3);
127 NextPc = SC_NPC(scp);
128 SC_NPC(scp) = (unsigned int)SingleStepTraps | (SC_NPC(scp)&3);
132 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned int));
134 /* We set the recovery counter to cover one instruction, put the */
135 /* original instruction back in, and then resume. We will then trap */
136 /* after executing that one instruction, at which time we can put */
137 /* the breakpoint back in. */
139 ((struct hp800_thread_state *)scp->sc_ap)->cr0 = 1;
141 *(unsigned int *)SC_PC(scp) = orig_inst;
149 static void restore_breakpoint(struct sigcontext *scp)
151 /* We just single-stepped over an instruction that we want to replace */
152 /* with a breakpoint. So we put the breakpoint back in, and tweek the */
153 /* state so that we will continue as if nothing happened. */
156 lose("SingleStepBreakpoint trap at strange time.\n");
158 if ((SC_PC(scp)&~3) == (unsigned int)SingleStepTraps) {
159 /* The next instruction was not nullified. */
161 if ((SC_NPC(scp)&~3) == (unsigned int)SingleStepTraps + 4) {
162 /* The instruction we just stepped over was not a branch, so */
163 /* we need to fix it up. If it was a branch, it will point to */
164 /* the correct place. */
165 SC_NPC(scp) = NextPc + 4;
169 /* The next instruction was nullified, so we want to skip it. */
170 SC_PC(scp) = NextPc + 4;
171 SC_NPC(scp) = NextPc + 8;
175 if (BreakpointAddr) {
176 *BreakpointAddr = trap_Breakpoint;
177 os_flush_icache((os_vm_address_t)BreakpointAddr,
178 sizeof(unsigned int));
179 BreakpointAddr = NULL;
184 static void sigtrap_handler(int signal, siginfo_t *siginfo, void *void_context)
186 os_context_t *context = arch_os_get_context(&void_context);
187 unsigned int bad_inst;
190 printf("sigtrap_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
191 SC_REG(scp,reg_ALLOC));
194 bad_inst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
195 if (bad_inst & 0xfc001fe0)
196 interrupt_handle_now(signal, siginfo, context);
198 int im5 = bad_inst & 0x1f;
202 fake_foreign_function_call(context);
203 lose("%%primitive halt called; the party is over.\n");
205 case trap_PendingInterrupt:
206 arch_skip_instruction(context);
207 interrupt_handle_pending(context);
212 interrupt_internal_error(signal, siginfo, context, im5==trap_Cerror);
215 case trap_Breakpoint:
216 /*sigsetmask(scp->sc_mask); */
217 handle_breakpoint(signal, siginfo, context);
220 case trap_FunEndBreakpoint:
221 /*sigsetmask(scp->sc_mask); */
225 handle_fun_end_breakpoint(signal, siginfo, context);
226 *os_context_pc_addr(context) = pc;
227 *os_context_npc_addr(context) = pc + 4;
231 case trap_SingleStepBreakpoint:
234 restore_breakpoint(context);
239 interrupt_handle_now(signal, siginfo, context);
245 static void sigfpe_handler(int signal, siginfo_t *siginfo, void *void_context)
247 os_context_t *context = arch_os_get_context(&void_context);
248 unsigned int badinst;
249 int opcode, r1, r2, t;
253 printf("sigfpe_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
254 SC_REG(scp,reg_ALLOC));
257 switch (siginfo->si_code) {
258 case FPE_INTOVF: /*I_OVFLO: */
259 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
260 opcode = badinst >> 26;
264 r1 = (badinst >> 16) & 0x1f;
265 op1 = fixnum_value(*os_context_register_addr(context, r1));
266 r2 = (badinst >> 21) & 0x1f;
267 op2 = fixnum_value(*os_context_register_addr(context, r2));
270 switch ((badinst >> 5) & 0x7f) {
272 /* Add and trap on overflow. */
277 /* Subtract and trap on overflow. */
282 goto not_interesting;
285 else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
286 /* Add or subtract immediate. */
287 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
288 r2 = (badinst >> 16) & 0x1f;
289 op2 = fixnum_value(*os_context_register_addr(context, r1));
290 t = (badinst >> 21) & 0x1f;
297 goto not_interesting;
299 /* ?? What happens here if we hit the end of dynamic space? */
300 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
301 *os_context_register_addr(context, t) = alloc_number(res);
302 *os_context_register_addr(context, reg_ALLOC)
303 = (unsigned long) dynamic_space_free_pointer;
304 arch_skip_instruction(context);
308 case 0: /* I_COND: ?? Maybe tagged add?? FIXME */
309 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
310 if ((badinst&0xfffff800) == (0xb000e000|reg_ALLOC<<21|reg_ALLOC<<16)) {
311 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. */
312 /* That means that it is the end of a pseudo-atomic. So do the */
313 /* add stripping off the pseudo-atomic-interrupted bit, and then */
314 /* tell the machine-independent code to process the pseudo- */
316 int immed = (badinst>>1)&0x3ff;
319 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
320 arch_skip_instruction(context);
321 interrupt_handle_pending(context);
324 /* else drop-through. */
327 interrupt_handle_now(signal, siginfo, context);
331 /* Merrily cut'n'pasted from sigfpe_handler. On Linux, until
332 2.4.19-pa4 (hopefully), the overflow_trap wasn't implemented,
333 resulting in a SIGBUS instead. We adapt the sigfpe_handler here, in
334 the hope that it will do as a replacement until the new kernel sees
335 the light of day. Since the instructions that we need to fix up
336 tend not to be doing unaligned memory access, this should be a safe
337 workaround. -- CSR, 2002-08-17 */
338 static void sigbus_handler(int signal, siginfo_t *siginfo, void *void_context)
340 os_context_t *context = arch_os_get_context(&void_context);
341 unsigned int badinst;
342 int opcode, r1, r2, t;
345 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
346 /* First, test for the pseudo-atomic instruction */
347 if ((badinst & 0xfffff800) == (0xb000e000 |
350 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped.
351 That means that it is the end of a pseudo-atomic. So do
352 the add stripping off the pseudo-atomic-interrupted bit,
353 and then tell the machine-independent code to process the
355 int immed = (badinst>>1) & 0x3ff;
358 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
359 arch_skip_instruction(context);
360 interrupt_handle_pending(context);
363 opcode = badinst >> 26;
366 r1 = (badinst >> 16) & 0x1f;
367 op1 = fixnum_value(*os_context_register_addr(context, r1));
368 r2 = (badinst >> 21) & 0x1f;
369 op2 = fixnum_value(*os_context_register_addr(context, r2));
372 switch ((badinst >> 5) & 0x7f) {
374 /* Add and trap on overflow. */
379 /* Subtract and trap on overflow. */
384 goto not_interesting;
386 } else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
387 /* Add or subtract immediate. */
388 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
389 r2 = (badinst >> 16) & 0x1f;
390 op2 = fixnum_value(*os_context_register_addr(context, r1));
391 t = (badinst >> 21) & 0x1f;
398 goto not_interesting;
400 /* ?? What happens here if we hit the end of dynamic space? */
401 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
402 *os_context_register_addr(context, t) = alloc_number(res);
403 *os_context_register_addr(context, reg_ALLOC)
404 = (unsigned long) dynamic_space_free_pointer;
405 arch_skip_instruction(context);
410 interrupt_handle_now(signal, siginfo, context);
415 void arch_install_interrupt_handlers(void)
417 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
418 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
419 /* FIXME: beyond 2.4.19-pa4 this shouldn't be necessary. */
420 undoably_install_low_level_interrupt_handler(SIGBUS,sigbus_handler);
424 lispobj funcall0(lispobj function)
426 lispobj *args = current_control_stack_pointer;
428 return call_into_lisp(function, args, 0);
431 lispobj funcall1(lispobj function, lispobj arg0)
433 lispobj *args = current_control_stack_pointer;
435 current_control_stack_pointer += 1;
438 return call_into_lisp(function, args, 1);
441 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
443 lispobj *args = current_control_stack_pointer;
445 current_control_stack_pointer += 2;
449 return call_into_lisp(function, args, 2);
452 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
454 lispobj *args = current_control_stack_pointer;
456 current_control_stack_pointer += 3;
461 return call_into_lisp(function, args, 3);