3 $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/sparc-arch.c,v 1.30 2008/11/12 15:04:24 rtoy Rel $
5 This code was written as part of the CMU Common Lisp project at
6 Carnegie Mellon University, and has been placed in the public domain.
14 #include <machine/trap.h>
19 #include "internals.h"
25 #include "interrupt.h"
27 #include "breakpoint.h"
31 arch_init(fpu_mode_t mode)
37 arch_get_bad_addr(HANDLER_ARGS)
41 os_context_t *os_context = (os_context_t *) context;
43 /* On the sparc, we have to decode the instruction. */
45 /* Make sure it's not the pc thats bogus, and that it was lisp code */
46 /* that caused the fault. */
47 if ((SC_PC(os_context) & 3) != 0 ||
48 ((SC_PC(os_context) < READ_ONLY_SPACE_START ||
49 SC_PC(os_context) >= READ_ONLY_SPACE_START + read_only_space_size) &&
50 ((lispobj *) SC_PC(os_context) < current_dynamic_space &&
51 (lispobj *) SC_PC(os_context) >=
52 current_dynamic_space + dynamic_space_size))) return 0;
54 badinst = *(unsigned int *) SC_PC(os_context);
56 if ((badinst >> 30) != 3)
57 /* All load/store instructions have op = 11 (binary) */
60 rs1 = (badinst >> 14) & 0x1f;
62 if (badinst & (1 << 13)) {
63 /* r[rs1] + simm(13) */
64 int simm13 = badinst & 0x1fff;
66 if (simm13 & (1 << 12))
69 return (os_vm_address_t) (SC_REG(os_context, rs1) + simm13);
72 int rs2 = badinst & 0x1f;
74 return (os_vm_address_t) (SC_REG(os_context, rs1) + SC_REG(os_context, rs2));
80 arch_skip_instruction(os_context_t *context)
82 /* Skip the offending instruction */
83 SC_PC(context) = SC_NPC(context);
88 arch_internal_error_arguments(struct sigcontext *scp)
90 return (unsigned char *) (SC_PC(scp) + 4);
94 arch_pseudo_atomic_atomic(struct sigcontext *scp)
96 return (SC_REG(scp, reg_ALLOC) & pseudo_atomic_Value);
100 arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
102 SC_REG(scp, reg_ALLOC) |= pseudo_atomic_InterruptedValue;
106 arch_install_breakpoint(void *pc)
108 unsigned int *ptr = (unsigned int *) pc;
109 unsigned int result = *ptr;
111 *ptr = trap_Breakpoint;
112 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
118 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
120 *(unsigned int *) pc = (unsigned int) orig_inst;
121 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
124 static unsigned int *skipped_break_addr, displaced_after_inst;
126 static sigset_t orig_sigmask;
129 arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
131 unsigned int *pc = (unsigned int *) SC_PC(scp);
132 unsigned int *npc = (unsigned int *) SC_NPC(scp);
134 orig_sigmask = scp->uc_sigmask;
135 sigemptyset(&scp->uc_sigmask);
136 FILLBLOCKSET(&scp->uc_sigmask);
139 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
141 skipped_break_addr = pc;
142 displaced_after_inst = *npc;
143 *npc = trap_AfterBreakpoint;
144 os_flush_icache((os_vm_address_t) npc, sizeof(unsigned int));
147 /* XXX never tested */
155 * Look at the instruction at address PC and see if it's a trap
156 * instruction with an immediate value. If so, set trapno to the trap
157 * number, and return non-zero. If it's not a trap instruction,
161 trap_inst_p(unsigned int *pc, int *trapno)
163 unsigned int trap_inst;
167 if (((trap_inst >> 30) == 2)
168 && (((trap_inst >> 19) & 0x3f) == 0x3a)
169 && (((trap_inst >> 14) & 0x1f) == reg_ZERO)
170 && (((trap_inst >> 13) & 1) == 1)) {
172 * Got a trap instruction with immediate trap value.
173 * Get the value and return.
175 *trapno = (trap_inst & 0x3f);
186 pseudo_atomic_trap_p(struct sigcontext *context)
189 unsigned int badinst;
194 pc = (unsigned int *) SC_PC(context);
199 * Check to see if the current instruction is a trap #16. We check
200 * to make sure this instruction was a trap instruction with rs1 = 0
201 * and a software trap number (immediate value) of 16.
203 if (trap_inst_p(pc, &trapno) && (trapno == trap_PseudoAtomic)) {
204 unsigned int previnst;
208 * Check to see if the previous instruction was an andcc alloc-tn,
209 * pseudo_atomic_InterruptedValue, zero-tn instruction.
211 if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
212 && (((previnst >> 14) & 0x1f) == reg_ALLOC)
213 && (((previnst >> 25) & 0x1f) == reg_ZERO)
214 && (((previnst >> 13) & 1) == 1)
215 && ((previnst & 0x1fff) == pseudo_atomic_InterruptedValue)) {
219 "Oops! Got a pseudo atomic trap without a preceeding andcc!\n");
227 * Return non-zero if the instruction is a trap 31 instruction
231 allocation_trap_p(struct sigcontext * context)
235 unsigned int or_inst;
241 * Make sure this is a trap 31 instruction preceeded by an OR
245 pc = (unsigned int *) SC_PC(context);
247 if (trap_inst_p(pc, &trapno) && (trapno == trap_Allocation)) {
248 /* Got the trap. Is it preceeded by an OR instruction or SUB
251 if ((((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2)) ||
252 (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 4))) {
256 "Whoa!!! Got an allocation trap not preceeded by an OR inst: 0x%08x!\n",
266 /* Pop the stack frame that build_fake_control_stack_frame makes */
268 pop_fake_control_stack_frame(struct sigcontext *context)
270 current_control_frame_pointer = (lispobj *) SC_REG(context, reg_CFP);
271 SC_REG(context, reg_OCFP) = current_control_frame_pointer[0];
272 SC_REG(context, reg_CODE) = current_control_frame_pointer[1];
273 SC_REG(context, reg_CSP) = SC_REG(context, reg_CFP);
274 SC_REG(context, reg_CFP) = SC_REG(context, reg_OCFP);
279 * Use this function to enable the minimum number of signals we need
280 * when our trap handler needs to call Lisp code that might cons. For
281 * consing to work with gencgc, we need to be able to trap the SIGILL
282 * signal to perform allocation.
285 enable_some_signals(void)
291 sigaddset(&sigs, SIGILL);
292 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
298 handle_allocation_trap(struct sigcontext *context)
301 unsigned int or_inst;
305 boolean were_in_lisp;
314 * Block all blockable signals. Need to do this because
315 * sigill_handler enables the signals. When the handler returns,
316 * signals should be enabled again, automatically.
320 FILLBLOCKSET(&block);
321 sigprocmask(SIG_BLOCK, &block, 0);
324 * Well, maybe not. sigill_handler probably shouldn't be unblocking
325 * all signals. So, let's enable just the signals we need. Since
326 * alloc might call GC, we need to have SIGILL enabled so we can do
327 * allocation. Do we need more?
329 enable_some_signals();
332 pc = (unsigned int *) SC_PC(context);
336 * The instruction before this trap instruction had better be an OR
337 * instruction or SUB instruction!
340 if (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2)) {
342 * An OR instruction. RS1 is the register we want to allocate
343 * to. RS2 (or an immediate) is the size.
346 target = (or_inst >> 14) & 0x1f;
348 immed = (or_inst >> 13) & 1;
351 size = or_inst & 0x1fff;
353 size = or_inst & 0x1f;
354 size = SC_REG(context, size);
356 } else if (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 4)) {
358 * A SUB instruction. RD is the register to allocate to, RS2
359 * (or an immediate) is the size.
362 target = (or_inst >> 25) & 0x1f;
363 immed = (or_inst >> 13) & 1;
365 size = or_inst & 0x1fff;
367 size = or_inst & 0x1f;
368 size = SC_REG(context, size);
374 * I don't think it's possible for us NOT to be in lisp when we get
375 * here. Remove this later?
377 were_in_lisp = !foreign_function_call_active;
380 fake_foreign_function_call(context);
382 fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
386 * alloc-tn was incremented by size. If we get here, we need to
387 * decrement it by size to restore it's original value.
389 /* current_dynamic_space_free_pointer = (lispobj *) SC_REG(context, reg_ALLOC); */
390 current_dynamic_space_free_pointer =
391 (lispobj *) ((long) current_dynamic_space_free_pointer - size);
394 * Allocate some memory, store the memory address in target.
398 fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
401 memory = (char *) alloc(size);
402 SC_REG(context, target) = (unsigned long) memory;
403 SC_REG(context, reg_ALLOC) =
404 (unsigned long) current_dynamic_space_free_pointer;
407 undo_fake_foreign_function_call(context);
414 * How to identify an illegal instruction trap and a trap instruction
418 #define ILLTRAP_INST ILL_ILLOPC
419 #define TRAP_INST(code) (CODE(code) == ILL_ILLTRP)
421 #define ILLTRAP_INST T_UNIMP_INSTR
422 #define TRAP_INST(code) ((CODE(code) >= T_SOFTWARE_TRAP + 16) && (CODE(code) < T_SOFTWARE_TRAP + 32))
426 sigill_handler(HANDLER_ARGS)
428 os_context_t *os_context = (os_context_t *) context;
433 * Do we really want to have the same signals as in the context?
434 * This would typically enable all signals, I think. But there
435 * are comments in interrupt_handle_now that says we want to
436 * alloc_sap while interrupts are disabled. The interrupt
437 * handlers that eventually get called from here will re-enable
438 * interrupts at the appropriate time, so we don't do anything
441 * (I'm guessing here. I don't really know if this is right or
442 * not, but it doesn't seem to cause harm, and it does seem to be
443 * a bad idea to have interrupts enabled here.)
446 sigprocmask(SIG_SETMASK, &os_context->uc_sigmask, 0);
449 if (CODE(code) == ILLTRAP_INST) {
452 unsigned int *pc = (unsigned int *) (SC_PC(os_context));
456 illtrap_code = inst & 0x3fffff;
458 switch (illtrap_code) {
459 case trap_PendingInterrupt:
460 arch_skip_instruction(os_context);
461 interrupt_handle_pending(os_context);
465 fake_foreign_function_call(os_context);
466 lose("%%primitive halt called; the party is over.\n");
470 interrupt_internal_error(signal, code, os_context,
471 illtrap_code == trap_Cerror);
474 case trap_Breakpoint:
475 enable_some_signals();
476 handle_breakpoint(signal, CODE(code), os_context);
479 case trap_FunctionEndBreakpoint:
480 enable_some_signals();
482 (long) handle_function_end_breakpoint(signal, CODE(code),
484 SC_NPC(os_context) = SC_PC(os_context) + 4;
487 case trap_AfterBreakpoint:
488 *skipped_break_addr = trap_Breakpoint;
489 skipped_break_addr = NULL;
490 *(unsigned long *) SC_PC(os_context) = displaced_after_inst;
491 os_context->uc_sigmask = orig_sigmask;
492 os_flush_icache((os_vm_address_t) SC_PC(os_context),
494 sizeof(unsigned long));
497 #ifdef trap_DynamicSpaceOverflowWarning
498 case trap_DynamicSpaceOverflowWarning:
499 arch_skip_instruction(os_context);
500 enable_some_signals();
501 interrupt_handle_space_overflow(SymbolFunction
502 (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
506 #ifdef trap_DynamicSpaceOverflowError
507 case trap_DynamicSpaceOverflowError:
508 arch_skip_instruction(os_context);
509 enable_some_signals();
510 interrupt_handle_space_overflow(SymbolFunction
511 (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
516 interrupt_handle_now(signal, code, os_context);
519 } else if (TRAP_INST(code)) {
520 if (pseudo_atomic_trap_p(os_context)) {
521 /* A trap instruction from a pseudo-atomic. We just need
522 to fixup up alloc-tn to remove the interrupted flag,
523 skip over the trap instruction, and then handle the
524 pending interrupt(s). */
525 SC_REG(os_context, reg_ALLOC) &= ~lowtag_Mask;
526 arch_skip_instruction(os_context);
527 interrupt_handle_pending(os_context);
530 else if (allocation_trap_p(os_context)) {
531 /* An allocation trap. Call the trap handler and then skip
533 handle_allocation_trap(os_context);
534 arch_skip_instruction(os_context);
538 interrupt_internal_error(signal, code, os_context, FALSE);
541 interrupt_handle_now(signal, code, os_context);
546 arch_install_interrupt_handlers(void)
548 interrupt_install_low_level_handler(SIGILL, sigill_handler);
552 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
555 funcall0(lispobj function)
557 lispobj *args = current_control_stack_pointer;
559 return call_into_lisp(function, args, 0);
563 funcall1(lispobj function, lispobj arg0)
565 lispobj *args = current_control_stack_pointer;
567 current_control_stack_pointer += 1;
570 return call_into_lisp(function, args, 1);
574 funcall2(lispobj function, lispobj arg0, lispobj arg1)
576 lispobj *args = current_control_stack_pointer;
578 current_control_stack_pointer += 2;
582 return call_into_lisp(function, args, 2);
586 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
588 lispobj *args = current_control_stack_pointer;
590 current_control_stack_pointer += 3;
595 return call_into_lisp(function, args, 3);
600 /* This is mostly stolen from the x86 version, with adjustments for sparc */
603 * Linkage entry size is 16, because we need at least 3 instruction to
606 * sethi %hi(addr), %g4
607 * jmpl [%g4 + %lo(addr)], %g5
610 * The Sparc V9 ABI seems to use 8 words for its jump tables. Maybe
611 * we should do the same?
615 * This had better match lisp::target-foreign-linkage-entry-size in
616 * sparc/parms.lisp! Each entry is 4 instructions long, so 16 bytes.
618 #ifndef LinkageEntrySize
619 #define LinkageEntrySize (4*4)
624 * Define the registers to use in the linkage jump table. Can be the
625 * same. This MUST be coordinated with resolve_linkage_tramp which
626 * needs to know the register used for LINKAGE_ADDR_REG.
628 * Some care must be exercised when choosing these. It has to be a
629 * register that is not otherwise being used. reg_L0 is a good
630 * choice. call_into_c trashes reg_L0 without preserving it, so we
631 * can trash it in the linkage jump table. For the linkage entries
632 * that call resolve_linkage_tramp, we can use reg_L0 too because
633 * resolve_linkage_tramp is always called from call_into_c. (This is
634 * enforced by having new-genesis create an entry for call_into_c, so
635 * we never have to do a lookup for call_into_c.)
637 * The LINKAGE_ADDR_REG is important! resolve_linkage_tramp needs to
638 * be coordinated with this because that's how resolve_linkage_tramp
639 * figures out what linkage entry it's being called from.
641 #define LINKAGE_TEMP_REG reg_L0
642 #define LINKAGE_ADDR_REG reg_L0
645 * Insert the necessary jump instructions at the given address.
646 * Return the address of the next word
649 arch_make_jump_entry(void *reloc_addr, void *target_addr)
653 * Make JMP to function entry.
655 * The instruction sequence is:
657 * sethi %hi(addr), temp_reg
658 * jmpl %temp_reg + %lo(addr), %addr_reg
664 unsigned long hi; /* Top 22 bits of address */
665 unsigned long lo; /* Low 10 bits of address */
668 inst_ptr = (int *) reloc_addr;
671 * Split the target address into hi and lo parts for the sethi
672 * instruction. hi is the top 22 bits. lo is the low 10 bits.
674 hi = (unsigned long) target_addr;
679 * sethi %hi(addr), temp_reg
682 inst = (0 << 30) | (LINKAGE_TEMP_REG << 25) | (4 << 22) | hi;
686 * jmpl [temp_reg + %lo(addr)], addr_reg
689 inst = (2U << 30) | (LINKAGE_ADDR_REG << 25) | (0x38 << 19)
690 | (LINKAGE_TEMP_REG << 14) | (1 << 13) | lo;
693 /* nop (really sethi 0, %g0) */
695 inst = (0 << 30) | (0 << 25) | (4 << 22) | 0;
700 os_flush_icache((os_vm_address_t) reloc_addr,
701 (char *) inst_ptr - (char *) reloc_addr);
706 arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
708 int *reloc_addr = (int *) (FOREIGN_LINKAGE_SPACE_START
710 + linkage_entry * LinkageEntrySize);
712 if (type == 1) { /* code reference */
713 arch_make_jump_entry(reloc_addr, target_addr);
714 } else if (type == 2) {
715 *(unsigned long *) reloc_addr = (unsigned long) target_addr;
719 /* Make a the entry a jump to resolve_linkage_tramp. */
721 extern void resolve_linkage_tramp(void);
724 arch_make_lazy_linkage(long linkage_entry)
726 arch_make_linkage_entry(linkage_entry, (void *) resolve_linkage_tramp, 1);
729 /* Get linkage entry. We're given the return address which should be
730 the address of the jmpl instruction (2nd word) of the linkage
731 entry. Figure out which entry this address belong to. */
734 arch_linkage_entry(unsigned long retaddr)
736 return (retaddr - (FOREIGN_LINKAGE_SPACE_START))
739 #endif /* LINKAGE_TABLE */