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;
89 void arch_clear_pseudo_atomic_interrupted(os_context_t *context)
91 *os_context_register_addr(context,reg_ALLOC) &= ~1;
94 void arch_skip_instruction(os_context_t *context)
96 ((char *) *os_context_pc_addr(context)) = ((char *) *os_context_npc_addr(context));
97 ((char *) *os_context_npc_addr(context)) += 4;
100 unsigned int arch_install_breakpoint(void *pc)
102 unsigned int *ulpc = (unsigned int *)pc;
103 unsigned int orig_inst = *ulpc;
105 *ulpc = trap_Breakpoint;
106 os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
110 void arch_remove_breakpoint(void *pc, unsigned int orig_inst)
112 unsigned int *ulpc = (unsigned int *)pc;
115 os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc));
118 void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
120 /* FIXME: Fill this in */
123 /* We change the next-pc to point to a breakpoint instruction, restore */
124 /* the original instruction, and exit. We would like to be able to */
125 /* sigreturn, but we can't, because this is hpux. */
126 unsigned int *pc = (unsigned int *)(SC_PC(scp) & ~3);
128 NextPc = SC_NPC(scp);
129 SC_NPC(scp) = (unsigned int)SingleStepTraps | (SC_NPC(scp)&3);
133 os_flush_icache((os_vm_address_t)pc, sizeof(unsigned int));
135 /* We set the recovery counter to cover one instruction, put the */
136 /* original instruction back in, and then resume. We will then trap */
137 /* after executing that one instruction, at which time we can put */
138 /* the breakpoint back in. */
140 ((struct hp800_thread_state *)scp->sc_ap)->cr0 = 1;
142 *(unsigned int *)SC_PC(scp) = orig_inst;
150 static void restore_breakpoint(struct sigcontext *scp)
152 /* We just single-stepped over an instruction that we want to replace */
153 /* with a breakpoint. So we put the breakpoint back in, and tweek the */
154 /* state so that we will continue as if nothing happened. */
157 lose("SingleStepBreakpoint trap at strange time.\n");
159 if ((SC_PC(scp)&~3) == (unsigned int)SingleStepTraps) {
160 /* The next instruction was not nullified. */
162 if ((SC_NPC(scp)&~3) == (unsigned int)SingleStepTraps + 4) {
163 /* The instruction we just stepped over was not a branch, so */
164 /* we need to fix it up. If it was a branch, it will point to */
165 /* the correct place. */
166 SC_NPC(scp) = NextPc + 4;
170 /* The next instruction was nullified, so we want to skip it. */
171 SC_PC(scp) = NextPc + 4;
172 SC_NPC(scp) = NextPc + 8;
176 if (BreakpointAddr) {
177 *BreakpointAddr = trap_Breakpoint;
178 os_flush_icache((os_vm_address_t)BreakpointAddr,
179 sizeof(unsigned int));
180 BreakpointAddr = NULL;
185 static void sigtrap_handler(int signal, siginfo_t *siginfo, void *void_context)
187 os_context_t *context = arch_os_get_context(&void_context);
188 unsigned int bad_inst;
191 printf("sigtrap_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
192 SC_REG(scp,reg_ALLOC));
195 bad_inst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
196 if (bad_inst & 0xfc001fe0)
197 interrupt_handle_now(signal, siginfo, context);
199 int im5 = bad_inst & 0x1f;
203 fake_foreign_function_call(context);
204 lose("%%primitive halt called; the party is over.\n");
206 case trap_PendingInterrupt:
207 arch_skip_instruction(context);
208 interrupt_handle_pending(context);
213 interrupt_internal_error(signal, siginfo, context, im5==trap_Cerror);
216 case trap_Breakpoint:
217 /*sigsetmask(scp->sc_mask); */
218 handle_breakpoint(signal, siginfo, context);
221 case trap_FunEndBreakpoint:
222 /*sigsetmask(scp->sc_mask); */
226 handle_fun_end_breakpoint(signal, siginfo, context);
227 *os_context_pc_addr(context) = pc;
228 *os_context_npc_addr(context) = pc + 4;
232 case trap_SingleStepBreakpoint:
235 restore_breakpoint(context);
240 interrupt_handle_now(signal, siginfo, context);
246 static void sigfpe_handler(int signal, siginfo_t *siginfo, void *void_context)
248 os_context_t *context = arch_os_get_context(&void_context);
249 unsigned int badinst;
250 int opcode, r1, r2, t;
254 printf("sigfpe_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
255 SC_REG(scp,reg_ALLOC));
258 switch (siginfo->si_code) {
259 case FPE_INTOVF: /*I_OVFLO: */
260 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
261 opcode = badinst >> 26;
265 r1 = (badinst >> 16) & 0x1f;
266 op1 = fixnum_value(*os_context_register_addr(context, r1));
267 r2 = (badinst >> 21) & 0x1f;
268 op2 = fixnum_value(*os_context_register_addr(context, r2));
271 switch ((badinst >> 5) & 0x7f) {
273 /* Add and trap on overflow. */
278 /* Subtract and trap on overflow. */
283 goto not_interesting;
286 else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
287 /* Add or subtract immediate. */
288 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
289 r2 = (badinst >> 16) & 0x1f;
290 op2 = fixnum_value(*os_context_register_addr(context, r1));
291 t = (badinst >> 21) & 0x1f;
298 goto not_interesting;
300 /* ?? What happens here if we hit the end of dynamic space? */
301 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
302 *os_context_register_addr(context, t) = alloc_number(res);
303 *os_context_register_addr(context, reg_ALLOC)
304 = (unsigned long) dynamic_space_free_pointer;
305 arch_skip_instruction(context);
309 case 0: /* I_COND: ?? Maybe tagged add?? FIXME */
310 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
311 if ((badinst&0xfffff800) == (0xb000e000|reg_ALLOC<<21|reg_ALLOC<<16)) {
312 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. */
313 /* That means that it is the end of a pseudo-atomic. So do the */
314 /* add stripping off the pseudo-atomic-interrupted bit, and then */
315 /* tell the machine-independent code to process the pseudo- */
317 int immed = (badinst>>1)&0x3ff;
320 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
321 arch_skip_instruction(context);
322 interrupt_handle_pending(context);
325 /* else drop-through. */
328 interrupt_handle_now(signal, siginfo, context);
332 /* Merrily cut'n'pasted from sigfpe_handler. On Linux, until
333 2.4.19-pa4 (hopefully), the overflow_trap wasn't implemented,
334 resulting in a SIGBUS instead. We adapt the sigfpe_handler here, in
335 the hope that it will do as a replacement until the new kernel sees
336 the light of day. Since the instructions that we need to fix up
337 tend not to be doing unaligned memory access, this should be a safe
338 workaround. -- CSR, 2002-08-17 */
339 static void sigbus_handler(int signal, siginfo_t *siginfo, void *void_context)
341 os_context_t *context = arch_os_get_context(&void_context);
342 unsigned int badinst;
343 int opcode, r1, r2, t;
346 badinst = *(unsigned int *)(*os_context_pc_addr(context) & ~3);
347 /* First, test for the pseudo-atomic instruction */
348 if ((badinst & 0xfffff800) == (0xb000e000 |
351 /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped.
352 That means that it is the end of a pseudo-atomic. So do
353 the add stripping off the pseudo-atomic-interrupted bit,
354 and then tell the machine-independent code to process the
356 int immed = (badinst>>1) & 0x3ff;
359 *os_context_register_addr(context, reg_ALLOC) += (immed-1);
360 arch_skip_instruction(context);
361 interrupt_handle_pending(context);
364 opcode = badinst >> 26;
367 r1 = (badinst >> 16) & 0x1f;
368 op1 = fixnum_value(*os_context_register_addr(context, r1));
369 r2 = (badinst >> 21) & 0x1f;
370 op2 = fixnum_value(*os_context_register_addr(context, r2));
373 switch ((badinst >> 5) & 0x7f) {
375 /* Add and trap on overflow. */
380 /* Subtract and trap on overflow. */
385 goto not_interesting;
387 } else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
388 /* Add or subtract immediate. */
389 op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
390 r2 = (badinst >> 16) & 0x1f;
391 op2 = fixnum_value(*os_context_register_addr(context, r1));
392 t = (badinst >> 21) & 0x1f;
399 goto not_interesting;
401 /* ?? What happens here if we hit the end of dynamic space? */
402 dynamic_space_free_pointer = (lispobj *) *os_context_register_addr(context, reg_ALLOC);
403 *os_context_register_addr(context, t) = alloc_number(res);
404 *os_context_register_addr(context, reg_ALLOC)
405 = (unsigned long) dynamic_space_free_pointer;
406 arch_skip_instruction(context);
411 interrupt_handle_now(signal, siginfo, context);
416 void arch_install_interrupt_handlers(void)
418 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
419 undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler);
420 /* FIXME: beyond 2.4.19-pa4 this shouldn't be necessary. */
421 undoably_install_low_level_interrupt_handler(SIGBUS,sigbus_handler);
425 lispobj funcall0(lispobj function)
427 lispobj *args = current_control_stack_pointer;
429 return call_into_lisp(function, args, 0);
432 lispobj funcall1(lispobj function, lispobj arg0)
434 lispobj *args = current_control_stack_pointer;
436 current_control_stack_pointer += 1;
439 return call_into_lisp(function, args, 1);
442 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
444 lispobj *args = current_control_stack_pointer;
446 current_control_stack_pointer += 2;
450 return call_into_lisp(function, args, 2);
453 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
455 lispobj *args = current_control_stack_pointer;
457 current_control_stack_pointer += 3;
462 return call_into_lisp(function, args, 3);