502717932ebd57f151cc6fccac42f6342b995500
[projects/cmucl/cmucl.git] / src / lisp / sparc-arch.c
1 /*
2
3  $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/sparc-arch.c,v 1.30 2008/11/12 15:04:24 rtoy Rel $
4
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.
7
8 */
9
10 #include <stdio.h>
11 #ifdef SOLARIS
12 #include <sys/trap.h>
13 #else
14 #include <machine/trap.h>
15 #endif
16
17 #include "arch.h"
18 #include "lisp.h"
19 #include "internals.h"
20 #include "globals.h"
21 #include "validate.h"
22 #include "os.h"
23 #include "lispregs.h"
24 #include "signal.h"
25 #include "interrupt.h"
26 #include "gencgc.h"
27 #include "breakpoint.h"
28 #include "interr.h"
29
30 char *
31 arch_init(fpu_mode_t mode)
32 {
33     return 0;
34 }
35
36 os_vm_address_t
37 arch_get_bad_addr(HANDLER_ARGS)
38 {
39     unsigned int badinst;
40     int rs1;
41     os_context_t *os_context = (os_context_t *) context;
42     
43     /* On the sparc, we have to decode the instruction. */
44
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;
53
54     badinst = *(unsigned int *) SC_PC(os_context);
55
56     if ((badinst >> 30) != 3)
57         /* All load/store instructions have op = 11 (binary) */
58         return 0;
59
60     rs1 = (badinst >> 14) & 0x1f;
61
62     if (badinst & (1 << 13)) {
63         /* r[rs1] + simm(13) */
64         int simm13 = badinst & 0x1fff;
65
66         if (simm13 & (1 << 12))
67             simm13 |= -1 << 13;
68
69         return (os_vm_address_t) (SC_REG(os_context, rs1) + simm13);
70     } else {
71         /* r[rs1] + r[rs2] */
72         int rs2 = badinst & 0x1f;
73
74         return (os_vm_address_t) (SC_REG(os_context, rs1) + SC_REG(os_context, rs2));
75     }
76
77 }
78
79 void
80 arch_skip_instruction(os_context_t *context)
81 {
82     /* Skip the offending instruction */
83     SC_PC(context) = SC_NPC(context);
84     SC_NPC(context) += 4;
85 }
86
87 unsigned char *
88 arch_internal_error_arguments(struct sigcontext *scp)
89 {
90     return (unsigned char *) (SC_PC(scp) + 4);
91 }
92
93 boolean
94 arch_pseudo_atomic_atomic(struct sigcontext *scp)
95 {
96     return (SC_REG(scp, reg_ALLOC) & pseudo_atomic_Value);
97 }
98
99 void
100 arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
101 {
102     SC_REG(scp, reg_ALLOC) |= pseudo_atomic_InterruptedValue;
103 }
104
105 unsigned long
106 arch_install_breakpoint(void *pc)
107 {
108     unsigned int *ptr = (unsigned int *) pc;
109     unsigned int result = *ptr;
110
111     *ptr = trap_Breakpoint;
112     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
113
114     return result;
115 }
116
117 void
118 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
119 {
120     *(unsigned int *) pc = (unsigned int) orig_inst;
121     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
122 }
123
124 static unsigned int *skipped_break_addr, displaced_after_inst;
125
126 static sigset_t orig_sigmask;
127
128 void
129 arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
130 {
131     unsigned int *pc = (unsigned int *) SC_PC(scp);
132     unsigned int *npc = (unsigned int *) SC_NPC(scp);
133
134     orig_sigmask = scp->uc_sigmask;
135     sigemptyset(&scp->uc_sigmask);
136     FILLBLOCKSET(&scp->uc_sigmask);
137
138     *pc = orig_inst;
139     os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
140
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));
145
146 #ifdef SOLARIS
147     /* XXX never tested */
148     setcontext(scp);
149 #else
150     sigreturn(scp);
151 #endif
152 }
153
154 /*
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,
158  * return 0.
159  */
160 boolean
161 trap_inst_p(unsigned int *pc, int *trapno)
162 {
163     unsigned int trap_inst;
164
165     trap_inst = *pc;
166
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)) {
171         /*
172          * Got a trap instruction with immediate trap value.
173          * Get the value and return.
174          */
175         *trapno = (trap_inst & 0x3f);
176
177         return 1;
178     } else {
179         *trapno = -1;
180         return 0;
181     }
182 }
183
184
185 static int
186 pseudo_atomic_trap_p(struct sigcontext *context)
187 {
188     unsigned int *pc;
189     unsigned int badinst;
190     int trapno;
191     int result;
192
193
194     pc = (unsigned int *) SC_PC(context);
195     badinst = *pc;
196     result = 0;
197
198     /*
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.
202      */
203     if (trap_inst_p(pc, &trapno) && (trapno == trap_PseudoAtomic)) {
204         unsigned int previnst;
205
206         previnst = pc[-1];
207         /*
208          * Check to see if the previous instruction was an andcc alloc-tn,
209          * pseudo_atomic_InterruptedValue, zero-tn instruction.
210          */
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)) {
216             result = 1;
217         } else {
218             fprintf(stderr,
219                     "Oops!  Got a pseudo atomic trap without a preceeding andcc!\n");
220         }
221     }
222     return result;
223 }
224
225 #ifdef GENCGC
226 /*
227  * Return non-zero if the instruction is a trap 31 instruction
228  */
229
230 boolean
231 allocation_trap_p(struct sigcontext * context)
232 {
233     int result;
234     unsigned int *pc;
235     unsigned int or_inst;
236     int trapno;
237
238     result = 0;
239
240     /*
241      * Make sure this is a trap 31 instruction preceeded by an OR
242      * instruction.
243      */
244
245     pc = (unsigned int *) SC_PC(context);
246
247     if (trap_inst_p(pc, &trapno) && (trapno == trap_Allocation)) {
248         /* Got the trap.  Is it preceeded by an OR instruction or SUB
249            instruction? */
250         or_inst = pc[-1];
251         if ((((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2)) ||
252             (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 4))) {
253             result = 1;
254         } else {
255             fprintf(stderr,
256                     "Whoa!!! Got an allocation trap not preceeded by an OR inst: 0x%08x!\n",
257                     or_inst);
258         }
259     }
260
261     return result;
262 }
263 #endif
264
265 #if 0
266 /* Pop the stack frame that build_fake_control_stack_frame makes */
267 static void
268 pop_fake_control_stack_frame(struct sigcontext *context)
269 {
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);
275 }
276 #endif
277
278 /*
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.
283  */
284 void
285 enable_some_signals(void)
286 {
287 #ifdef GENCGC
288     sigset_t sigs;
289
290     sigemptyset(&sigs);
291     sigaddset(&sigs, SIGILL);
292     sigprocmask(SIG_UNBLOCK, &sigs, NULL);
293 #endif
294 }
295
296 #ifdef GENCGC
297 void
298 handle_allocation_trap(struct sigcontext *context)
299 {
300     unsigned int *pc;
301     unsigned int or_inst;
302     int target;
303     int size;
304     int immed;
305     boolean were_in_lisp;
306     char *memory;
307     sigset_t block;
308
309     target = 0;
310     size = 0;
311
312 #if 0
313     /*
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.
317      */
318
319     sigemptyset(&block);
320     FILLBLOCKSET(&block);
321     sigprocmask(SIG_BLOCK, &block, 0);
322 #else
323     /*
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?
328      */
329     enable_some_signals();
330 #endif
331
332     pc = (unsigned int *) SC_PC(context);
333     or_inst = pc[-1];
334
335     /*
336      * The instruction before this trap instruction had better be an OR
337      * instruction or SUB instruction!
338      */
339
340     if (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2)) {
341         /*
342          * An OR instruction.  RS1 is the register we want to allocate
343          * to.  RS2 (or an immediate) is the size.
344          */
345
346         target = (or_inst >> 14) & 0x1f;
347
348         immed = (or_inst >> 13) & 1;
349
350         if (immed == 1) {
351             size = or_inst & 0x1fff;
352         } else {
353             size = or_inst & 0x1f;
354             size = SC_REG(context, size);
355         }
356     } else if (((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 4)) {
357         /*
358          * A SUB instruction.  RD is the register to allocate to, RS2
359          * (or an immediate) is the size.
360          */
361
362         target = (or_inst >> 25) & 0x1f;
363         immed = (or_inst >> 13) & 1;
364         if (immed == 1) {
365             size = or_inst & 0x1fff;
366         } else {
367             size = or_inst & 0x1f;
368             size = SC_REG(context, size);
369         }
370     }
371
372
373     /*
374      * I don't think it's possible for us NOT to be in lisp when we get
375      * here.  Remove this later?
376      */
377     were_in_lisp = !foreign_function_call_active;
378
379     if (were_in_lisp) {
380         fake_foreign_function_call(context);
381     } else {
382         fprintf(stderr, "**** Whoa! allocation trap and we weren't in lisp!\n");
383     }
384
385     /*
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.
388      */
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);
392
393     /*
394      * Allocate some memory, store the memory address in target.
395      */
396
397 #if 0
398     fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]);
399 #endif
400
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;
405
406     if (were_in_lisp) {
407         undo_fake_foreign_function_call(context);
408     }
409
410 }
411 #endif
412
413 /*
414  * How to identify an illegal instruction trap and a trap instruction
415  * trap.
416  */
417 #ifdef SOLARIS
418 #define ILLTRAP_INST ILL_ILLOPC
419 #define TRAP_INST(code) (CODE(code) == ILL_ILLTRP)
420 #else
421 #define ILLTRAP_INST T_UNIMP_INSTR
422 #define TRAP_INST(code) ((CODE(code) >= T_SOFTWARE_TRAP + 16) && (CODE(code) < T_SOFTWARE_TRAP + 32))
423 #endif
424
425 static void
426 sigill_handler(HANDLER_ARGS)
427 {
428     os_context_t *os_context = (os_context_t *) context;
429     
430     SAVE_CONTEXT();
431
432     /*
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
439      * here.
440      *
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.)
444      */
445 #if 0
446     sigprocmask(SIG_SETMASK, &os_context->uc_sigmask, 0);
447 #endif
448
449     if (CODE(code) == ILLTRAP_INST) {
450         int illtrap_code;
451         unsigned int inst;
452         unsigned int *pc = (unsigned int *) (SC_PC(os_context));
453
454         inst = *pc;
455
456         illtrap_code = inst & 0x3fffff;
457
458         switch (illtrap_code) {
459           case trap_PendingInterrupt:
460               arch_skip_instruction(os_context);
461               interrupt_handle_pending(os_context);
462               break;
463
464           case trap_Halt:
465               fake_foreign_function_call(os_context);
466               lose("%%primitive halt called; the party is over.\n");
467
468           case trap_Error:
469           case trap_Cerror:
470               interrupt_internal_error(signal, code, os_context,
471                                        illtrap_code == trap_Cerror);
472               break;
473
474           case trap_Breakpoint:
475               enable_some_signals();
476               handle_breakpoint(signal, CODE(code), os_context);
477               break;
478
479           case trap_FunctionEndBreakpoint:
480               enable_some_signals();
481               SC_PC(os_context) =
482                   (long) handle_function_end_breakpoint(signal, CODE(code),
483                                                         os_context);
484               SC_NPC(os_context) = SC_PC(os_context) + 4;
485               break;
486
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),
493
494                               sizeof(unsigned long));
495               break;
496
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),
503                                               os_context);
504               break;
505 #endif
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),
512                                               os_context);
513               break;
514 #endif
515           default:
516               interrupt_handle_now(signal, code, os_context);
517               break;
518         }
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);
528         }
529 #ifdef GENCGC
530         else if (allocation_trap_p(os_context)) {
531             /* An allocation trap. Call the trap handler and then skip
532                this instruction */
533             handle_allocation_trap(os_context);
534             arch_skip_instruction(os_context);
535         }
536 #endif
537         else {
538             interrupt_internal_error(signal, code, os_context, FALSE);
539         }
540     } else {
541         interrupt_handle_now(signal, code, os_context);
542     }
543 }
544
545 void
546 arch_install_interrupt_handlers(void)
547 {
548     interrupt_install_low_level_handler(SIGILL, sigill_handler);
549 }
550
551
552 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
553
554 lispobj
555 funcall0(lispobj function)
556 {
557     lispobj *args = current_control_stack_pointer;
558
559     return call_into_lisp(function, args, 0);
560 }
561
562 lispobj
563 funcall1(lispobj function, lispobj arg0)
564 {
565     lispobj *args = current_control_stack_pointer;
566
567     current_control_stack_pointer += 1;
568     args[0] = arg0;
569
570     return call_into_lisp(function, args, 1);
571 }
572
573 lispobj
574 funcall2(lispobj function, lispobj arg0, lispobj arg1)
575 {
576     lispobj *args = current_control_stack_pointer;
577
578     current_control_stack_pointer += 2;
579     args[0] = arg0;
580     args[1] = arg1;
581
582     return call_into_lisp(function, args, 2);
583 }
584
585 lispobj
586 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
587 {
588     lispobj *args = current_control_stack_pointer;
589
590     current_control_stack_pointer += 3;
591     args[0] = arg0;
592     args[1] = arg1;
593     args[2] = arg2;
594
595     return call_into_lisp(function, args, 3);
596 }
597
598 #ifdef LINKAGE_TABLE
599
600 /* This is mostly stolen from the x86 version, with adjustments for sparc */
601
602 /*
603  * Linkage entry size is 16, because we need at least 3 instruction to
604  * implement a jump:
605  *
606  *      sethi %hi(addr), %g4
607  *      jmpl  [%g4 + %lo(addr)], %g5
608  *      nop
609  *
610  * The Sparc V9 ABI seems to use 8 words for its jump tables.  Maybe
611  * we should do the same?
612  */
613
614 /*
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.
617  */
618 #ifndef LinkageEntrySize
619 #define LinkageEntrySize (4*4)
620 #endif
621
622
623 /*
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.
627  *
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.)
636  *
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.
640  */
641 #define LINKAGE_TEMP_REG        reg_L0
642 #define LINKAGE_ADDR_REG        reg_L0
643
644 /*
645  * Insert the necessary jump instructions at the given address.
646  * Return the address of the next word
647  */
648 void *
649 arch_make_jump_entry(void *reloc_addr, void *target_addr)
650 {
651
652     /*
653      * Make JMP to function entry.
654      *
655      * The instruction sequence is:
656      *
657      *        sethi %hi(addr), temp_reg
658      *        jmpl  %temp_reg + %lo(addr), %addr_reg
659      *        nop
660      *        nop
661      *        
662      */
663     int *inst_ptr;
664     unsigned long hi;           /* Top 22 bits of address */
665     unsigned long lo;           /* Low 10 bits of address */
666     unsigned int inst;
667
668     inst_ptr = (int *) reloc_addr;
669
670     /*
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.
673      */
674     hi = (unsigned long) target_addr;
675     lo = hi & 0x3ff;
676     hi >>= 10;
677
678     /*
679      * sethi %hi(addr), temp_reg
680      */
681
682     inst = (0 << 30) | (LINKAGE_TEMP_REG << 25) | (4 << 22) | hi;
683     *inst_ptr++ = inst;
684
685     /*
686      * jmpl [temp_reg + %lo(addr)], addr_reg
687      */
688
689     inst = (2U << 30) | (LINKAGE_ADDR_REG << 25) | (0x38 << 19)
690         | (LINKAGE_TEMP_REG << 14) | (1 << 13) | lo;
691     *inst_ptr++ = inst;
692
693     /* nop (really sethi 0, %g0) */
694
695     inst = (0 << 30) | (0 << 25) | (4 << 22) | 0;
696
697     *inst_ptr++ = inst;
698     *inst_ptr++ = inst;
699
700     os_flush_icache((os_vm_address_t) reloc_addr,
701                     (char *) inst_ptr - (char *) reloc_addr);
702     return reloc_addr;
703 }
704
705 void
706 arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
707 {
708     int *reloc_addr = (int *) (FOREIGN_LINKAGE_SPACE_START
709
710                                + linkage_entry * LinkageEntrySize);
711
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;
716     }
717 }
718
719 /* Make a the entry a jump to resolve_linkage_tramp. */
720
721 extern void resolve_linkage_tramp(void);
722
723 void
724 arch_make_lazy_linkage(long linkage_entry)
725 {
726     arch_make_linkage_entry(linkage_entry, (void *) resolve_linkage_tramp, 1);
727 }
728
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. */
732
733 long
734 arch_linkage_entry(unsigned long retaddr)
735 {
736     return (retaddr - (FOREIGN_LINKAGE_SPACE_START))
737         / LinkageEntrySize;
738 }
739 #endif /* LINKAGE_TABLE */