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.
21 #include "interrupt.h"
23 #include "breakpoint.h"
26 #if defined(LISP_FEATURE_GENCGC)
27 #include "gencgc-alloc-region.h"
30 /* The header files may not define PT_DAR/PT_DSISR. This definition
31 is correct for all versions of ppc linux >= 2.0.30
33 As of DR2.1u4, MkLinux doesn't pass these registers to signal
34 handlers correctly; a patch is necessary in order to (partially)
37 Even with the patch, the DSISR may not have its 'write' bit set
38 correctly (it tends not to be set if the fault was caused by
39 something other than a protection violation.)
43 #if defined (LISP_FEATURE_DARWIN) || defined(LISP_FEATURE_LINUX)
57 arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
61 #if defined(LISP_FEATURE_NETBSD)
62 addr = (os_vm_address_t) (code->si_addr);
64 addr = (os_vm_address_t) (*os_context_register_addr(context,PT_DAR));
71 arch_skip_instruction(os_context_t *context)
74 pcptr = (char**) os_context_pc_addr(context);
79 arch_internal_error_arguments(os_context_t *context)
81 return (unsigned char *)(*os_context_pc_addr(context)+4);
86 arch_pseudo_atomic_atomic(os_context_t *context)
88 /* FIXME: this foreign_function_call_active test is dubious at
89 * best. If a foreign call is made in a pseudo atomic section
90 * (?) or more likely a pseudo atomic section is in a foreign
91 * call then an interrupt is executed immediately. Maybe it
92 * has to do with C code not maintaining pseudo atomic
93 * properly. MG - 2005-08-10
95 * The foreign_function_call_active used to live at each call-site
96 * to arch_pseudo_atomic_atomic, but this seems clearer.
98 return (!foreign_function_call_active)
99 && ((*os_context_register_addr(context,reg_ALLOC)) & 4);
103 arch_set_pseudo_atomic_interrupted(os_context_t *context)
105 *os_context_register_addr(context,reg_ALLOC) |= 1;
109 arch_clear_pseudo_atomic_interrupted(os_context_t *context)
111 *os_context_register_addr(context,reg_ALLOC) &= ~1;
115 arch_install_breakpoint(void *pc)
117 unsigned int *ptr = (unsigned int *)pc;
118 unsigned int result = *ptr;
119 *ptr = (3<<26) | (5 << 21) | trap_Breakpoint;
120 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
125 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
127 *(unsigned int *)pc = orig_inst;
128 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
132 * Perform the instruction that we overwrote with a breakpoint. As we
133 * don't have a single-step facility, this means we have to:
134 * - put the instruction back
135 * - put a second breakpoint at the following instruction,
136 * set after_breakpoint and continue execution.
138 * When the second breakpoint is hit (very shortly thereafter, we hope)
139 * sigtrap_handler gets called again, but follows the AfterBreakpoint
141 * - puts a bpt back in the first breakpoint place (running across a
142 * breakpoint shouldn't cause it to be uninstalled)
143 * - replaces the second bpt with the instruction it was meant to be
148 static unsigned int *skipped_break_addr, displaced_after_inst;
149 static sigset_t orig_sigmask;
152 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
154 /* not sure how we ensure that we get the breakpoint reinstalled
155 * after doing this -dan */
156 unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context));
158 orig_sigmask = *os_context_sigmask_addr(context);
159 sigaddset_blockable(os_context_sigmask_addr(context));
162 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
163 skipped_break_addr = pc;
165 /* FIXME: we should apparently be installing the after-breakpoint
166 * here, but would need to find the next instruction address for
167 * it first. alpha-arch.c shows how to do it. --NS 2007-04-02 */
170 #ifdef LISP_FEATURE_GENCGC
172 * Return non-zero if the current instruction is an allocation trap
175 allocation_trap_p(os_context_t * context)
187 * First, the instruction has to be a TWLGE temp, NL3, which has the
189 * | 6| 5| 5 | 5 | 10|1| width
190 * |31|5 |dst|src| 4|0| field
192 pc = (unsigned int *) (*os_context_pc_addr(context));
196 fprintf(stderr, "allocation_trap_p at %p: inst = 0x%08x\n", pc, inst);
200 src = (inst >> 11) & 0x1f;
201 dst = (inst >> 16) & 0x1f;
202 if ((opcode == 31) && (src == reg_NL3) && (5 == ((inst >> 21) & 0x1f))
203 && (4 == ((inst >> 1) & 0x3ff))) {
205 * We got the instruction. Now, look back to make sure it was
206 * proceeded by what we expected. 2 instructions back should be
207 * an ADD or ADDI instruction.
209 unsigned int add_inst;
213 fprintf(stderr, " add inst at %p: inst = 0x%08x\n",
216 opcode = add_inst >> 26;
217 if ((opcode == 31) && (266 == ((add_inst >> 1) & 0x1ff))) {
219 } else if ((opcode == 14)) {
223 "Whoa! Got allocation trap but could not find ADD or ADDI instruction: 0x%08x in the proper place\n",
230 extern struct alloc_region boxed_region;
233 handle_allocation_trap(os_context_t * context)
237 unsigned int target, target_ptr, end_addr;
240 boolean were_in_lisp;
247 fprintf(stderr, "In handle_allocation_trap\n");
250 /* I don't think it's possible for us NOT to be in lisp when we get
251 * here. Remove this later? */
252 were_in_lisp = !foreign_function_call_active;
255 fake_foreign_function_call(context);
257 fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
261 * Look at current instruction: TWNE temp, NL3. We're here because
262 * temp > NL3 and temp is the end of the allocation, and NL3 is
263 * current-region-end-addr.
265 * We need to adjust temp and alloc-tn.
268 pc = (unsigned int *) (*os_context_pc_addr(context));
270 end_addr = (inst >> 11) & 0x1f;
271 target = (inst >> 16) & 0x1f;
273 target_ptr = *os_context_register_addr(context, target);
276 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
277 fprintf(stderr, "boxed_region.free_pointer: %p\n", boxed_region.free_pointer);
278 fprintf(stderr, "boxed_region.end_addr: %p\n", boxed_region.end_addr);
279 fprintf(stderr, "target reg: %d, end_addr reg: %d\n", target, end_addr);
280 fprintf(stderr, "target: %x\n", *os_context_register_addr(context, target));
281 fprintf(stderr, "end_addr: %x\n", *os_context_register_addr(context, end_addr));
285 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
286 fprintf(stderr, " trap inst = 0x%08x\n", inst);
287 fprintf(stderr, " target reg = %s\n", lisp_register_names[target]);
291 * Go back and look at the add/addi instruction. The second src arg
292 * is the size of the allocation. Get it and call alloc to allocate
298 fprintf(stderr, " add inst = 0x%08x, opcode = %d\n", inst, opcode);
302 * ADDI temp-tn, alloc-tn, size
306 size = (inst & 0xffff);
307 } else if (opcode == 31) {
309 * ADD temp-tn, alloc-tn, size-tn
315 reg = (inst >> 11) & 0x1f;
317 fprintf(stderr, " add, reg = %s\n", lisp_register_names[reg]);
319 size = *os_context_register_addr(context, reg);
324 fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
327 #if INLINE_ALLOC_DEBUG
328 if ((((unsigned long)boxed_region.end_addr + size) / PAGE_SIZE) ==
329 (((unsigned long)boxed_region.end_addr) / PAGE_SIZE)) {
330 fprintf(stderr,"*** possibly bogus trap allocation of %d bytes at %p\n",
332 fprintf(stderr, " dynamic_space_free_pointer: %p, boxed_region.end_addr %p\n",
333 dynamic_space_free_pointer, boxed_region.end_addr);
338 fprintf(stderr, "Ready to alloc\n");
339 fprintf(stderr, "free_pointer = 0x%08x\n",
340 dynamic_space_free_pointer);
344 * alloc-tn was incremented by size. Need to decrement it by size
345 * to restore its original value. This is not true on GENCGC
346 * anymore. d_s_f_p and reg_alloc get out of sync, but the p_a
347 * bits stay intact and we set it to the proper value when it
348 * needs to be. Keep this comment here for the moment in case
349 * somebody tries to figure out what happened here.
351 /* dynamic_space_free_pointer =
352 (lispobj *) ((long) dynamic_space_free_pointer - size);
355 fprintf(stderr, "free_pointer = 0x%08x new\n",
356 dynamic_space_free_pointer);
359 memory = (char *) alloc(size);
362 fprintf(stderr, "alloc returned %p\n", memory);
363 fprintf(stderr, "free_pointer = 0x%08x\n",
364 dynamic_space_free_pointer);
368 * The allocation macro wants the result to point to the end of the
374 fprintf(stderr, "object end at %p\n", memory);
377 *os_context_register_addr(context, target) = (unsigned long) memory;
378 *os_context_register_addr(context, reg_ALLOC) =
379 (unsigned long) dynamic_space_free_pointer
380 | (*os_context_register_addr(context, reg_ALLOC)
384 undo_fake_foreign_function_call(context);
392 arch_handle_breakpoint(os_context_t *context)
394 handle_breakpoint(context);
398 arch_handle_fun_end_breakpoint(os_context_t *context)
400 *os_context_pc_addr(context)
401 =(int)handle_fun_end_breakpoint(context);
405 arch_handle_after_breakpoint(os_context_t *context)
407 *skipped_break_addr = trap_Breakpoint;
408 skipped_break_addr = NULL;
409 *(unsigned int *)*os_context_pc_addr(context)
410 = displaced_after_inst;
411 *os_context_sigmask_addr(context)= orig_sigmask;
412 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context),
413 sizeof(unsigned int));
417 arch_handle_single_step_trap(os_context_t *context, int trap)
419 unsigned int code = *((u32 *)(*os_context_pc_addr(context)));
420 int register_offset = code >> 5 & 0x1f;
421 handle_single_step_trap(context, trap, register_offset);
422 arch_skip_instruction(context);
426 sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
430 code=*((u32 *)(*os_context_pc_addr(context)));
431 if (code == ((3 << 26) | (0x18 << 21) | (reg_NL3 << 16))) {
432 arch_clear_pseudo_atomic_interrupted(context);
433 arch_skip_instruction(context);
434 /* interrupt or GC was requested in PA; now we're done with the
435 PA section we may as well get around to it */
436 interrupt_handle_pending(context);
440 #ifdef LISP_FEATURE_GENCGC
441 /* Is this an allocation trap? */
442 if (allocation_trap_p(context)) {
443 handle_allocation_trap(context);
444 arch_skip_instruction(context);
449 if ((code >> 16) == ((3 << 10) | (6 << 5))) {
450 /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */
451 int trap = code & 0x1f;
452 handle_trap(context,trap);
455 if (((code >> 26) == 3) && (((code >> 21) & 31) == 24)) {
456 interrupt_internal_error(context, 0);
460 interrupt_handle_now(signal, (siginfo_t *)code, context);
464 void arch_install_interrupt_handlers()
466 undoably_install_low_level_interrupt_handler(SIGILL, sigtrap_handler);
467 undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler);
471 ppc_flush_icache(os_vm_address_t address, os_vm_size_t length)
473 os_vm_address_t end = (os_vm_address_t) ((int)(address+length+(32-1)) &~(32-1));
474 extern void ppc_flush_cache_line(os_vm_address_t);
476 while (address < end) {
477 ppc_flush_cache_line(address);
482 #ifdef LISP_FEATURE_LINKAGE_TABLE
484 /* Linkage tables for PowerPC
486 * Linkage entry size is 16, because we need at least 4 instructions to
491 * Define the registers to use in the linkage jump table. Can be the
492 * same. Some care must be exercised when choosing these. It has to be
493 * a register that is not otherwise being used. reg_NFP is a good
494 * choice. call_into_c trashes reg_NFP without preserving it, so we can
495 * trash it in the linkage jump table.
497 #define LINKAGE_TEMP_REG reg_NFP
498 #define LINKAGE_ADDR_REG reg_NFP
501 * Insert the necessary jump instructions at the given address.
504 arch_write_linkage_table_jmp(void* reloc_addr, void *target_addr)
507 * Make JMP to function entry.
509 * The instruction sequence is:
511 * addis 13, 0, (hi part of addr)
512 * ori 13, 13, (low part of addr)
518 unsigned long hi; /* Top 16 bits of address */
519 unsigned long lo; /* Low 16 bits of address */
522 inst_ptr = (int*) reloc_addr;
525 * Split the target address into hi and lo parts for the sethi
526 * instruction. hi is the top 22 bits. lo is the low 10 bits.
528 hi = (unsigned long) target_addr;
533 * addis 13, 0, (hi part)
536 inst = (15 << 26) | (LINKAGE_TEMP_REG << 21) | (0 << 16) | hi;
540 * ori 13, 13, (lo part)
543 inst = (24 << 26) | (LINKAGE_TEMP_REG << 21) | (LINKAGE_TEMP_REG << 16) | lo;
550 inst = (31 << 26) | (LINKAGE_TEMP_REG << 21) | (9 << 16) | (467 << 1);
557 inst = (19 << 26) | (20 << 21) | (528 << 1);
563 os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - (char*) reloc_addr);
567 arch_write_linkage_table_ref(void * reloc_addr, void *target_addr)
569 *(unsigned long *)reloc_addr = (unsigned long)target_addr;