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.
22 #include "interrupt.h"
24 #include "breakpoint.h"
32 os_vm_address_t
arch_get_bad_addr(int sig
, siginfo_t
*code
, os_context_t
*context
)
34 return (os_vm_address_t
)code
->si_addr
;
37 void arch_skip_instruction(os_context_t
*context
)
39 /* KLUDGE: Other platforms check for trap codes and skip inlined
40 * trap/error parameters. We should too. */
42 /* Note that we're doing integer arithmetic here, not pointer. So
43 * the value that the return value of os_context_pc_addr() points
44 * to will be incremented by 4, not 16.
46 *os_context_pc_addr(context
) += 4;
49 unsigned char *arch_internal_error_arguments(os_context_t
*context
)
51 return (unsigned char *)(*os_context_pc_addr(context
) + 5);
54 boolean
arch_pseudo_atomic_atomic(os_context_t
*context
)
56 /* FIXME: this foreign_function_call_active test is dubious at
57 * best. If a foreign call is made in a pseudo atomic section
58 * (?) or more likely a pseudo atomic section is in a foreign
59 * call then an interrupt is executed immediately. Maybe it
60 * has to do with C code not maintaining pseudo atomic
61 * properly. MG - 2005-08-10
63 * The foreign_function_call_active used to live at each call-site
64 * to arch_pseudo_atomic_atomic, but this seems clearer.
66 return (!foreign_function_call_active
)
67 && (NIL
!= SymbolValue(PSEUDO_ATOMIC_ATOMIC
,0));
70 void arch_set_pseudo_atomic_interrupted(os_context_t
*context
)
72 /* 0x000f0001 is the syscall number for BREAK_POINT. */
73 SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED
,MAKE_FIXNUM(0x000f0001),0);
76 void arch_clear_pseudo_atomic_interrupted(os_context_t
*context
)
78 SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED
,NIL
,0);
81 unsigned int arch_install_breakpoint(void *pc
)
83 /* FIXME: Implement. */
88 void arch_remove_breakpoint(void *pc
, unsigned int orig_inst
)
90 /* FIXME: Implement. */
93 void arch_do_displaced_inst(os_context_t
*context
, unsigned int orig_inst
)
95 /* FIXME: Implement. */
99 static int pseudo_atomic_trap_p(os_context_t
*context
)
102 unsigned int badinst
;
106 pc
= (unsigned int*) *os_context_pc_addr(context
);
110 /* Check to see if the current instruction is a pseudo-atomic-trap */
111 if (((badinst
>> 30) == 2) && (((badinst
>> 19) & 0x3f) == 0x3a)
112 && (((badinst
>> 13) & 1) == 1) && ((badinst
& 0x7f) == PSEUDO_ATOMIC_TRAP
))
114 unsigned int previnst
;
117 * Check to see if the previous instruction was an andcc alloc-tn,
118 * 3, zero-tn instruction.
120 if (((previnst
>> 30) == 2) && (((previnst
>> 19) & 0x3f) == 0x11)
121 && (((previnst
>> 14) & 0x1f) == reg_ALLOC
)
122 && (((previnst
>> 25) & 0x1f) == reg_ZERO
)
123 && (((previnst
>> 13) & 1) == 1)
124 && ((previnst
& 0x1fff) == 3))
130 fprintf(stderr
, "Oops! Got a PSEUDO-ATOMIC-TRAP without a preceeding andcc!\n");
138 arch_handle_breakpoint(os_context_t
*context
)
140 handle_breakpoint(context
);
144 arch_handle_fun_end_breakpoint(os_context_t
*context
)
146 *os_context_pc_addr(context
) = (int) handle_fun_end_breakpoint(context
);
151 arch_handle_after_breakpoint(os_context_t
*context
)
153 *skipped_break_addr
= trap_Breakpoint
;
154 os_flush_icache(skipped_break_addr
, sizeof(unsigned int));
155 skipped_break_addr
= NULL
;
156 *(unsigned long *) os_context_pc_addr(context
) = displaced_after_inst
;
157 /* context->sigmask = orig_sigmask; */
158 os_flush_icache((os_vm_address_t
) os_context_pc_addr(context
), sizeof(unsigned int));
163 arch_handle_single_step_trap(os_context_t
*context
, int trap
)
165 unsigned char register_offset
=
166 *((unsigned char *)(*os_context_pc_addr(context
))+5);
167 handle_single_step_trap(context
, trap
, register_offset
);
168 /* KLUDGE: arch_skip_instruction() only skips one instruction, and
169 * there is a following word to deal with as well, so skip
171 arch_skip_instruction(context
);
172 arch_skip_instruction(context
);
176 static void sigill_handler(int signal
, siginfo_t
*siginfo
,
177 os_context_t
*context
)
179 if ((siginfo
->si_code
) == ILL_ILLOPC
180 #ifdef LISP_FEATURE_LINUX
181 || (linux_sparc_siginfo_bug
&& (siginfo
->si_code
== 2))
186 unsigned int* pc
= (unsigned int*) siginfo
->si_addr
;
190 handle_trap(context
,trap
);
192 else if ((siginfo
->si_code
) == ILL_ILLTRP
193 #ifdef LISP_FEATURE_LINUX
194 || (linux_sparc_siginfo_bug
&& (siginfo
->si_code
) == 192)
197 if (pseudo_atomic_trap_p(context
)) {
198 /* A trap instruction from a pseudo-atomic. We just need
199 to fixup up alloc-tn to remove the interrupted flag,
200 skip over the trap instruction, and then handle the
201 pending interrupt(s). */
202 arch_clear_pseudo_atomic_interrupted(context
);
203 arch_skip_instruction(context
);
204 interrupt_handle_pending(context
);
207 interrupt_internal_error(context
, 0);
211 interrupt_handle_now(signal
, siginfo
, context
);
215 static void sigemt_handler(int signal
, siginfo_t
*siginfo
,
216 os_context_t
*context
)
218 unsigned int badinst
;
219 boolean subtract
, immed
;
220 int rd
, rs1
, op1
, rs2
, op2
, result
;
222 badinst
= *(unsigned int *)os_context_pc_addr(context
);
223 if ((badinst
>> 30) != 2 || ((badinst
>> 20) & 0x1f) != 0x11) {
224 /* It wasn't a tagged add. Pass the signal into lisp. */
225 interrupt_handle_now(signal
, siginfo
, context
);
229 fprintf(stderr
, "SIGEMT trap handler with tagged op instruction!\n");
231 /* Extract the parts of the inst. */
232 subtract
= badinst
& (1<<19);
233 rs1
= (badinst
>>14) & 0x1f;
234 op1
= *os_context_register_addr(context
, rs1
);
236 /* If the first arg is $ALLOC then it is really a signal-pending note */
237 /* for the pseudo-atomic noise. */
238 if (rs1
== reg_ALLOC
) {
239 /* Perform the op anyway. */
240 op2
= badinst
& 0x1fff;
247 /* KLUDGE: this & ~7 is a little bit magical but basically
248 clears pseudo_atomic bits if any */
249 *os_context_register_addr(context
, reg_ALLOC
) = result
& ~7;
250 arch_skip_instruction(context
);
251 interrupt_handle_pending(context
);
255 if ((op1
& 3) != 0) {
256 /* The first arg wan't a fixnum. */
257 interrupt_internal_error(context
, 0);
261 if (immed
= badinst
& (1<<13)) {
262 op2
= badinst
& 0x1fff;
267 rs2
= badinst
& 0x1f;
268 op2
= *os_context_register_addr(context
, rs2
);
271 if ((op2
& 3) != 0) {
272 /* The second arg wan't a fixnum. */
273 interrupt_internal_error(context
, 0);
277 rd
= (badinst
>>25) & 0x1f;
279 /* Don't bother computing the result unless we are going to use it. */
281 result
= (op1
>>2) - (op2
>>2);
283 result
= (op1
>>2) + (op2
>>2);
285 dynamic_space_free_pointer
=
286 (lispobj
*) *os_context_register_addr(context
, reg_ALLOC
);
288 *os_context_register_addr(context
, rd
) = alloc_number(result
);
290 *os_context_register_addr(context
, reg_ALLOC
) =
291 (unsigned long) dynamic_space_free_pointer
;
294 arch_skip_instruction(context
);
299 sigtrap_handler(int signal
, siginfo_t
*siginfo
, os_context_t
*context
)
301 unsigned int code
= *((unsigned char *)(4+*os_context_pc_addr(context
)));
302 u32 trap_instruction
= *((u32
*)*os_context_pc_addr(context
));
303 int condition_bits
= (trap_instruction
>> 28) & 0x0f;
305 /* Make sure that we're looking at an SWI instruction or that one
306 * undefined instruction that the kernel recognizes as an explicit
308 if ((condition_bits
== 15)
309 || (((trap_instruction
& 0x0f000000) != 0x0f000000)
310 && (trap_instruction
!= 0xe7f001f0))) {
311 lose("Unrecognized trap instruction %08lx in sigtrap_handler()",
315 switch (condition_bits
) {
318 /* This is a handle-pending-interrupt trap. */
319 arch_clear_pseudo_atomic_interrupted(context
);
320 arch_skip_instruction(context
);
321 interrupt_handle_pending(context
);
325 /* This is a generic trap. */
326 handle_trap(context
, code
);
330 /* This is something that we don't recognize and therefore
331 * should not happen. */
332 lose("Unknown trap condition bits 0x%x", condition_bits
);
336 void arch_install_interrupt_handlers()
339 undoably_install_low_level_interrupt_handler(SIGILL
, sigill_handler
);
340 undoably_install_low_level_interrupt_handler(SIGEMT
, sigemt_handler
);
342 undoably_install_low_level_interrupt_handler(SIGTRAP
, sigtrap_handler
);
346 #ifdef LISP_FEATURE_LINKAGE_TABLE
350 * Linkage entry size is 16, because we need 4 instructions.
353 #define LINKAGE_TEMP_REG reg_NFP
355 void arch_write_linkage_table_jmp(void* reloc_addr
, void *target_addr
)
363 BX is needed for thumb interworking, without it it could take just two words with
370 inst_ptr
= (int*) reloc_addr
;
373 inst
= 0xe59f0000 | LINKAGE_TEMP_REG
<< 12 | 4;
377 inst
= 0xe12fff10 | LINKAGE_TEMP_REG
;
380 // nop aka mov r0, r0
385 *inst_ptr
++ = target_addr
;
387 os_flush_icache((os_vm_address_t
) reloc_addr
, (char*) inst_ptr
- (char*) reloc_addr
);
391 arch_write_linkage_table_ref(void * reloc_addr
, void *target_addr
)
393 *(unsigned long *)reloc_addr
= (unsigned long)target_addr
;