Remove more disassembler bogosity
[sbcl.git] / src / runtime / hppa-arch.c
blob90ab7cdc46b4b82f9b9a3fc4ade4999a85c0d985
1 /*
2 * This software is part of the SBCL system. See the README file for
3 * more information.
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.
11 #include <stdio.h>
13 /* Copied from sparc-arch.c. Not all of these are necessary, probably */
14 #include "sbcl.h"
15 #include "runtime.h"
16 #include "arch.h"
17 #include "globals.h"
18 #include "validate.h"
19 #include "os.h"
20 #include "lispregs.h"
21 #include "signal.h"
22 #include "alloc.h"
23 #include "interrupt.h"
24 #include "interr.h"
25 #include "breakpoint.h"
27 void arch_init(void)
29 return;
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;
41 #if 0
42 #ifdef LISP_FEATURE_HPUX
43 struct save_state *state;
44 os_vm_address_t addr;
46 state = (struct save_state *)(&(scp->sc_sl.sl_ss));
48 if (state == NULL)
49 return NULL;
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)
54 return addr;
56 /* Otherwise, it must have been a data fault. */
57 return (os_vm_address_t)state->ss_cr21;
58 #else
59 struct hp800_thread_state *state;
60 os_vm_address_t addr;
62 state = (struct hp800_thread_state *)(scp->sc_ap);
64 if (state == NULL)
65 return NULL;
67 /* Check the instruction address first. */
68 addr = scp->sc_pcoqh & ~3;
69 if (addr < 0x1000)
70 return addr;
72 /* Otherwise, it must have been a data fault. */
73 return state->cr21;
74 #endif
75 #endif
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.
94 * --NS 2007-05-15 */
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;
100 #else
101 return (!foreign_function_call_active) &&
102 ((*os_context_register_addr(context,reg_ALLOC)) & 4);
103 #endif
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)
112 |= SS_MODIFIEDWIDE;
113 #else
114 *os_context_register_addr(context,reg_ALLOC) |= 1;
115 #endif
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)
124 |= SS_MODIFIEDWIDE;
125 #else
126 *os_context_register_addr(context,reg_ALLOC) &= ~1;
127 #endif
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)
136 |= SS_MODIFIEDWIDE;
137 #endif
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));
147 return orig_inst;
150 void arch_remove_breakpoint(void *pc, unsigned int orig_inst)
152 unsigned int *ulpc = (unsigned int *)pc;
154 *ulpc = orig_inst;
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 */
162 #if 0
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);
172 BreakpointAddr = pc;
173 *pc = orig_inst;
174 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned int));
175 #else
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;
182 scp->sc_ps |= 0x10;
183 *(unsigned int *)SC_PC(scp) = orig_inst;
185 sigreturn(scp);
186 #endif
187 #endif
190 #ifdef LISP_FEATURE_HPUX
191 #if 0
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. */
198 if (NextPc == NULL)
199 lose("SingleStepBreakpoint trap at strange time.\n");
201 if ((SC_PC(scp)&~3) == (unsigned int)SingleStepTraps) {
202 /* The next instruction was not nullified. */
203 SC_PC(scp) = NextPc;
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;
211 else {
212 /* The next instruction was nullified, so we want to skip it. */
213 SC_PC(scp) = NextPc + 4;
214 SC_NPC(scp) = NextPc + 8;
216 NextPc = NULL;
218 if (BreakpointAddr) {
219 *BreakpointAddr = trap_Breakpoint;
220 os_flush_icache((os_vm_address_t)BreakpointAddr,
221 sizeof(unsigned int));
222 BreakpointAddr = NULL;
225 #endif
226 #endif
230 void
231 arch_handle_breakpoint(os_context_t *context)
233 /*sigsetmask(scp->sc_mask); */
234 handle_breakpoint(context);
237 void
238 arch_handle_fun_end_breakpoint(os_context_t *context)
240 /*sigsetmask(scp->sc_mask); */
241 unsigned long pc;
242 pc = (unsigned long)
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)
248 |= SS_MODIFIEDWIDE;
249 #endif
253 //FIX-lav: this whole is copied from mips
254 void
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);
263 static void
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);
271 else {
272 int im5 = bad_inst & 0x1f;
273 handle_trap(context, im5);
277 static void
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);
287 } else {
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 */
299 #else
300 if (siginfo->si_code == FPE_COND &&
301 #endif
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;
312 if (badinst & 1)
313 immed |= -1<<10;
314 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
315 arch_skip_instruction(context);
316 interrupt_handle_pending(context);
317 } else {
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 |
337 reg_ALLOC<<16)) {
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
342 pseudo-atomic. */
343 int immed = (badinst>>1) & 0x3ff;
344 if (badinst & 1)
345 immed |= -1<<10;
346 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
347 arch_skip_instruction(context);
348 interrupt_handle_pending(context);
349 } else {
350 interrupt_handle_now(signal, siginfo, context);
354 #ifdef LISP_FEATURE_HPUX
355 static void
356 ignore_handler(int signal, siginfo_t *siginfo, os_context_t *context)
359 #endif
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);
373 #endif