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.)
42 arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
44 unsigned long pc = (unsigned long)(*os_context_pc_addr(context));
47 addr = (os_vm_address_t) (*os_context_register_addr(context,PT_DAR));
53 arch_skip_instruction(os_context_t *context)
56 pcptr = (char**) os_context_pc_addr(context);
61 arch_internal_error_arguments(os_context_t *context)
63 return (unsigned char *)(*os_context_pc_addr(context)+4);
68 arch_pseudo_atomic_atomic(os_context_t *context)
70 return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
74 arch_set_pseudo_atomic_interrupted(os_context_t *context)
76 *os_context_register_addr(context,reg_ALLOC) |= 1;
80 arch_clear_pseudo_atomic_interrupted(os_context_t *context)
82 *os_context_register_addr(context,reg_ALLOC) &= ~1;
86 arch_install_breakpoint(void *pc)
88 unsigned int *ptr = (unsigned int *)pc;
89 unsigned int result = *ptr;
90 *ptr = (3<<26) | (5 << 21) | trap_Breakpoint;
91 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
96 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
98 *(unsigned int *)pc = orig_inst;
99 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
103 * Perform the instruction that we overwrote with a breakpoint. As we
104 * don't have a single-step facility, this means we have to:
105 * - put the instruction back
106 * - put a second breakpoint at the following instruction,
107 * set after_breakpoint and continue execution.
109 * When the second breakpoint is hit (very shortly thereafter, we hope)
110 * sigtrap_handler gets called again, but follows the AfterBreakpoint
112 * - puts a bpt back in the first breakpoint place (running across a
113 * breakpoint shouldn't cause it to be uninstalled)
114 * - replaces the second bpt with the instruction it was meant to be
119 static unsigned int *skipped_break_addr, displaced_after_inst;
120 static sigset_t orig_sigmask;
123 arch_do_displaced_inst(os_context_t *context,unsigned int orig_inst)
125 /* not sure how we ensure that we get the breakpoint reinstalled
126 * after doing this -dan */
127 unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context));
129 orig_sigmask = *os_context_sigmask_addr(context);
130 sigaddset_blockable(os_context_sigmask_addr(context));
133 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
134 skipped_break_addr = pc;
137 #ifdef LISP_FEATURE_GENCGC
139 * Return non-zero if the current instruction is an allocation trap
142 allocation_trap_p(os_context_t * context)
154 * First, the instruction has to be a TWLGE temp, NL3, which has the
156 * | 6| 5| 5 | 5 | 10|1| width
157 * |31|5 |dst|src| 4|0| field
159 pc = (unsigned int *) (*os_context_pc_addr(context));
163 fprintf(stderr, "allocation_trap_p at %p: inst = 0x%08x\n", pc, inst);
167 src = (inst >> 11) & 0x1f;
168 dst = (inst >> 16) & 0x1f;
169 if ((opcode == 31) && (src == reg_NL3) && (5 == ((inst >> 21) & 0x1f))
170 && (4 == ((inst >> 1) & 0x3ff))) {
172 * We got the instruction. Now, look back to make sure it was
173 * proceeded by what we expected. 2 instructions back should be
174 * an ADD or ADDI instruction.
176 unsigned int add_inst;
180 fprintf(stderr, " add inst at %p: inst = 0x%08x\n",
183 opcode = add_inst >> 26;
184 if ((opcode == 31) && (266 == ((add_inst >> 1) & 0x1ff))) {
186 } else if ((opcode == 14)) {
190 "Whoa! Got allocation trap but could not find ADD or ADDI instruction: 0x%08x in the proper place\n",
197 extern struct alloc_region boxed_region;
200 handle_allocation_trap(os_context_t * context)
204 unsigned int or_inst;
205 unsigned int target, target_ptr, end_addr;
209 boolean were_in_lisp;
217 fprintf(stderr, "In handle_allocation_trap\n");
221 * I don't think it's possible for us NOT to be in lisp when we get
222 * here. Remove this later?
224 were_in_lisp = !foreign_function_call_active;
227 fake_foreign_function_call(context);
229 fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
233 * Look at current instruction: TWNE temp, NL3. We're here because
234 * temp > NL3 and temp is the end of the allocation, and NL3 is
235 * current-region-end-addr.
237 * We need to adjust temp and alloc-tn.
240 pc = (unsigned int *) (*os_context_pc_addr(context));
242 end_addr = (inst >> 11) & 0x1f;
243 target = (inst >> 16) & 0x1f;
245 target_ptr = *os_context_register_addr(context, target);
248 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
249 fprintf(stderr, "boxed_region.free_pointer: %p\n", boxed_region.free_pointer);
250 fprintf(stderr, "boxed_region.end_addr: %p\n", boxed_region.end_addr);
251 fprintf(stderr, "target reg: %d, end_addr reg: %d\n", target, end_addr);
252 fprintf(stderr, "target: %x\n", *os_context_register_addr(context, target));
253 fprintf(stderr, "end_addr: %x\n", *os_context_register_addr(context, end_addr));
257 fprintf(stderr, "handle_allocation_trap at %p:\n", pc);
258 fprintf(stderr, " trap inst = 0x%08x\n", inst);
259 fprintf(stderr, " target reg = %s\n", lisp_register_names[target]);
263 * Go back and look at the add/addi instruction. The second src arg
264 * is the size of the allocation. Get it and call alloc to allocate
270 fprintf(stderr, " add inst = 0x%08x, opcode = %d\n", inst, opcode);
274 * ADDI temp-tn, alloc-tn, size
278 size = (inst & 0xffff);
279 } else if (opcode == 31) {
281 * ADD temp-tn, alloc-tn, size-tn
287 reg = (inst >> 11) & 0x1f;
289 fprintf(stderr, " add, reg = %s\n", lisp_register_names[reg]);
291 size = *os_context_register_addr(context, reg);
296 fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
299 #if INLINE_ALLOC_DEBUG
300 if ((((unsigned long)boxed_region.end_addr + size) / PAGE_SIZE) ==
301 (((unsigned long)boxed_region.end_addr) / PAGE_SIZE)) {
302 fprintf(stderr,"*** possibly bogus trap allocation of %d bytes at %p\n",
304 fprintf(stderr, " dynamic_space_free_pointer: %p, boxed_region.end_addr %p\n",
305 dynamic_space_free_pointer, boxed_region.end_addr);
310 fprintf(stderr, "Ready to alloc\n");
311 fprintf(stderr, "free_pointer = 0x%08x\n",
312 dynamic_space_free_pointer);
316 * alloc-tn was incremented by size. Need to decrement it by size
317 * to restore its original value. This is not true on GENCGC
318 * anymore. d_s_f_p and reg_alloc get out of sync, but the p_a
319 * bits stay intact and we set it to the proper value when it
320 * needs to be. Keep this comment here for the moment in case
321 * somebody tries to figure out what happened here.
323 /* dynamic_space_free_pointer =
324 (lispobj *) ((long) dynamic_space_free_pointer - size);
327 fprintf(stderr, "free_pointer = 0x%08x new\n",
328 dynamic_space_free_pointer);
331 memory = (char *) alloc(size);
334 fprintf(stderr, "alloc returned %p\n", memory);
335 fprintf(stderr, "free_pointer = 0x%08x\n",
336 dynamic_space_free_pointer);
340 * The allocation macro wants the result to point to the end of the
346 fprintf(stderr, "object end at %p\n", memory);
349 *os_context_register_addr(context, target) = (unsigned long) memory;
350 *os_context_register_addr(context, reg_ALLOC) =
351 (unsigned long) dynamic_space_free_pointer
352 | (*os_context_register_addr(context, reg_ALLOC)
356 undo_fake_foreign_function_call(context);
365 sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
369 #ifdef LISP_FEATURE_LINUX
370 os_restore_fp_control(context);
372 code=*((u32 *)(*os_context_pc_addr(context)));
373 if (code == ((3 << 26) | (0x18 << 21) | (reg_NL3 << 16))) {
374 arch_clear_pseudo_atomic_interrupted(context);
375 arch_skip_instruction(context);
376 /* interrupt or GC was requested in PA; now we're done with the
377 PA section we may as well get around to it */
378 interrupt_handle_pending(context);
382 #ifdef LISP_FEATURE_GENCGC
383 /* Is this an allocation trap? */
384 if (allocation_trap_p(context)) {
385 handle_allocation_trap(context);
386 arch_skip_instruction(context);
387 #ifdef LISP_FEATURE_DARWIN
388 DARWIN_FIX_CONTEXT(context);
394 if ((code >> 16) == ((3 << 10) | (6 << 5))) {
395 /* twllei reg_ZERO,N will always trap if reg_ZERO = 0 */
396 int trap = code & 0x1f;
400 fake_foreign_function_call(context);
401 lose("%%primitive halt called; the party is over.\n");
405 interrupt_internal_error(signal, code, context, trap == trap_Cerror);
408 case trap_PendingInterrupt:
409 /* This is supposed run after WITHOUT-INTERRUPTS if there
410 * were pending signals. */
411 arch_skip_instruction(context);
412 interrupt_handle_pending(context);
415 case trap_Breakpoint:
416 handle_breakpoint(signal, code, context);
419 case trap_FunEndBreakpoint:
420 *os_context_pc_addr(context)
421 =(int)handle_fun_end_breakpoint(signal, code, context);
424 case trap_AfterBreakpoint:
425 *skipped_break_addr = trap_Breakpoint;
426 skipped_break_addr = NULL;
427 *(unsigned int *)*os_context_pc_addr(context)
428 = displaced_after_inst;
429 *os_context_sigmask_addr(context)= orig_sigmask;
431 os_flush_icache((os_vm_address_t) *os_context_pc_addr(context),
432 sizeof(unsigned int));
436 interrupt_handle_now(signal, code, context);
439 #ifdef LISP_FEATURE_DARWIN
440 DARWIN_FIX_CONTEXT(context);
444 if (((code >> 26) == 3) && (((code >> 21) & 31) == 24)) {
445 interrupt_internal_error(signal, code, context, 0);
446 #ifdef LISP_FEATURE_DARWIN
447 DARWIN_FIX_CONTEXT(context);
452 interrupt_handle_now(signal, code, context);
453 #ifdef LISP_FEATURE_DARWIN
454 /* Work around G5 bug */
455 DARWIN_FIX_CONTEXT(context);
460 void arch_install_interrupt_handlers()
462 undoably_install_low_level_interrupt_handler(SIGILL,sigtrap_handler);
463 undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler);
467 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
469 lispobj funcall0(lispobj function)
471 lispobj *args = current_control_stack_pointer;
473 return call_into_lisp(function, args, 0);
476 lispobj funcall1(lispobj function, lispobj arg0)
478 lispobj *args = current_control_stack_pointer;
480 current_control_stack_pointer += 1;
483 return call_into_lisp(function, args, 1);
486 lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
488 lispobj *args = current_control_stack_pointer;
490 current_control_stack_pointer += 2;
494 return call_into_lisp(function, args, 2);
497 lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
499 lispobj *args = current_control_stack_pointer;
501 current_control_stack_pointer += 3;
506 return call_into_lisp(function, args, 3);
510 ppc_flush_icache(os_vm_address_t address, os_vm_size_t length)
512 os_vm_address_t end = (os_vm_address_t) ((int)(address+length+(32-1)) &~(32-1));
513 extern void ppc_flush_cache_line(os_vm_address_t);
515 while (address < end) {
516 ppc_flush_cache_line(address);
521 #ifdef LISP_FEATURE_LINKAGE_TABLE
523 /* Linkage tables for PowerPC
525 * Linkage entry size is 16, because we need at least 4 instructions to
530 * Define the registers to use in the linkage jump table. Can be the
531 * same. Some care must be exercised when choosing these. It has to be
532 * a register that is not otherwise being used. reg_NFP is a good
533 * choice. call_into_c trashes reg_NFP without preserving it, so we can
534 * trash it in the linkage jump table.
536 #define LINKAGE_TEMP_REG reg_NFP
537 #define LINKAGE_ADDR_REG reg_NFP
540 * Insert the necessary jump instructions at the given address.
543 arch_write_linkage_table_jmp(void* reloc_addr, void *target_addr)
546 * Make JMP to function entry.
548 * The instruction sequence is:
550 * addis 13, 0, (hi part of addr)
551 * ori 13, 13, (low part of addr)
557 unsigned long hi; /* Top 16 bits of address */
558 unsigned long lo; /* Low 16 bits of address */
561 inst_ptr = (int*) reloc_addr;
564 * Split the target address into hi and lo parts for the sethi
565 * instruction. hi is the top 22 bits. lo is the low 10 bits.
567 hi = (unsigned long) target_addr;
572 * addis 13, 0, (hi part)
575 inst = (15 << 26) | (LINKAGE_TEMP_REG << 21) | (0 << 16) | hi;
579 * ori 13, 13, (lo part)
582 inst = (24 << 26) | (LINKAGE_TEMP_REG << 21) | (LINKAGE_TEMP_REG << 16) | lo;
589 inst = (31 << 26) | (LINKAGE_TEMP_REG << 21) | (9 << 16) | (467 << 1);
596 inst = (19 << 26) | (20 << 21) | (528 << 1);
602 os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - (char*) reloc_addr);
606 arch_write_linkage_table_ref(void * reloc_addr, void *target_addr)
608 *(unsigned long *)reloc_addr = (unsigned long)target_addr;