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"
25 #if defined(LISP_FEATURE_GENCGC)
26 #include "gencgc-alloc-region.h"
29 /* The header files may not define PT_DAR/PT_DSISR. This definition
30 is correct for all versions of ppc linux >= 2.0.30
32 As of DR2.1u4, MkLinux doesn't pass these registers to signal
33 handlers correctly; a patch is necessary in order to (partially)
36 Even with the patch, the DSISR may not have its 'write' bit set
37 correctly (it tends not to be set if the fault was caused by
38 something other than a protection violation.)
42 #if defined (LISP_FEATURE_DARWIN) || defined(LISP_FEATURE_LINUX)
56 arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
60 #if defined(LISP_FEATURE_NETBSD)
61 addr = (os_vm_address_t) (code->si_addr);
63 addr = (os_vm_address_t) (*os_context_register_addr(context,PT_DAR));
70 arch_skip_instruction(os_context_t *context)
73 pcptr = (char**) os_context_pc_addr(context);
78 arch_internal_error_arguments(os_context_t *context)
80 return (unsigned char *)(*os_context_pc_addr(context)+4);
85 arch_pseudo_atomic_atomic(os_context_t *context)
87 return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
91 arch_set_pseudo_atomic_interrupted(os_context_t *context)
93 *os_context_register_addr(context,reg_ALLOC) |= 1;
97 arch_clear_pseudo_atomic_interrupted(os_context_t *context)
99 *os_context_register_addr(context,reg_ALLOC) &= ~1;
103 arch_install_breakpoint(void *pc)
105 unsigned int *ptr = (unsigned int *)pc;
106 unsigned int result = *ptr;
107 *ptr = (3<<26) | (5 << 21) | trap_Breakpoint;
108 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
113 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
115 *(unsigned int *)pc = orig_inst;
116 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
120 * Perform the instruction that we overwrote with a breakpoint. As we
121 * don't have a single-step facility, this means we have to:
122 * - put the instruction back
123 * - put a second breakpoint at the following instruction,
124 * set after_breakpoint and continue execution.
126 * When the second breakpoint is hit (very shortly thereafter, we hope)
127 * sigtrap_handler gets called again, but follows the AfterBreakpoint
129 * - puts a bpt back in the first breakpoint place (running across a
130 * breakpoint shouldn't cause it to be uninstalled)
131 * - replaces the second bpt with the instruction it was meant to be
136 static unsigned int *skipped_break_addr, displaced_after_inst;
137 static sigset_t orig_sigmask;
140 arch_do_displaced_inst(os_context_t *context,unsigned int orig_inst)
142 /* not sure how we ensure that we get the breakpoint reinstalled
143 * after doing this -dan */
144 unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context));
146 orig_sigmask = *os_context_sigmask_addr(context);
147 sigaddset_blockable(os_context_sigmask_addr(context));
150 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
151 skipped_break_addr = pc;
154 #ifdef LISP_FEATURE_GENCGC
156 * Return non-zero if the current instruction is an allocation trap
159 allocation_trap_p(os_context_t * context)
171 * First, the instruction has to be a TWLGE temp, NL3, which has the
173 * | 6| 5| 5 | 5 | 10|1| width
174 * |31|5 |dst|src| 4|0| field
176 pc = (unsigned int *) (*os_context_pc_addr(context));
180 fprintf(stderr, "allocation_trap_p at %p: inst = 0x%08x\n", pc, inst);
184 src = (inst >> 11) & 0x1f;
185 dst = (inst >> 16) & 0x1f;
186 if ((opcode == 31) && (src == reg_NL3) && (5 == ((inst >> 21) & 0x1f))
187 && (4 == ((inst >> 1) & 0x3ff))) {
189 * We got the instruction. Now, look back to make sure it was
190 * proceeded by what we expected. 2 instructions back should be
191 * an ADD or ADDI instruction.
193 unsigned int add_inst;
197 fprintf(stderr, " add inst at %p: inst = 0x%08x\n",
200 opcode = add_inst >> 26;
201 if ((opcode == 31) && (266 == ((add_inst >> 1) & 0x1ff))) {
203 } else if ((opcode == 14)) {
207 "Whoa! Got allocation trap but could not find ADD or ADDI instruction: 0x%08x in the proper place\n",
214 extern struct alloc_region boxed_region;
217 handle_allocation_trap(os_context_t * context)
221 unsigned int target, target_ptr, end_addr;
224 boolean were_in_lisp;
231 fprintf(stderr, "In handle_allocation_trap\n");
235 * I don't think it's possible for us NOT to be in lisp when we get
236 * here. Remove this later?
238 were_in_lisp = !foreign_function_call_active;
241 fake_foreign_function_call(context);
243 fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
247 * Look at current instruction: TWNE temp, NL3. We're here because
248 * temp > NL3 and temp is the end of the allocation, and NL3 is
249 * current-region-end-addr.
251 * We need to adjust temp and alloc-tn.
254 pc = (unsigned int *) (*os_context_pc_addr(context));
256 end_addr = (inst >> 11) & 0x1f;
257 target = (inst >> 16) & 0x1f;
259 target_ptr = *os_context_register_addr(context, target);
262 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
263 fprintf(stderr, "boxed_region.free_pointer: %p\n", boxed_region.free_pointer);
264 fprintf(stderr, "boxed_region.end_addr: %p\n", boxed_region.end_addr);
265 fprintf(stderr, "target reg: %d, end_addr reg: %d\n", target, end_addr);
266 fprintf(stderr, "target: %x\n", *os_context_register_addr(context, target));
267 fprintf(stderr, "end_addr: %x\n", *os_context_register_addr(context, end_addr));
271 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
272 fprintf(stderr, " trap inst = 0x%08x\n", inst);
273 fprintf(stderr, " target reg = %s\n", lisp_register_names[target]);
277 * Go back and look at the add/addi instruction. The second src arg
278 * is the size of the allocation. Get it and call alloc to allocate
284 fprintf(stderr, " add inst = 0x%08x, opcode = %d\n", inst, opcode);
288 * ADDI temp-tn, alloc-tn, size
292 size = (inst & 0xffff);
293 } else if (opcode == 31) {
295 * ADD temp-tn, alloc-tn, size-tn
301 reg = (inst >> 11) & 0x1f;
303 fprintf(stderr, " add, reg = %s\n", lisp_register_names[reg]);
305 size = *os_context_register_addr(context, reg);
310 fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
313 #if INLINE_ALLOC_DEBUG
314 if ((((unsigned long)boxed_region.end_addr + size) / PAGE_SIZE) ==
315 (((unsigned long)boxed_region.end_addr) / PAGE_SIZE)) {
316 fprintf(stderr,"*** possibly bogus trap allocation of %d bytes at %p\n",
318 fprintf(stderr, " dynamic_space_free_pointer: %p, boxed_region.end_addr %p\n",
319 dynamic_space_free_pointer, boxed_region.end_addr);
324 fprintf(stderr, "Ready to alloc\n");
325 fprintf(stderr, "free_pointer = 0x%08x\n",
326 dynamic_space_free_pointer);
330 * alloc-tn was incremented by size. Need to decrement it by size
331 * to restore its original value. This is not true on GENCGC
332 * anymore. d_s_f_p and reg_alloc get out of sync, but the p_a
333 * bits stay intact and we set it to the proper value when it
334 * needs to be. Keep this comment here for the moment in case
335 * somebody tries to figure out what happened here.
337 /* dynamic_space_free_pointer =
338 (lispobj *) ((long) dynamic_space_free_pointer - size);
341 fprintf(stderr, "free_pointer = 0x%08x new\n",
342 dynamic_space_free_pointer);
345 memory = (char *) alloc(size);
348 fprintf(stderr, "alloc returned %p\n", memory);
349 fprintf(stderr, "free_pointer = 0x%08x\n",
350 dynamic_space_free_pointer);
354 * The allocation macro wants the result to point to the end of the
360 fprintf(stderr, "object end at %p\n", memory);
363 *os_context_register_addr(context, target) = (unsigned long) memory;
364 *os_context_register_addr(context, reg_ALLOC) =
365 (unsigned long) dynamic_space_free_pointer
366 | (*os_context_register_addr(context, reg_ALLOC)
370 undo_fake_foreign_function_call(context);
378 arch_handle_breakpoint(os_context_t *context)
380 handle_breakpoint(context);
384 arch_handle_fun_end_breakpoint(os_context_t *context)
386 *os_context_pc_addr(context)
387 =(int)handle_fun_end_breakpoint(context);
390 /* FIXME: AFTER-BREAKPOINT-TRAP is defined for PPC, but never
391 * emitted as far as I can see. Should it be emitted, do removed
394 arch_handle_after_breakpoint(os_context_t *context)
396 *skipped_break_addr = trap_Breakpoint;
397 skipped_break_addr = NULL;
398 *(unsigned int *)*os_context_pc_addr(context)
399 = displaced_after_inst;
400 *os_context_sigmask_addr(context)= orig_sigmask;
401 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context),
402 sizeof(unsigned int));
406 arch_handle_single_step_trap(os_context_t *context, int trap)
408 unsigned int code = *((u32 *)(*os_context_pc_addr(context)));
409 int register_offset = code >> 5 & 0x1f;
410 handle_single_step_trap(context, trap, register_offset);
411 arch_skip_instruction(context);
415 sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
419 #ifdef LISP_FEATURE_LINUX
420 os_restore_fp_control(context);
422 code=*((u32 *)(*os_context_pc_addr(context)));
423 if (code == ((3 << 26) | (0x18 << 21) | (reg_NL3 << 16))) {
424 arch_clear_pseudo_atomic_interrupted(context);
425 arch_skip_instruction(context);
426 /* interrupt or GC was requested in PA; now we're done with the
427 PA section we may as well get around to it */
428 interrupt_handle_pending(context);
432 #ifdef LISP_FEATURE_GENCGC
433 /* Is this an allocation trap? */
434 if (allocation_trap_p(context)) {
435 handle_allocation_trap(context);
436 arch_skip_instruction(context);
437 #ifdef LISP_FEATURE_DARWIN
438 DARWIN_FIX_CONTEXT(context);
444 if ((code >> 16) == ((3 << 10) | (6 << 5))) {
445 /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */
446 int trap = code & 0x1f;
448 if (!maybe_handle_trap(context,trap))
449 interrupt_handle_now(signal, siginfo, context);
451 #ifdef LISP_FEATURE_DARWIN
452 DARWIN_FIX_CONTEXT(context);
456 if (((code >> 26) == 3) && (((code >> 21) & 31) == 24)) {
457 interrupt_internal_error(context, 0);
458 #ifdef LISP_FEATURE_DARWIN
459 DARWIN_FIX_CONTEXT(context);
464 interrupt_handle_now(signal, code, context);
465 #ifdef LISP_FEATURE_DARWIN
466 /* Work around G5 bug */
467 DARWIN_FIX_CONTEXT(context);
472 void arch_install_interrupt_handlers()
474 undoably_install_low_level_interrupt_handler(SIGILL,sigtrap_handler);
475 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
479 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
481 lispobj funcall0(lispobj function)
483 lispobj *args = current_control_stack_pointer;
485 return call_into_lisp(function, args, 0);
488 lispobj funcall1(lispobj function, lispobj arg0)
490 lispobj *args = current_control_stack_pointer;
492 current_control_stack_pointer += 1;
495 return call_into_lisp(function, args, 1);
498 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
500 lispobj *args = current_control_stack_pointer;
502 current_control_stack_pointer += 2;
506 return call_into_lisp(function, args, 2);
509 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
511 lispobj *args = current_control_stack_pointer;
513 current_control_stack_pointer += 3;
518 return call_into_lisp(function, args, 3);
522 ppc_flush_icache(os_vm_address_t address, os_vm_size_t length)
524 os_vm_address_t end = (os_vm_address_t) ((int)(address+length+(32-1)) &~(32-1));
525 extern void ppc_flush_cache_line(os_vm_address_t);
527 while (address < end) {
528 ppc_flush_cache_line(address);
533 #ifdef LISP_FEATURE_LINKAGE_TABLE
535 /* Linkage tables for PowerPC
537 * Linkage entry size is 16, because we need at least 4 instructions to
542 * Define the registers to use in the linkage jump table. Can be the
543 * same. Some care must be exercised when choosing these. It has to be
544 * a register that is not otherwise being used. reg_NFP is a good
545 * choice. call_into_c trashes reg_NFP without preserving it, so we can
546 * trash it in the linkage jump table.
548 #define LINKAGE_TEMP_REG reg_NFP
549 #define LINKAGE_ADDR_REG reg_NFP
552 * Insert the necessary jump instructions at the given address.
555 arch_write_linkage_table_jmp(void* reloc_addr, void *target_addr)
558 * Make JMP to function entry.
560 * The instruction sequence is:
562 * addis 13, 0, (hi part of addr)
563 * ori 13, 13, (low part of addr)
569 unsigned long hi; /* Top 16 bits of address */
570 unsigned long lo; /* Low 16 bits of address */
573 inst_ptr = (int*) reloc_addr;
576 * Split the target address into hi and lo parts for the sethi
577 * instruction. hi is the top 22 bits. lo is the low 10 bits.
579 hi = (unsigned long) target_addr;
584 * addis 13, 0, (hi part)
587 inst = (15 << 26) | (LINKAGE_TEMP_REG << 21) | (0 << 16) | hi;
591 * ori 13, 13, (lo part)
594 inst = (24 << 26) | (LINKAGE_TEMP_REG << 21) | (LINKAGE_TEMP_REG << 16) | lo;
601 inst = (31 << 26) | (LINKAGE_TEMP_REG << 21) | (9 << 16) | (467 << 1);
608 inst = (19 << 26) | (20 << 21) | (528 << 1);
614 os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - (char*) reloc_addr);
618 arch_write_linkage_table_ref(void * reloc_addr, void *target_addr)
620 *(unsigned long *)reloc_addr = (unsigned long)target_addr;