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.
19 #include "interrupt.h"
22 #include "interrupt.h"
24 #include "breakpoint.h"
27 #if defined(LISP_FEATURE_GENCGC)
28 #include "gencgc-alloc-region.h"
31 /* The header files may not define PT_DAR/PT_DSISR. This definition
32 is correct for all versions of ppc linux >= 2.0.30
34 As of DR2.1u4, MkLinux doesn't pass these registers to signal
35 handlers correctly; a patch is necessary in order to (partially)
38 Even with the patch, the DSISR may not have its 'write' bit set
39 correctly (it tends not to be set if the fault was caused by
40 something other than a protection violation.)
44 #if defined (LISP_FEATURE_DARWIN) || defined(LISP_FEATURE_LINUX)
58 arch_get_bad_addr(int sig
, siginfo_t
*code
, os_context_t
*context
)
62 #if defined(LISP_FEATURE_NETBSD)
63 addr
= (os_vm_address_t
) (code
->si_addr
);
65 addr
= (os_vm_address_t
) (*os_context_register_addr(context
,PT_DAR
));
72 arch_skip_instruction(os_context_t
*context
)
75 pcptr
= (char**) os_context_pc_addr(context
);
80 arch_internal_error_arguments(os_context_t
*context
)
82 return (unsigned char *)(*os_context_pc_addr(context
)+4);
87 arch_pseudo_atomic_atomic(os_context_t
*context
)
89 /* FIXME: this foreign_function_call_active test is dubious at
90 * best. If a foreign call is made in a pseudo atomic section
91 * (?) or more likely a pseudo atomic section is in a foreign
92 * call then an interrupt is executed immediately. Maybe it
93 * has to do with C code not maintaining pseudo atomic
94 * properly. MG - 2005-08-10
96 * The foreign_function_call_active used to live at each call-site
97 * to arch_pseudo_atomic_atomic, but this seems clearer.
99 return (!foreign_function_call_active
)
100 && ((*os_context_register_addr(context
,reg_ALLOC
)) & 4);
104 arch_set_pseudo_atomic_interrupted(os_context_t
*context
)
106 *os_context_register_addr(context
,reg_ALLOC
) |= 1;
110 arch_clear_pseudo_atomic_interrupted(os_context_t
*context
)
112 *os_context_register_addr(context
,reg_ALLOC
) &= ~1;
116 arch_install_breakpoint(void *pc
)
118 unsigned int *ptr
= (unsigned int *)pc
;
119 unsigned int result
= *ptr
;
120 *ptr
= (3<<26) | (5 << 21) | trap_Breakpoint
;
121 os_flush_icache((os_vm_address_t
) pc
, sizeof(unsigned int));
126 arch_remove_breakpoint(void *pc
, unsigned int orig_inst
)
128 *(unsigned int *)pc
= orig_inst
;
129 os_flush_icache((os_vm_address_t
) pc
, sizeof(unsigned int));
133 * Perform the instruction that we overwrote with a breakpoint. As we
134 * don't have a single-step facility, this means we have to:
135 * - put the instruction back
136 * - put a second breakpoint at the following instruction,
137 * set after_breakpoint and continue execution.
139 * When the second breakpoint is hit (very shortly thereafter, we hope)
140 * sigtrap_handler gets called again, but follows the AfterBreakpoint
142 * - puts a bpt back in the first breakpoint place (running across a
143 * breakpoint shouldn't cause it to be uninstalled)
144 * - replaces the second bpt with the instruction it was meant to be
149 static unsigned int *skipped_break_addr
, displaced_after_inst
;
150 static sigset_t orig_sigmask
;
153 arch_do_displaced_inst(os_context_t
*context
, unsigned int orig_inst
)
155 /* not sure how we ensure that we get the breakpoint reinstalled
156 * after doing this -dan */
157 unsigned int *pc
= (unsigned int *)(*os_context_pc_addr(context
));
159 orig_sigmask
= *os_context_sigmask_addr(context
);
160 sigaddset_blockable(os_context_sigmask_addr(context
));
163 os_flush_icache((os_vm_address_t
) pc
, sizeof(unsigned int));
164 skipped_break_addr
= pc
;
166 /* FIXME: we should apparently be installing the after-breakpoint
167 * here, but would need to find the next instruction address for
168 * it first. alpha-arch.c shows how to do it. --NS 2007-04-02 */
171 #ifdef LISP_FEATURE_GENCGC
173 * Return non-zero if the current instruction is an allocation trap
176 allocation_trap_p(os_context_t
* context
)
188 * First, the instruction has to be a TWLGE temp, NL3, which has the
190 * | 6| 5| 5 | 5 | 10|1| width
191 * |31|5 |dst|src| 4|0| field
193 pc
= (unsigned int *) (*os_context_pc_addr(context
));
197 fprintf(stderr
, "allocation_trap_p at %p: inst = 0x%08x\n", pc
, inst
);
201 src
= (inst
>> 11) & 0x1f;
202 dst
= (inst
>> 16) & 0x1f;
203 if ((opcode
== 31) && (src
== reg_NL3
) && (5 == ((inst
>> 21) & 0x1f))
204 && (4 == ((inst
>> 1) & 0x3ff))) {
206 * We got the instruction. Now, look back to make sure it was
207 * proceeded by what we expected. 2 instructions back should be
208 * an ADD or ADDI instruction.
210 unsigned int add_inst
;
214 fprintf(stderr
, " add inst at %p: inst = 0x%08x\n",
217 opcode
= add_inst
>> 26;
218 if ((opcode
== 31) && (266 == ((add_inst
>> 1) & 0x1ff))) {
220 } else if ((opcode
== 14)) {
224 "Whoa! Got allocation trap but could not find ADD or ADDI instruction: 0x%08x in the proper place\n",
231 extern struct alloc_region boxed_region
;
234 handle_allocation_trap(os_context_t
* context
)
238 unsigned int target
, target_ptr
, end_addr
;
241 boolean were_in_lisp
;
248 fprintf(stderr
, "In handle_allocation_trap\n");
251 /* I don't think it's possible for us NOT to be in lisp when we get
252 * here. Remove this later? */
253 were_in_lisp
= !foreign_function_call_active
;
256 fake_foreign_function_call(context
);
258 fprintf(stderr
, "**** Whoa! allocation trap and we weren't in lisp!\n");
262 * Look at current instruction: TWNE temp, NL3. We're here because
263 * temp > NL3 and temp is the end of the allocation, and NL3 is
264 * current-region-end-addr.
266 * We need to adjust temp and alloc-tn.
269 pc
= (unsigned int *) (*os_context_pc_addr(context
));
271 end_addr
= (inst
>> 11) & 0x1f;
272 target
= (inst
>> 16) & 0x1f;
274 target_ptr
= *os_context_register_addr(context
, target
);
277 fprintf(stderr
, "handle_allocation_trap at %p:\n", pc
);
278 fprintf(stderr
, "boxed_region.free_pointer: %p\n", boxed_region
.free_pointer
);
279 fprintf(stderr
, "boxed_region.end_addr: %p\n", boxed_region
.end_addr
);
280 fprintf(stderr
, "target reg: %d, end_addr reg: %d\n", target
, end_addr
);
281 fprintf(stderr
, "target: %x\n", *os_context_register_addr(context
, target
));
282 fprintf(stderr
, "end_addr: %x\n", *os_context_register_addr(context
, end_addr
));
286 fprintf(stderr
, "handle_allocation_trap at %p:\n", pc
);
287 fprintf(stderr
, " trap inst = 0x%08x\n", inst
);
288 fprintf(stderr
, " target reg = %s\n", lisp_register_names
[target
]);
292 * Go back and look at the add/addi instruction. The second src arg
293 * is the size of the allocation. Get it and call alloc to allocate
299 fprintf(stderr
, " add inst = 0x%08x, opcode = %d\n", inst
, opcode
);
303 * ADDI temp-tn, alloc-tn, size
307 size
= (inst
& 0xffff);
308 } else if (opcode
== 31) {
310 * ADD temp-tn, alloc-tn, size-tn
316 reg
= (inst
>> 11) & 0x1f;
318 fprintf(stderr
, " add, reg = %s\n", lisp_register_names
[reg
]);
320 size
= *os_context_register_addr(context
, reg
);
325 fprintf(stderr
, "Alloc %d to %s\n", size
, lisp_register_names
[target
]);
328 #if INLINE_ALLOC_DEBUG
329 if ((((unsigned long)boxed_region
.end_addr
+ size
) / PAGE_SIZE
) ==
330 (((unsigned long)boxed_region
.end_addr
) / PAGE_SIZE
)) {
331 fprintf(stderr
,"*** possibly bogus trap allocation of %d bytes at %p\n",
333 fprintf(stderr
, " dynamic_space_free_pointer: %p, boxed_region.end_addr %p\n",
334 dynamic_space_free_pointer
, boxed_region
.end_addr
);
339 fprintf(stderr
, "Ready to alloc\n");
340 fprintf(stderr
, "free_pointer = 0x%08x\n",
341 dynamic_space_free_pointer
);
345 * alloc-tn was incremented by size. Need to decrement it by size
346 * to restore its original value. This is not true on GENCGC
347 * anymore. d_s_f_p and reg_alloc get out of sync, but the p_a
348 * bits stay intact and we set it to the proper value when it
349 * needs to be. Keep this comment here for the moment in case
350 * somebody tries to figure out what happened here.
352 /* dynamic_space_free_pointer =
353 (lispobj *) ((long) dynamic_space_free_pointer - size);
356 fprintf(stderr
, "free_pointer = 0x%08x new\n",
357 dynamic_space_free_pointer
);
361 struct interrupt_data
*data
=
362 arch_os_get_current_thread()->interrupt_data
;
363 data
->allocation_trap_context
= context
;
364 memory
= (char *) alloc(size
);
365 data
->allocation_trap_context
= 0;
369 fprintf(stderr
, "alloc returned %p\n", memory
);
370 fprintf(stderr
, "free_pointer = 0x%08x\n",
371 dynamic_space_free_pointer
);
375 * The allocation macro wants the result to point to the end of the
381 fprintf(stderr
, "object end at %p\n", memory
);
384 *os_context_register_addr(context
, target
) = (unsigned long) memory
;
385 *os_context_register_addr(context
, reg_ALLOC
) =
386 (unsigned long) dynamic_space_free_pointer
387 | (*os_context_register_addr(context
, reg_ALLOC
)
391 undo_fake_foreign_function_call(context
);
399 arch_handle_breakpoint(os_context_t
*context
)
401 handle_breakpoint(context
);
405 arch_handle_fun_end_breakpoint(os_context_t
*context
)
407 *os_context_pc_addr(context
)
408 =(int)handle_fun_end_breakpoint(context
);
412 arch_handle_after_breakpoint(os_context_t
*context
)
414 *skipped_break_addr
= trap_Breakpoint
;
415 skipped_break_addr
= NULL
;
416 *(unsigned int *)*os_context_pc_addr(context
)
417 = displaced_after_inst
;
418 *os_context_sigmask_addr(context
)= orig_sigmask
;
419 os_flush_icache((os_vm_address_t
) *os_context_pc_addr(context
),
420 sizeof(unsigned int));
424 arch_handle_single_step_trap(os_context_t
*context
, int trap
)
426 unsigned int code
= *((u32
*)(*os_context_pc_addr(context
)));
427 int register_offset
= code
>> 5 & 0x1f;
428 handle_single_step_trap(context
, trap
, register_offset
);
429 arch_skip_instruction(context
);
433 sigtrap_handler(int signal
, siginfo_t
*siginfo
, os_context_t
*context
)
437 code
=*((u32
*)(*os_context_pc_addr(context
)));
438 if (code
== ((3 << 26) | (0x18 << 21) | (reg_NL3
<< 16))) {
439 arch_clear_pseudo_atomic_interrupted(context
);
440 arch_skip_instruction(context
);
441 /* interrupt or GC was requested in PA; now we're done with the
442 PA section we may as well get around to it */
443 interrupt_handle_pending(context
);
447 #ifdef LISP_FEATURE_GENCGC
448 /* Is this an allocation trap? */
449 if (allocation_trap_p(context
)) {
450 handle_allocation_trap(context
);
451 arch_skip_instruction(context
);
456 if ((code
>> 16) == ((3 << 10) | (6 << 5))) {
457 /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */
458 int trap
= code
& 0x1f;
459 handle_trap(context
,trap
);
462 if (((code
>> 26) == 3) && (((code
>> 21) & 31) == 24)) {
463 interrupt_internal_error(context
, 0);
467 interrupt_handle_now(signal
, (siginfo_t
*)code
, context
);
471 void arch_install_interrupt_handlers()
473 undoably_install_low_level_interrupt_handler(SIGILL
, sigtrap_handler
);
474 undoably_install_low_level_interrupt_handler(SIGTRAP
, sigtrap_handler
);
478 ppc_flush_icache(os_vm_address_t address
, os_vm_size_t length
)
480 os_vm_address_t end
= (os_vm_address_t
) ((int)(address
+length
+(32-1)) &~(32-1));
481 extern void ppc_flush_cache_line(os_vm_address_t
);
483 while (address
< end
) {
484 ppc_flush_cache_line(address
);
489 #ifdef LISP_FEATURE_LINKAGE_TABLE
491 /* Linkage tables for PowerPC
493 * Linkage entry size is 16, because we need at least 4 instructions to
498 * Define the registers to use in the linkage jump table. Can be the
499 * same. Some care must be exercised when choosing these. It has to be
500 * a register that is not otherwise being used. reg_NFP is a good
501 * choice. call_into_c trashes reg_NFP without preserving it, so we can
502 * trash it in the linkage jump table.
504 #define LINKAGE_TEMP_REG reg_NFP
505 #define LINKAGE_ADDR_REG reg_NFP
508 * Insert the necessary jump instructions at the given address.
511 arch_write_linkage_table_jmp(void* reloc_addr
, void *target_addr
)
514 * Make JMP to function entry.
516 * The instruction sequence is:
518 * addis 13, 0, (hi part of addr)
519 * ori 13, 13, (low part of addr)
525 unsigned long hi
; /* Top 16 bits of address */
526 unsigned long lo
; /* Low 16 bits of address */
529 inst_ptr
= (int*) reloc_addr
;
532 * Split the target address into hi and lo parts for the sethi
533 * instruction. hi is the top 22 bits. lo is the low 10 bits.
535 hi
= (unsigned long) target_addr
;
540 * addis 13, 0, (hi part)
543 inst
= (15 << 26) | (LINKAGE_TEMP_REG
<< 21) | (0 << 16) | hi
;
547 * ori 13, 13, (lo part)
550 inst
= (24 << 26) | (LINKAGE_TEMP_REG
<< 21) | (LINKAGE_TEMP_REG
<< 16) | lo
;
557 inst
= (31 << 26) | (LINKAGE_TEMP_REG
<< 21) | (9 << 16) | (467 << 1);
564 inst
= (19 << 26) | (20 << 21) | (528 << 1);
570 os_flush_icache((os_vm_address_t
) reloc_addr
, (char*) inst_ptr
- (char*) reloc_addr
);
574 arch_write_linkage_table_ref(void * reloc_addr
, void *target_addr
)
576 *(unsigned long *)reloc_addr
= (unsigned long)target_addr
;