10 #include "interrupt.h"
13 #if defined(LISP_FEATURE_GENCGC)
14 #include "gencgc-alloc-region.h"
17 /* The header files may not define PT_DAR/PT_DSISR. This definition
18 is correct for all versions of ppc linux >= 2.0.30
20 As of DR2.1u4, MkLinux doesn't pass these registers to signal
21 handlers correctly; a patch is necessary in order to (partially)
24 Even with the patch, the DSISR may not have its 'write' bit set
25 correctly (it tends not to be set if the fault was caused by
26 something other than a protection violation.)
30 #if defined (LISP_FEATURE_DARWIN) || defined(LISP_FEATURE_LINUX)
44 arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
46 unsigned long pc = (unsigned long)(*os_context_pc_addr(context));
49 #if defined(LISP_FEATURE_NETBSD)
50 addr = (os_vm_address_t) (code->si_addr);
52 addr = (os_vm_address_t) (*os_context_register_addr(context,PT_DAR));
59 arch_skip_instruction(os_context_t *context)
62 pcptr = (char**) os_context_pc_addr(context);
67 arch_internal_error_arguments(os_context_t *context)
69 return (unsigned char *)(*os_context_pc_addr(context)+4);
74 arch_pseudo_atomic_atomic(os_context_t *context)
76 return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
80 arch_set_pseudo_atomic_interrupted(os_context_t *context)
82 *os_context_register_addr(context,reg_ALLOC) |= 1;
86 arch_clear_pseudo_atomic_interrupted(os_context_t *context)
88 *os_context_register_addr(context,reg_ALLOC) &= ~1;
92 arch_install_breakpoint(void *pc)
94 unsigned int *ptr = (unsigned int *)pc;
95 unsigned int result = *ptr;
96 *ptr = (3<<26) | (5 << 21) | trap_Breakpoint;
97 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
102 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
104 *(unsigned int *)pc = orig_inst;
105 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
109 * Perform the instruction that we overwrote with a breakpoint. As we
110 * don't have a single-step facility, this means we have to:
111 * - put the instruction back
112 * - put a second breakpoint at the following instruction,
113 * set after_breakpoint and continue execution.
115 * When the second breakpoint is hit (very shortly thereafter, we hope)
116 * sigtrap_handler gets called again, but follows the AfterBreakpoint
118 * - puts a bpt back in the first breakpoint place (running across a
119 * breakpoint shouldn't cause it to be uninstalled)
120 * - replaces the second bpt with the instruction it was meant to be
125 static unsigned int *skipped_break_addr, displaced_after_inst;
126 static sigset_t orig_sigmask;
129 arch_do_displaced_inst(os_context_t *context,unsigned int orig_inst)
131 /* not sure how we ensure that we get the breakpoint reinstalled
132 * after doing this -dan */
133 unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context));
135 orig_sigmask = *os_context_sigmask_addr(context);
136 sigaddset_blockable(os_context_sigmask_addr(context));
139 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
140 skipped_break_addr = pc;
143 #ifdef LISP_FEATURE_GENCGC
145 * Return non-zero if the current instruction is an allocation trap
148 allocation_trap_p(os_context_t * context)
160 * First, the instruction has to be a TWLGE temp, NL3, which has the
162 * | 6| 5| 5 | 5 | 10|1| width
163 * |31|5 |dst|src| 4|0| field
165 pc = (unsigned int *) (*os_context_pc_addr(context));
169 fprintf(stderr, "allocation_trap_p at %p: inst = 0x%08x\n", pc, inst);
173 src = (inst >> 11) & 0x1f;
174 dst = (inst >> 16) & 0x1f;
175 if ((opcode == 31) && (src == reg_NL3) && (5 == ((inst >> 21) & 0x1f))
176 && (4 == ((inst >> 1) & 0x3ff))) {
178 * We got the instruction. Now, look back to make sure it was
179 * proceeded by what we expected. 2 instructions back should be
180 * an ADD or ADDI instruction.
182 unsigned int add_inst;
186 fprintf(stderr, " add inst at %p: inst = 0x%08x\n",
189 opcode = add_inst >> 26;
190 if ((opcode == 31) && (266 == ((add_inst >> 1) & 0x1ff))) {
192 } else if ((opcode == 14)) {
196 "Whoa! Got allocation trap but could not find ADD or ADDI instruction: 0x%08x in the proper place\n",
203 extern struct alloc_region boxed_region;
206 handle_allocation_trap(os_context_t * context)
210 unsigned int or_inst;
211 unsigned int target, target_ptr, end_addr;
215 boolean were_in_lisp;
223 fprintf(stderr, "In handle_allocation_trap\n");
227 * I don't think it's possible for us NOT to be in lisp when we get
228 * here. Remove this later?
230 were_in_lisp = !foreign_function_call_active;
233 fake_foreign_function_call(context);
235 fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
239 * Look at current instruction: TWNE temp, NL3. We're here because
240 * temp > NL3 and temp is the end of the allocation, and NL3 is
241 * current-region-end-addr.
243 * We need to adjust temp and alloc-tn.
246 pc = (unsigned int *) (*os_context_pc_addr(context));
248 end_addr = (inst >> 11) & 0x1f;
249 target = (inst >> 16) & 0x1f;
251 target_ptr = *os_context_register_addr(context, target);
254 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
255 fprintf(stderr, "boxed_region.free_pointer: %p\n", boxed_region.free_pointer);
256 fprintf(stderr, "boxed_region.end_addr: %p\n", boxed_region.end_addr);
257 fprintf(stderr, "target reg: %d, end_addr reg: %d\n", target, end_addr);
258 fprintf(stderr, "target: %x\n", *os_context_register_addr(context, target));
259 fprintf(stderr, "end_addr: %x\n", *os_context_register_addr(context, end_addr));
263 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
264 fprintf(stderr, " trap inst = 0x%08x\n", inst);
265 fprintf(stderr, " target reg = %s\n", lisp_register_names[target]);
269 * Go back and look at the add/addi instruction. The second src arg
270 * is the size of the allocation. Get it and call alloc to allocate
276 fprintf(stderr, " add inst = 0x%08x, opcode = %d\n", inst, opcode);
280 * ADDI temp-tn, alloc-tn, size
284 size = (inst & 0xffff);
285 } else if (opcode == 31) {
287 * ADD temp-tn, alloc-tn, size-tn
293 reg = (inst >> 11) & 0x1f;
295 fprintf(stderr, " add, reg = %s\n", lisp_register_names[reg]);
297 size = *os_context_register_addr(context, reg);
302 fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
305 #if INLINE_ALLOC_DEBUG
306 if ((((unsigned long)boxed_region.end_addr + size) / PAGE_SIZE) ==
307 (((unsigned long)boxed_region.end_addr) / PAGE_SIZE)) {
308 fprintf(stderr,"*** possibly bogus trap allocation of %d bytes at %p\n",
310 fprintf(stderr, " dynamic_space_free_pointer: %p, boxed_region.end_addr %p\n",
311 dynamic_space_free_pointer, boxed_region.end_addr);
316 fprintf(stderr, "Ready to alloc\n");
317 fprintf(stderr, "free_pointer = 0x%08x\n",
318 dynamic_space_free_pointer);
322 * alloc-tn was incremented by size. Need to decrement it by size
323 * to restore its original value. This is not true on GENCGC
324 * anymore. d_s_f_p and reg_alloc get out of sync, but the p_a
325 * bits stay intact and we set it to the proper value when it
326 * needs to be. Keep this comment here for the moment in case
327 * somebody tries to figure out what happened here.
329 /* dynamic_space_free_pointer =
330 (lispobj *) ((long) dynamic_space_free_pointer - size);
333 fprintf(stderr, "free_pointer = 0x%08x new\n",
334 dynamic_space_free_pointer);
337 memory = (char *) alloc(size);
340 fprintf(stderr, "alloc returned %p\n", memory);
341 fprintf(stderr, "free_pointer = 0x%08x\n",
342 dynamic_space_free_pointer);
346 * The allocation macro wants the result to point to the end of the
352 fprintf(stderr, "object end at %p\n", memory);
355 *os_context_register_addr(context, target) = (unsigned long) memory;
356 *os_context_register_addr(context, reg_ALLOC) =
357 (unsigned long) dynamic_space_free_pointer
358 | (*os_context_register_addr(context, reg_ALLOC)
362 undo_fake_foreign_function_call(context);
371 sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
375 #ifdef LISP_FEATURE_LINUX
376 os_restore_fp_control(context);
378 code=*((u32 *)(*os_context_pc_addr(context)));
379 if (code == ((3 << 26) | (0x18 << 21) | (reg_NL3 << 16))) {
380 arch_clear_pseudo_atomic_interrupted(context);
381 arch_skip_instruction(context);
382 /* interrupt or GC was requested in PA; now we're done with the
383 PA section we may as well get around to it */
384 interrupt_handle_pending(context);
388 #ifdef LISP_FEATURE_GENCGC
389 /* Is this an allocation trap? */
390 if (allocation_trap_p(context)) {
391 handle_allocation_trap(context);
392 arch_skip_instruction(context);
393 #ifdef LISP_FEATURE_DARWIN
394 DARWIN_FIX_CONTEXT(context);
400 if ((code >> 16) == ((3 << 10) | (6 << 5))) {
401 /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */
402 int trap = code & 0x1f;
406 fake_foreign_function_call(context);
407 lose("%%primitive halt called; the party is over.\n");
411 interrupt_internal_error(signal, code, context, trap == trap_Cerror);
414 case trap_PendingInterrupt:
415 /* This is supposed run after WITHOUT-INTERRUPTS if there
416 * were pending signals. */
417 arch_skip_instruction(context);
418 interrupt_handle_pending(context);
421 case trap_Breakpoint:
422 handle_breakpoint(signal, code, context);
425 case trap_FunEndBreakpoint:
426 *os_context_pc_addr(context)
427 =(int)handle_fun_end_breakpoint(signal, code, context);
430 case trap_AfterBreakpoint:
431 *skipped_break_addr = trap_Breakpoint;
432 skipped_break_addr = NULL;
433 *(unsigned int *)*os_context_pc_addr(context)
434 = displaced_after_inst;
435 *os_context_sigmask_addr(context)= orig_sigmask;
437 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context),
438 sizeof(unsigned int));
441 case trap_SingleStepAround:
442 case trap_SingleStepBefore:
444 int register_offset = code >> 5 & 0x1f;
446 handle_single_step_trap(context, trap, register_offset);
448 arch_skip_instruction(context);
452 interrupt_handle_now(signal, code, context);
455 #ifdef LISP_FEATURE_DARWIN
456 DARWIN_FIX_CONTEXT(context);
460 if (((code >> 26) == 3) && (((code >> 21) & 31) == 24)) {
461 interrupt_internal_error(signal, code, context, 0);
462 #ifdef LISP_FEATURE_DARWIN
463 DARWIN_FIX_CONTEXT(context);
468 interrupt_handle_now(signal, code, context);
469 #ifdef LISP_FEATURE_DARWIN
470 /* Work around G5 bug */
471 DARWIN_FIX_CONTEXT(context);
476 void arch_install_interrupt_handlers()
478 undoably_install_low_level_interrupt_handler(SIGILL,sigtrap_handler);
479 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
483 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
485 lispobj funcall0(lispobj function)
487 lispobj *args = current_control_stack_pointer;
489 return call_into_lisp(function, args, 0);
492 lispobj funcall1(lispobj function, lispobj arg0)
494 lispobj *args = current_control_stack_pointer;
496 current_control_stack_pointer += 1;
499 return call_into_lisp(function, args, 1);
502 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
504 lispobj *args = current_control_stack_pointer;
506 current_control_stack_pointer += 2;
510 return call_into_lisp(function, args, 2);
513 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
515 lispobj *args = current_control_stack_pointer;
517 current_control_stack_pointer += 3;
522 return call_into_lisp(function, args, 3);
526 ppc_flush_icache(os_vm_address_t address, os_vm_size_t length)
528 os_vm_address_t end = (os_vm_address_t) ((int)(address+length+(32-1)) &~(32-1));
529 extern void ppc_flush_cache_line(os_vm_address_t);
531 while (address < end) {
532 ppc_flush_cache_line(address);
537 #ifdef LISP_FEATURE_LINKAGE_TABLE
539 /* Linkage tables for PowerPC
541 * Linkage entry size is 16, because we need at least 4 instructions to
546 * Define the registers to use in the linkage jump table. Can be the
547 * same. Some care must be exercised when choosing these. It has to be
548 * a register that is not otherwise being used. reg_NFP is a good
549 * choice. call_into_c trashes reg_NFP without preserving it, so we can
550 * trash it in the linkage jump table.
552 #define LINKAGE_TEMP_REG reg_NFP
553 #define LINKAGE_ADDR_REG reg_NFP
556 * Insert the necessary jump instructions at the given address.
559 arch_write_linkage_table_jmp(void* reloc_addr, void *target_addr)
562 * Make JMP to function entry.
564 * The instruction sequence is:
566 * addis 13, 0, (hi part of addr)
567 * ori 13, 13, (low part of addr)
573 unsigned long hi; /* Top 16 bits of address */
574 unsigned long lo; /* Low 16 bits of address */
577 inst_ptr = (int*) reloc_addr;
580 * Split the target address into hi and lo parts for the sethi
581 * instruction. hi is the top 22 bits. lo is the low 10 bits.
583 hi = (unsigned long) target_addr;
588 * addis 13, 0, (hi part)
591 inst = (15 << 26) | (LINKAGE_TEMP_REG << 21) | (0 << 16) | hi;
595 * ori 13, 13, (lo part)
598 inst = (24 << 26) | (LINKAGE_TEMP_REG << 21) | (LINKAGE_TEMP_REG << 16) | lo;
605 inst = (31 << 26) | (LINKAGE_TEMP_REG << 21) | (9 << 16) | (467 << 1);
612 inst = (19 << 26) | (20 << 21) | (528 << 1);
618 os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - (char*) reloc_addr);
622 arch_write_linkage_table_ref(void * reloc_addr, void *target_addr)
624 *(unsigned long *)reloc_addr = (unsigned long)target_addr;