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;
184 sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
186 printf("sigtrap_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
187 SC_REG(scp,reg_ALLOC));
190 bad_inst = *(unsigned long *)(*os_context_pc_addr(context) & ~3);
191 if (bad_inst & 0xfc001fe0)
192 interrupt_handle_now(signal, siginfo, context);
194 int im5 = bad_inst & 0x1f;
198 fake_foreign_function_call(context);
199 lose("%%primitive halt called; the party is over.\n");
201 case trap_PendingInterrupt:
202 arch_skip_instruction(context);
203 interrupt_handle_pending(context);
208 interrupt_internal_error(signal, siginfo, context, im5==trap_Cerror);
211 case trap_Breakpoint:
212 /*sigsetmask(scp->sc_mask); */
213 handle_breakpoint(signal, siginfo, context);
216 case trap_FunEndBreakpoint:
217 /*sigsetmask(scp->sc_mask); */
221 handle_fun_end_breakpoint(signal, siginfo, context);
222 *os_context_pc_addr(context) = pc;
223 *os_context_npc_addr(context) = pc + 4;
227 case trap_SingleStepBreakpoint:
230 restore_breakpoint(context);
235 interrupt_handle_now(signal, siginfo, context);
241 static void sigfpe_handler(int signal, siginfo_t *siginfo, void *void_context)
243 os_context_t *context = arch_os_get_context(&void_context);
244 unsigned long badinst;
245 int opcode, r1, r2, t;
249 printf("sigfpe_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
250 SC_REG(scp,reg_ALLOC));
253 switch (siginfo->si_code) {
254 case FPE_INTOVF: /*I_OVFLO: */
255 badinst = *(unsigned long *)(*os_context_pc_addr(context) & ~3);
256 opcode = badinst >> 26;
260 r1 = (badinst >> 16) & 0x1f;
261 op1 = fixnum_value(*os_context_register_addr(context, r1));
262 r2 = (badinst >> 21) & 0x1f;
263 op2 = fixnum_value(*os_context_register_addr(context, r2));
266 switch ((badinst >> 5) & 0x7f) {
268 /* Add and trap on overflow. */
273 /* Subtract and trap on overflow. */
278 goto not_interesting;
281 else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
282 /* Add or subtract immediate. */
283 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
284 r2 = (badinst >> 16) & 0x1f;
285 op2 = fixnum_value(*os_context_register_addr(context, r1));
286 t = (badinst >> 21) & 0x1f;
293 goto not_interesting;
295 /* ?? What happens here if we hit the end of dynamic space? */
296 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
297 *os_context_register_addr(context, t) = alloc_number(res);
298 *os_context_register_addr(context, reg_ALLOC)
299 = (unsigned long) dynamic_space_free_pointer;
300 arch_skip_instruction(context);
304 case 0: /* I_COND: ?? Maybe tagged add?? FIXME */
305 badinst = *(unsigned long *)(*os_context_pc_addr(context) & ~3);
306 if ((badinst&0xfffff800) == (0xb000e000|reg_ALLOC<<21|reg_ALLOC<<16)) {
307 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. */
308 /* That means that it is the end of a pseudo-atomic. So do the */
309 /* add stripping off the pseudo-atomic-interrupted bit, and then */
310 /* tell the machine-independent code to process the pseudo- */
312 int immed = (badinst>>1)&0x3ff;
315 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
316 arch_skip_instruction(context);
317 interrupt_handle_pending(context);
320 /* else drop-through. */
323 interrupt_handle_now(signal, siginfo, context);
327 /* Merrily cut'n'pasted from sigfpe_handler. On Linux, until
328 2.4.19-pa4 (hopefully), the overflow_trap wasn't implemented,
329 resulting in a SIGBUS instead. We adapt the sigfpe_handler here, in
330 the hope that it will do as a replacement until the new kernel sees
331 the light of day. Since the instructions that we need to fix up
332 tend not to be doing unaligned memory access, this should be a safe
333 workaround. -- CSR, 2002-08-17 */
334 static void sigbus_handler(int signal, siginfo_t *siginfo, void *void_context)
336 os_context_t *context = arch_os_get_context(&void_context);
337 unsigned long badinst;
338 int opcode, r1, r2, t;
341 badinst = *(unsigned long *)(*os_context_pc_addr(context) & ~3);
342 /* First, test for the pseudo-atomic instruction */
343 if ((badinst & 0xfffff800) == (0xb000e000 |
346 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped.
347 That means that it is the end of a pseudo-atomic. So do
348 the add stripping off the pseudo-atomic-interrupted bit,
349 and then tell the machine-independent code to process the
351 int immed = (badinst>>1) & 0x3ff;
354 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
355 arch_skip_instruction(context);
356 interrupt_handle_pending(context);
359 opcode = badinst >> 26;
362 r1 = (badinst >> 16) & 0x1f;
363 op1 = fixnum_value(*os_context_register_addr(context, r1));
364 r2 = (badinst >> 21) & 0x1f;
365 op2 = fixnum_value(*os_context_register_addr(context, r2));
368 switch ((badinst >> 5) & 0x7f) {
370 /* Add and trap on overflow. */
375 /* Subtract and trap on overflow. */
380 goto not_interesting;
382 } else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
383 /* Add or subtract immediate. */
384 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
385 r2 = (badinst >> 16) & 0x1f;
386 op2 = fixnum_value(*os_context_register_addr(context, r1));
387 t = (badinst >> 21) & 0x1f;
394 goto not_interesting;
396 /* ?? What happens here if we hit the end of dynamic space? */
397 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
398 *os_context_register_addr(context, t) = alloc_number(res);
399 *os_context_register_addr(context, reg_ALLOC)
400 = (unsigned long) dynamic_space_free_pointer;
401 arch_skip_instruction(context);
406 interrupt_handle_now(signal, siginfo, context);
411 void arch_install_interrupt_handlers(void)
413 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
414 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
415 /* FIXME: beyond 2.4.19-pa4 this shouldn't be necessary. */
416 undoably_install_low_level_interrupt_handler(SIGBUS,sigbus_handler);
420 lispobj funcall0(lispobj function)
422 lispobj *args = current_control_stack_pointer;
424 return call_into_lisp(function, args, 0);
427 lispobj funcall1(lispobj function, lispobj arg0)
429 lispobj *args = current_control_stack_pointer;
431 current_control_stack_pointer += 1;
434 return call_into_lisp(function, args, 1);
437 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
439 lispobj *args = current_control_stack_pointer;
441 current_control_stack_pointer += 2;
445 return call_into_lisp(function, args, 2);
448 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
450 lispobj *args = current_control_stack_pointer;
452 current_control_stack_pointer += 3;
457 return call_into_lisp(function, args, 3);