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 static inline unsigned int
33 os_context_pc(os_context_t *context)
35 return (unsigned int)(*os_context_pc_addr(context));
38 os_vm_address_t arch_get_bad_addr(int signal, siginfo_t *siginfo, os_context_t *context)
40 return (os_vm_address_t)siginfo->si_addr;
42 #ifdef LISP_FEATURE_HPUX
43 struct save_state *state;
46 state = (struct save_state *)(&(scp->sc_sl.sl_ss));
51 /* Check the instruction address first. */
52 addr = (os_vm_address_t)((unsigned long)scp->sc_pcoq_head & ~3);
53 if (addr < (os_vm_address_t)0x1000)
56 /* Otherwise, it must have been a data fault. */
57 return (os_vm_address_t)state->ss_cr21;
59 struct hp800_thread_state *state;
62 state = (struct hp800_thread_state *)(scp->sc_ap);
67 /* Check the instruction address first. */
68 addr = scp->sc_pcoqh & ~3;
72 /* Otherwise, it must have been a data fault. */
78 unsigned char *arch_internal_error_arguments(os_context_t *context)
80 return (unsigned char *)((*os_context_pc_addr(context) & ~3) + 4);
83 boolean arch_pseudo_atomic_atomic(os_context_t *context)
85 /* FIXME: this foreign_function_call_active test is dubious at
86 * best. If a foreign call is made in a pseudo atomic section
87 * (?) or more likely a pseudo atomic section is in a foreign
88 * call then an interrupt is executed immediately. Maybe it
89 * has to do with C code not maintaining pseudo atomic
90 * properly. MG - 2005-08-10
92 * The foreign_function_call_active used to live at each call-site
93 * to arch_pseudo_atomic_atomic, but this seems clearer.
96 // FIX-lav: use accessor macro instead
97 return (!foreign_function_call_active) &&
98 *(&((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64.ss_gr7) & 4;
101 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
104 *(&((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64.ss_gr7) |= 1;
105 /* on hpux do we need to watch out for the barbarian ? */
106 #ifdef LISP_FEATURE_HPUX
107 *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags)
112 /* FIXME: untested */
113 void arch_clear_pseudo_atomic_interrupted(os_context_t *context)
115 *(&((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64.ss_gr7) &= ~1;
116 #ifdef LISP_FEATURE_HPUX
117 *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags)
122 void arch_skip_instruction(os_context_t *context)
124 *((unsigned int *) os_context_pc_addr(context)) = *((unsigned int *) os_context_npc_addr(context));
125 *((unsigned int *) os_context_npc_addr(context)) += 4;
126 #ifdef LISP_FEATURE_HPUX
127 *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags)
132 unsigned int arch_install_breakpoint(void *pc)
134 unsigned int *ulpc = (unsigned int *)pc;
135 unsigned int orig_inst = *ulpc;
137 *ulpc = trap_Breakpoint;
138 os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
142 void arch_remove_breakpoint(void *pc, unsigned int orig_inst)
144 unsigned int *ulpc = (unsigned int *)pc;
147 os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
150 void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
152 fprintf(stderr, "arch_do_displaced_inst() WARNING: stub.\n");
153 /* FIXME: Fill this in */
155 #ifdef LISP_FEATURE_HPUX
156 /* We change the next-pc to point to a breakpoint instruction, restore */
157 /* the original instruction, and exit. We would like to be able to */
158 /* sigreturn, but we can't, because this is hpux. */
159 unsigned int *pc = (unsigned int *)(SC_PC(scp) & ~3);
161 NextPc = SC_NPC(scp);
162 SC_NPC(scp) = (unsigned int)SingleStepTraps | (SC_NPC(scp)&3);
166 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned int));
168 /* We set the recovery counter to cover one instruction, put the */
169 /* original instruction back in, and then resume. We will then trap */
170 /* after executing that one instruction, at which time we can put */
171 /* the breakpoint back in. */
173 ((struct hp800_thread_state *)scp->sc_ap)->cr0 = 1;
175 *(unsigned int *)SC_PC(scp) = orig_inst;
182 #ifdef LISP_FEATURE_HPUX
184 static void restore_breakpoint(struct sigcontext *scp)
186 /* We just single-stepped over an instruction that we want to replace */
187 /* with a breakpoint. So we put the breakpoint back in, and tweek the */
188 /* state so that we will continue as if nothing happened. */
191 lose("SingleStepBreakpoint trap at strange time.\n");
193 if ((SC_PC(scp)&~3) == (unsigned int)SingleStepTraps) {
194 /* The next instruction was not nullified. */
196 if ((SC_NPC(scp)&~3) == (unsigned int)SingleStepTraps + 4) {
197 /* The instruction we just stepped over was not a branch, so */
198 /* we need to fix it up. If it was a branch, it will point to */
199 /* the correct place. */
200 SC_NPC(scp) = NextPc + 4;
204 /* The next instruction was nullified, so we want to skip it. */
205 SC_PC(scp) = NextPc + 4;
206 SC_NPC(scp) = NextPc + 8;
210 if (BreakpointAddr) {
211 *BreakpointAddr = trap_Breakpoint;
212 os_flush_icache((os_vm_address_t)BreakpointAddr,
213 sizeof(unsigned int));
214 BreakpointAddr = NULL;
223 arch_handle_breakpoint(os_context_t *context)
225 /*sigsetmask(scp->sc_mask); */
226 handle_breakpoint(context);
230 arch_handle_fun_end_breakpoint(os_context_t *context)
232 /*sigsetmask(scp->sc_mask); */
235 handle_fun_end_breakpoint(context);
236 *os_context_pc_addr(context) = pc;
237 *os_context_npc_addr(context) = pc + 4;
238 *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags)
243 //FIX-lav: this whole is copied from mips
245 arch_handle_single_step_trap(os_context_t *context, int trap)
247 unsigned int code = *((u32 *)(os_context_pc(context)));
248 int register_offset = code >> 11 & 0x1f;
249 handle_single_step_trap(context, trap, register_offset);
250 arch_skip_instruction(context);
254 sigtrap_handler(int signal, siginfo_t *siginfo, void *void_context)
256 os_context_t *context = arch_os_get_context(&void_context);
257 unsigned int bad_inst;
259 bad_inst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
260 if (bad_inst & 0xfc001fe0)
261 interrupt_handle_now(signal, siginfo, context);
263 int im5 = bad_inst & 0x1f;
264 handle_trap(context, im5);
269 sigill_handler(int signal, siginfo_t *siginfo, void *void_context)
271 os_context_t *context = arch_os_get_context(&void_context);
272 unsigned int bad_inst;
274 bad_inst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
275 if (bad_inst == 9) { /* pending-interrupt */
276 arch_clear_pseudo_atomic_interrupted(context);
277 arch_skip_instruction(context);
278 interrupt_handle_pending(context);
280 handle_trap(context,bad_inst);
284 static void sigfpe_handler(int signal, siginfo_t *siginfo, void *void_context)
286 os_context_t *context = arch_os_get_context(&void_context);
287 unsigned int badinst;
288 int opcode, r1, r2, t;
291 switch (siginfo->si_code) {
292 case FPE_INTOVF: /*I_OVFLO: */
293 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
294 opcode = badinst >> 26;
298 r1 = (badinst >> 16) & 0x1f;
299 op1 = fixnum_value(*os_context_register_addr(context, r1));
300 r2 = (badinst >> 21) & 0x1f;
301 op2 = fixnum_value(*os_context_register_addr(context, r2));
304 switch ((badinst >> 5) & 0x7f) {
306 /* Add and trap on overflow. */
311 /* Subtract and trap on overflow. */
316 goto not_interesting;
319 else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
320 /* Add or subtract immediate. */
321 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
322 r2 = (badinst >> 16) & 0x1f;
323 op2 = fixnum_value(*os_context_register_addr(context, r2));
324 t = (badinst >> 21) & 0x1f;
331 goto not_interesting;
332 /* ?? What happens here if we hit the end of dynamic space? */
333 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
334 *os_context_register_addr(context, t) = alloc_number(res);
335 *os_context_register_addr(context, reg_ALLOC)
336 = (unsigned long) dynamic_space_free_pointer;
337 arch_skip_instruction(context);
344 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
345 if ((badinst&0xfffff800) == (0xb000e000|reg_ALLOC<<21|reg_ALLOC<<16)) {
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 the
348 * add stripping off the pseudo-atomic-interrupted bit, and then
349 * tell the machine-independent code to process the pseudo-
350 * atomic. We cant skip the instruction because it holds
351 * extra-bytes that we must add to reg_alloc in context.
352 * It is so because we optimized away 'addi ,extra-bytes reg_alloc'
354 int immed = (badinst>>1)&0x3ff;
357 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
358 arch_skip_instruction(context);
359 interrupt_handle_pending(context);
362 /* else drop-through. */
365 interrupt_handle_now(signal, siginfo, context);
369 /* Merrily cut'n'pasted from sigfpe_handler. On Linux, until
370 2.4.19-pa4 (hopefully), the overflow_trap wasn't implemented,
371 resulting in a SIGBUS instead. We adapt the sigfpe_handler here, in
372 the hope that it will do as a replacement until the new kernel sees
373 the light of day. Since the instructions that we need to fix up
374 tend not to be doing unaligned memory access, this should be a safe
375 workaround. -- CSR, 2002-08-17 */
376 static void sigbus_handler(int signal, siginfo_t *siginfo, void *void_context)
378 os_context_t *context = arch_os_get_context(&void_context);
379 unsigned int badinst;
380 int opcode, r1, r2, t;
383 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
384 /* First, test for the pseudo-atomic instruction */
385 if ((badinst & 0xfffff800) == (0xb000e000 |
388 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped.
389 That means that it is the end of a pseudo-atomic. So do
390 the add stripping off the pseudo-atomic-interrupted bit,
391 and then tell the machine-independent code to process the
393 int immed = (badinst>>1) & 0x3ff;
396 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
397 arch_skip_instruction(context);
398 interrupt_handle_pending(context);
401 opcode = badinst >> 26;
404 r1 = (badinst >> 16) & 0x1f;
405 op1 = fixnum_value(*os_context_register_addr(context, r1));
406 r2 = (badinst >> 21) & 0x1f;
407 op2 = fixnum_value(*os_context_register_addr(context, r2));
410 switch ((badinst >> 5) & 0x7f) {
412 /* Add and trap on overflow. */
417 /* Subtract and trap on overflow. */
422 goto not_interesting;
424 } else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
425 /* Add or subtract immediate. */
426 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
427 r2 = (badinst >> 16) & 0x1f;
428 op2 = fixnum_value(*os_context_register_addr(context, r2));
429 t = (badinst >> 21) & 0x1f;
436 goto not_interesting;
438 /* ?? What happens here if we hit the end of dynamic space? */
439 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
440 *os_context_register_addr(context, t) = alloc_number(res);
441 *os_context_register_addr(context, reg_ALLOC)
442 = (unsigned long) dynamic_space_free_pointer;
443 arch_skip_instruction(context);
448 interrupt_handle_now(signal, siginfo, context);
453 ignore_handler(int signal, siginfo_t *siginfo, void *void_context)
457 /* this routine installs interrupt handlers that will
458 * bypass the lisp interrupt handlers */
459 void arch_install_interrupt_handlers(void)
461 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
462 undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler);
463 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
464 /* FIXME: beyond 2.4.19-pa4 this shouldn't be necessary. */
465 undoably_install_low_level_interrupt_handler(SIGBUS,sigbus_handler);
466 #ifdef LISP_FEATURE_HPUX
467 undoably_install_low_level_interrupt_handler(SIGXCPU,ignore_handler);
468 undoably_install_low_level_interrupt_handler(SIGXFSZ,ignore_handler);