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 #if defined(LISP_FEATURE_HPUX)
97 // FIX-lav: use accessor macro instead
98 return (!foreign_function_call_active
) &&
99 *(&((ucontext_t
*) context
)->uc_mcontext
.ss_wide
.ss_64
.ss_gr7
) & 4;
101 return (!foreign_function_call_active
) &&
102 ((*os_context_register_addr(context
,reg_ALLOC
)) & 4);
106 void arch_set_pseudo_atomic_interrupted(os_context_t
*context
)
108 #if defined(LISP_FEATURE_HPUX)
109 *(&((ucontext_t
*) context
)->uc_mcontext
.ss_wide
.ss_64
.ss_gr7
) |= 1;
110 /* on hpux do we need to watch out for the barbarian ? */
111 *((os_context_register_t
*) &((ucontext_t
*) context
)->uc_mcontext
.ss_flags
)
114 *os_context_register_addr(context
,reg_ALLOC
) |= 1;
118 /* FIXME: untested */
119 void arch_clear_pseudo_atomic_interrupted(os_context_t
*context
)
121 #if defined(LISP_FEATURE_HPUX)
122 *(&((ucontext_t
*) context
)->uc_mcontext
.ss_wide
.ss_64
.ss_gr7
) &= ~1;
123 *((os_context_register_t
*) &((ucontext_t
*) context
)->uc_mcontext
.ss_flags
)
126 *os_context_register_addr(context
,reg_ALLOC
) &= ~1;
130 void arch_skip_instruction(os_context_t
*context
)
132 *((unsigned int *) os_context_pc_addr(context
)) = *((unsigned int *) os_context_npc_addr(context
));
133 *((unsigned int *) os_context_npc_addr(context
)) += 4;
134 #ifdef LISP_FEATURE_HPUX
135 *((os_context_register_t
*) &((ucontext_t
*) context
)->uc_mcontext
.ss_flags
)
140 unsigned int arch_install_breakpoint(void *pc
)
142 unsigned int *ulpc
= (unsigned int *)pc
;
143 unsigned int orig_inst
= *ulpc
;
145 *ulpc
= trap_Breakpoint
;
146 os_flush_icache((os_vm_address_t
)pc
, sizeof(*ulpc
));
150 void arch_remove_breakpoint(void *pc
, unsigned int orig_inst
)
152 unsigned int *ulpc
= (unsigned int *)pc
;
155 os_flush_icache((os_vm_address_t
)pc
, sizeof(*ulpc
));
158 void arch_do_displaced_inst(os_context_t
*context
, unsigned int orig_inst
)
160 fprintf(stderr
, "arch_do_displaced_inst() WARNING: stub.\n");
161 /* FIXME: Fill this in */
163 #ifdef LISP_FEATURE_HPUX
164 /* We change the next-pc to point to a breakpoint instruction, restore */
165 /* the original instruction, and exit. We would like to be able to */
166 /* sigreturn, but we can't, because this is hpux. */
167 unsigned int *pc
= (unsigned int *)(SC_PC(scp
) & ~3);
169 NextPc
= SC_NPC(scp
);
170 SC_NPC(scp
) = (unsigned int)SingleStepTraps
| (SC_NPC(scp
)&3);
174 os_flush_icache((os_vm_address_t
)pc
, sizeof(unsigned int));
176 /* We set the recovery counter to cover one instruction, put the */
177 /* original instruction back in, and then resume. We will then trap */
178 /* after executing that one instruction, at which time we can put */
179 /* the breakpoint back in. */
181 ((struct hp800_thread_state
*)scp
->sc_ap
)->cr0
= 1;
183 *(unsigned int *)SC_PC(scp
) = orig_inst
;
190 #ifdef LISP_FEATURE_HPUX
192 static void restore_breakpoint(struct sigcontext
*scp
)
194 /* We just single-stepped over an instruction that we want to replace */
195 /* with a breakpoint. So we put the breakpoint back in, and tweek the */
196 /* state so that we will continue as if nothing happened. */
199 lose("SingleStepBreakpoint trap at strange time.\n");
201 if ((SC_PC(scp
)&~3) == (unsigned int)SingleStepTraps
) {
202 /* The next instruction was not nullified. */
204 if ((SC_NPC(scp
)&~3) == (unsigned int)SingleStepTraps
+ 4) {
205 /* The instruction we just stepped over was not a branch, so */
206 /* we need to fix it up. If it was a branch, it will point to */
207 /* the correct place. */
208 SC_NPC(scp
) = NextPc
+ 4;
212 /* The next instruction was nullified, so we want to skip it. */
213 SC_PC(scp
) = NextPc
+ 4;
214 SC_NPC(scp
) = NextPc
+ 8;
218 if (BreakpointAddr
) {
219 *BreakpointAddr
= trap_Breakpoint
;
220 os_flush_icache((os_vm_address_t
)BreakpointAddr
,
221 sizeof(unsigned int));
222 BreakpointAddr
= NULL
;
231 arch_handle_breakpoint(os_context_t
*context
)
233 /*sigsetmask(scp->sc_mask); */
234 handle_breakpoint(context
);
238 arch_handle_fun_end_breakpoint(os_context_t
*context
)
240 /*sigsetmask(scp->sc_mask); */
243 handle_fun_end_breakpoint(context
);
244 *os_context_pc_addr(context
) = pc
;
245 *os_context_npc_addr(context
) = pc
+ 4;
246 #ifdef LISP_FEATURE_HPUX
247 *((os_context_register_t
*) &((ucontext_t
*) context
)->uc_mcontext
.ss_flags
)
253 //FIX-lav: this whole is copied from mips
255 arch_handle_single_step_trap(os_context_t
*context
, int trap
)
257 unsigned int code
= *((u32
*)(os_context_pc(context
)));
258 int register_offset
= code
>> 11 & 0x1f;
259 handle_single_step_trap(context
, trap
, register_offset
);
260 arch_skip_instruction(context
);
264 sigtrap_handler(int signal
, siginfo_t
*siginfo
, os_context_t
*context
)
266 unsigned int bad_inst
;
268 bad_inst
= *(unsigned int *)(*os_context_pc_addr(context
) & ~3);
269 if (bad_inst
& 0xfc001fe0)
270 interrupt_handle_now(signal
, siginfo
, context
);
272 int im5
= bad_inst
& 0x1f;
273 handle_trap(context
, im5
);
278 sigill_handler(int signal
, siginfo_t
*siginfo
, os_context_t
*context
)
280 unsigned int bad_inst
;
282 bad_inst
= *(unsigned int *)(*os_context_pc_addr(context
) & ~3);
283 if (bad_inst
== 9) { /* pending-interrupt */
284 arch_clear_pseudo_atomic_interrupted(context
);
285 arch_skip_instruction(context
);
286 interrupt_handle_pending(context
);
288 handle_trap(context
,bad_inst
);
292 static void sigfpe_handler(int signal
, siginfo_t
*siginfo
,
293 os_context_t
*context
)
295 unsigned badinst
= *(unsigned *)(*os_context_pc_addr(context
) & ~3);
297 #ifdef LISP_FEATURE_LINUX
298 if (!siginfo
->si_code
&& /* Linux 3.14 seems to set si_code to 0 for this case */
300 if (siginfo
->si_code
== FPE_COND
&&
302 (badinst
&0xfffff800) == (0xb000e000|reg_ALLOC
<<21|reg_ALLOC
<<16)) {
303 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped.
304 * That means that it is the end of a pseudo-atomic. So do the
305 * add stripping off the pseudo-atomic-interrupted bit, and then
306 * tell the machine-independent code to process the pseudo-
307 * atomic. We cant skip the instruction because it holds
308 * extra-bytes that we must add to reg_alloc in context.
309 * It is so because we optimized away 'addi ,extra-bytes reg_alloc'
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
);
318 interrupt_handle_now(signal
, siginfo
, context
);
322 /* Merrily cut'n'pasted from sigfpe_handler. On Linux, until
323 2.4.19-pa4 (hopefully), the overflow_trap wasn't implemented,
324 resulting in a SIGBUS instead. We adapt the sigfpe_handler here, in
325 the hope that it will do as a replacement until the new kernel sees
326 the light of day. Since the instructions that we need to fix up
327 tend not to be doing unaligned memory access, this should be a safe
328 workaround. -- CSR, 2002-08-17 */
329 static void sigbus_handler(int signal
, siginfo_t
*siginfo
,
330 os_context_t
*context
)
333 unsigned badinst
= *(unsigned *)(*os_context_pc_addr(context
) & ~3);
335 /* First, test for the pseudo-atomic instruction */
336 if ((badinst
& 0xfffff800) == (0xb000e000 | reg_ALLOC
<<21 |
338 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped.
339 That means that it is the end of a pseudo-atomic. So do
340 the add stripping off the pseudo-atomic-interrupted bit,
341 and then tell the machine-independent code to process the
343 int immed
= (badinst
>>1) & 0x3ff;
346 *os_context_register_addr(context
, reg_ALLOC
) += (immed
-1);
347 arch_skip_instruction(context
);
348 interrupt_handle_pending(context
);
350 interrupt_handle_now(signal
, siginfo
, context
);
354 #ifdef LISP_FEATURE_HPUX
356 ignore_handler(int signal
, siginfo_t
*siginfo
, os_context_t
*context
)
361 /* this routine installs interrupt handlers that will
362 * bypass the lisp interrupt handlers */
363 void arch_install_interrupt_handlers(void)
365 undoably_install_low_level_interrupt_handler(SIGTRAP
,sigtrap_handler
);
366 undoably_install_low_level_interrupt_handler(SIGILL
,sigill_handler
);
367 undoably_install_low_level_interrupt_handler(SIGFPE
,sigfpe_handler
);
368 /* FIXME: beyond 2.4.19-pa4 this shouldn't be necessary. */
369 undoably_install_low_level_interrupt_handler(SIGBUS
,sigbus_handler
);
370 #ifdef LISP_FEATURE_HPUX
371 undoably_install_low_level_interrupt_handler(SIGXCPU
,ignore_handler
);
372 undoably_install_low_level_interrupt_handler(SIGXFSZ
,ignore_handler
);