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)
54 /* Magic encoding for the instruction used for traps. */
55 #define TRAP_INSTRUCTION(trap) ((3<<26) | (6 << 21) | (trap))
61 arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
65 #if defined(LISP_FEATURE_NETBSD) || defined(LISP_FEATURE_OPENBSD)
66 addr = (os_vm_address_t) (code->si_addr);
68 addr = (os_vm_address_t) (*os_context_register_addr(context,PT_DAR));
75 arch_skip_instruction(os_context_t *context)
78 pcptr = (char**) os_context_pc_addr(context);
83 arch_internal_error_arguments(os_context_t *context)
85 return (unsigned char *)(*os_context_pc_addr(context)+4);
90 arch_pseudo_atomic_atomic(os_context_t *context)
92 /* FIXME: this foreign_function_call_active test is dubious at
93 * best. If a foreign call is made in a pseudo atomic section
94 * (?) or more likely a pseudo atomic section is in a foreign
95 * call then an interrupt is executed immediately. Maybe it
96 * has to do with C code not maintaining pseudo atomic
97 * properly. MG - 2005-08-10
99 * The foreign_function_call_active used to live at each call-site
100 * to arch_pseudo_atomic_atomic, but this seems clearer.
102 return (!foreign_function_call_active_p(arch_os_get_current_thread()))
103 && ((*os_context_register_addr(context,reg_ALLOC)) & 4);
107 arch_set_pseudo_atomic_interrupted(os_context_t *context)
109 *os_context_register_addr(context,reg_ALLOC) |= 1;
113 arch_clear_pseudo_atomic_interrupted(os_context_t *context)
115 *os_context_register_addr(context,reg_ALLOC) &= ~1;
119 arch_install_breakpoint(void *pc)
121 unsigned int *ptr = (unsigned int *)pc;
122 unsigned int result = *ptr;
123 *ptr = TRAP_INSTRUCTION(trap_Breakpoint);
124 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
129 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
131 *(unsigned int *)pc = orig_inst;
132 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
136 * Perform the instruction that we overwrote with a breakpoint. As we
137 * don't have a single-step facility, this means we have to:
138 * - put the instruction back
139 * - put a second breakpoint at the following instruction,
140 * set after_breakpoint and continue execution.
142 * When the second breakpoint is hit (very shortly thereafter, we hope)
143 * sigtrap_handler gets called again, but follows the AfterBreakpoint
145 * - puts a bpt back in the first breakpoint place (running across a
146 * breakpoint shouldn't cause it to be uninstalled)
147 * - replaces the second bpt with the instruction it was meant to be
152 static unsigned int *skipped_break_addr, displaced_after_inst;
153 static sigset_t orig_sigmask;
156 should_branch(os_context_t *context, unsigned int orig_inst)
158 /* orig_inst is a conditional branch instruction. We need to
159 * know if the branch will be taken if executed in context. */
160 int ctr = *os_context_ctr_addr(context);
161 int cr = *os_context_cr_addr(context);
162 int bo_field = (orig_inst >> 21) & 0x1f;
163 int bi_field = (orig_inst >> 16) & 0x1f;
166 if (!(bo_field & 4)) ctr--; /* Decrement CTR if necessary. */
168 ctr_ok = (bo_field & 4) || ((ctr == 0) == ((bo_field & 2) == 2));
169 return ctr_ok && ((bo_field & 0x10) ||
170 !(((cr >> (31-bi_field)) ^ (bo_field >> 3)) & 1));
174 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
176 /* not sure how we ensure that we get the breakpoint reinstalled
177 * after doing this -dan */
178 unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context));
179 unsigned int *next_pc;
180 int op = orig_inst >> 26;
181 int sub_op = (orig_inst & 0x7fe) >> 1; /* XL-form sub-opcode */
183 orig_sigmask = *os_context_sigmask_addr(context);
184 sigaddset_blockable(os_context_sigmask_addr(context));
187 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
188 skipped_break_addr = pc;
190 /* Figure out where we will end up after running the displaced
191 * instruction by defaulting to the next instruction in the stream
192 * and then checking for branch instructions. FIXME: This will
193 * probably screw up if it attempts to step a trap instruction. */
198 unsigned int displacement = orig_inst & 0x03fffffc;
200 if (displacement & 0x02000000) {
201 displacement |= 0xc0000000;
203 if (orig_inst & 2) { /* Absolute Address */
204 next_pc = (unsigned int *)displacement;
206 next_pc = (unsigned int *)(((unsigned int)pc) + displacement);
208 } else if ((op == 16)
209 && should_branch(context, orig_inst)) {
210 /* Branch Conditional B-form */
211 unsigned int displacement = orig_inst & 0x0000fffc;
213 if (displacement & 0x00008000) {
214 displacement |= 0xffff0000;
216 if (orig_inst & 2) { /* Absolute Address */
217 next_pc = (unsigned int *)displacement;
219 next_pc = (unsigned int *)(((unsigned int)pc) + displacement);
221 } else if ((op == 19) && (sub_op == 16)
222 && should_branch(context, orig_inst)) {
223 /* Branch Conditional to Link Register XL-form */
224 next_pc = (unsigned int *)
225 ((*os_context_lr_addr(context)) & ~3);
226 } else if ((op == 19) && (sub_op == 528)
227 && should_branch(context, orig_inst)) {
228 /* Branch Conditional to Count Register XL-form */
229 next_pc = (unsigned int *)
230 ((*os_context_ctr_addr(context)) & ~3);
233 /* Set the "after" breakpoint. */
234 displaced_after_inst = *next_pc;
235 *next_pc = TRAP_INSTRUCTION(trap_AfterBreakpoint);
236 os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned int));
239 #ifdef LISP_FEATURE_GENCGC
241 * Return non-zero if the current instruction is an allocation trap
244 allocation_trap_p(os_context_t * context)
256 * First, the instruction has to be a TWLGE temp, NL3, which has the
258 * | 6| 5| 5 | 5 | 10|1| width
259 * |31|5 |dst|src| 4|0| field
261 pc = (unsigned int *) (*os_context_pc_addr(context));
265 fprintf(stderr, "allocation_trap_p at %p: inst = 0x%08x\n", pc, inst);
269 src = (inst >> 11) & 0x1f;
270 dst = (inst >> 16) & 0x1f;
271 if ((opcode == 31) && (src == reg_NL3) && (5 == ((inst >> 21) & 0x1f))
272 && (4 == ((inst >> 1) & 0x3ff))) {
274 * We got the instruction. Now, look back to make sure it was
275 * proceeded by what we expected. 2 instructions back should be
276 * an ADD or ADDI instruction.
278 unsigned int add_inst;
282 fprintf(stderr, " add inst at %p: inst = 0x%08x\n",
285 opcode = add_inst >> 26;
286 if ((opcode == 31) && (266 == ((add_inst >> 1) & 0x1ff))) {
288 } else if ((opcode == 14)) {
292 "Whoa! Got allocation trap but could not find ADD or ADDI instruction: 0x%08x in the proper place\n",
299 extern struct alloc_region boxed_region;
302 handle_allocation_trap(os_context_t * context)
306 unsigned int target, target_ptr, end_addr;
309 boolean were_in_lisp;
316 fprintf(stderr, "In handle_allocation_trap\n");
319 /* I don't think it's possible for us NOT to be in lisp when we get
320 * here. Remove this later? */
321 were_in_lisp = !foreign_function_call_active_p(arch_os_get_current_thread());
324 fake_foreign_function_call(context);
326 fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
330 * Look at current instruction: TWNE temp, NL3. We're here because
331 * temp > NL3 and temp is the end of the allocation, and NL3 is
332 * current-region-end-addr.
334 * We need to adjust temp and alloc-tn.
337 pc = (unsigned int *) (*os_context_pc_addr(context));
339 end_addr = (inst >> 11) & 0x1f;
340 target = (inst >> 16) & 0x1f;
342 target_ptr = *os_context_register_addr(context, target);
345 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
346 fprintf(stderr, "boxed_region.free_pointer: %p\n", boxed_region.free_pointer);
347 fprintf(stderr, "boxed_region.end_addr: %p\n", boxed_region.end_addr);
348 fprintf(stderr, "target reg: %d, end_addr reg: %d\n", target, end_addr);
349 fprintf(stderr, "target: %x\n", *os_context_register_addr(context, target));
350 fprintf(stderr, "end_addr: %x\n", *os_context_register_addr(context, end_addr));
354 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
355 fprintf(stderr, " trap inst = 0x%08x\n", inst);
356 fprintf(stderr, " target reg = %s\n", lisp_register_names[target]);
360 * Go back and look at the add/addi instruction. The second src arg
361 * is the size of the allocation. Get it and call alloc to allocate
367 fprintf(stderr, " add inst = 0x%08x, opcode = %d\n", inst, opcode);
371 * ADDI temp-tn, alloc-tn, size
375 size = (inst & 0xffff);
376 } else if (opcode == 31) {
378 * ADD temp-tn, alloc-tn, size-tn
384 reg = (inst >> 11) & 0x1f;
386 fprintf(stderr, " add, reg = %s\n", lisp_register_names[reg]);
388 size = *os_context_register_addr(context, reg);
393 fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
396 #if INLINE_ALLOC_DEBUG
397 if ((((unsigned long)boxed_region.end_addr + size) / PAGE_SIZE) ==
398 (((unsigned long)boxed_region.end_addr) / PAGE_SIZE)) {
399 fprintf(stderr,"*** possibly bogus trap allocation of %d bytes at %p\n",
401 fprintf(stderr, " dynamic_space_free_pointer: %p, boxed_region.end_addr %p\n",
402 dynamic_space_free_pointer, boxed_region.end_addr);
407 fprintf(stderr, "Ready to alloc\n");
408 fprintf(stderr, "free_pointer = 0x%08x\n",
409 dynamic_space_free_pointer);
413 * alloc-tn was incremented by size. Need to decrement it by size
414 * to restore its original value. This is not true on GENCGC
415 * anymore. d_s_f_p and reg_alloc get out of sync, but the p_a
416 * bits stay intact and we set it to the proper value when it
417 * needs to be. Keep this comment here for the moment in case
418 * somebody tries to figure out what happened here.
420 /* dynamic_space_free_pointer =
421 (lispobj *) ((long) dynamic_space_free_pointer - size);
424 fprintf(stderr, "free_pointer = 0x%08x new\n",
425 dynamic_space_free_pointer);
429 struct interrupt_data *data =
430 arch_os_get_current_thread()->interrupt_data;
431 data->allocation_trap_context = context;
432 memory = (char *) alloc(size);
433 data->allocation_trap_context = 0;
437 fprintf(stderr, "alloc returned %p\n", memory);
438 fprintf(stderr, "free_pointer = 0x%08x\n",
439 dynamic_space_free_pointer);
443 * The allocation macro wants the result to point to the end of the
449 fprintf(stderr, "object end at %p\n", memory);
452 *os_context_register_addr(context, target) = (unsigned long) memory;
453 *os_context_register_addr(context, reg_ALLOC) =
454 (unsigned long) dynamic_space_free_pointer
455 | (*os_context_register_addr(context, reg_ALLOC)
459 undo_fake_foreign_function_call(context);
467 arch_handle_breakpoint(os_context_t *context)
469 handle_breakpoint(context);
473 arch_handle_fun_end_breakpoint(os_context_t *context)
475 *os_context_pc_addr(context)
476 =(int)handle_fun_end_breakpoint(context);
480 arch_handle_after_breakpoint(os_context_t *context)
482 *skipped_break_addr = TRAP_INSTRUCTION(trap_Breakpoint);
483 os_flush_icache((os_vm_address_t) skipped_break_addr,
484 sizeof(unsigned int));
485 skipped_break_addr = NULL;
486 *(unsigned int *)*os_context_pc_addr(context)
487 = displaced_after_inst;
488 *os_context_sigmask_addr(context)= orig_sigmask;
489 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context),
490 sizeof(unsigned int));
494 arch_handle_single_step_trap(os_context_t *context, int trap)
496 unsigned int code = *((u32 *)(*os_context_pc_addr(context)));
497 int register_offset = code >> 5 & 0x1f;
498 handle_single_step_trap(context, trap, register_offset);
499 arch_skip_instruction(context);
503 sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
507 code=*((u32 *)(*os_context_pc_addr(context)));
508 if (code == ((3 << 26) | (0x18 << 21) | (reg_NL3 << 16))) {
509 arch_clear_pseudo_atomic_interrupted(context);
510 arch_skip_instruction(context);
511 /* interrupt or GC was requested in PA; now we're done with the
512 PA section we may as well get around to it */
513 interrupt_handle_pending(context);
517 #ifdef LISP_FEATURE_GENCGC
518 /* Is this an allocation trap? */
519 if (allocation_trap_p(context)) {
520 handle_allocation_trap(context);
521 arch_skip_instruction(context);
526 if ((code >> 16) == ((3 << 10) | (6 << 5))) {
527 /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */
528 int trap = code & 0x1f;
529 handle_trap(context,trap);
532 if (((code >> 26) == 3) && (((code >> 21) & 31) == 24)) {
533 interrupt_internal_error(context, 0);
537 interrupt_handle_now(signal, (siginfo_t *)code, context);
541 void arch_install_interrupt_handlers()
543 undoably_install_low_level_interrupt_handler(SIGILL, sigtrap_handler);
544 undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler);
548 ppc_flush_icache(os_vm_address_t address, os_vm_size_t length)
550 os_vm_address_t end = (os_vm_address_t) ((int)(address+length+(32-1)) &~(32-1));
551 extern void ppc_flush_cache_line(os_vm_address_t);
553 while (address < end) {
554 ppc_flush_cache_line(address);
559 #ifdef LISP_FEATURE_LINKAGE_TABLE
561 /* Linkage tables for PowerPC
563 * Linkage entry size is 16, because we need at least 4 instructions to
568 * Define the registers to use in the linkage jump table. Can be the
569 * same. Some care must be exercised when choosing these. It has to be
570 * a register that is not otherwise being used. reg_NFP is a good
571 * choice. call_into_c trashes reg_NFP without preserving it, so we can
572 * trash it in the linkage jump table.
574 #define LINKAGE_TEMP_REG reg_NFP
575 #define LINKAGE_ADDR_REG reg_NFP
578 * Insert the necessary jump instructions at the given address.
581 arch_write_linkage_table_jmp(void* reloc_addr, void *target_addr)
584 * Make JMP to function entry.
586 * The instruction sequence is:
588 * addis 13, 0, (hi part of addr)
589 * ori 13, 13, (low part of addr)
595 unsigned long hi; /* Top 16 bits of address */
596 unsigned long lo; /* Low 16 bits of address */
599 inst_ptr = (int*) reloc_addr;
602 * Split the target address into hi and lo parts for the sethi
603 * instruction. hi is the top 22 bits. lo is the low 10 bits.
605 hi = (unsigned long) target_addr;
610 * addis 13, 0, (hi part)
613 inst = (15 << 26) | (LINKAGE_TEMP_REG << 21) | (0 << 16) | hi;
617 * ori 13, 13, (lo part)
620 inst = (24 << 26) | (LINKAGE_TEMP_REG << 21) | (LINKAGE_TEMP_REG << 16) | lo;
627 inst = (31 << 26) | (LINKAGE_TEMP_REG << 21) | (9 << 16) | (467 << 1);
634 inst = (19 << 26) | (20 << 21) | (528 << 1);
637 os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - (char*) reloc_addr);
641 arch_write_linkage_table_ref(void * reloc_addr, void *target_addr)
643 *(unsigned long *)reloc_addr = (unsigned long)target_addr;