diff options
| author | Jake Burkholder <jake@FreeBSD.org> | 2001-09-03 23:10:45 +0000 |
|---|---|---|
| committer | Jake Burkholder <jake@FreeBSD.org> | 2001-09-03 23:10:45 +0000 |
| commit | 880a354a4ad66e264413c7f2fe9f276cfa2acdba (patch) | |
| tree | e6d6ac79778aa0e037738238c2e767e7d5c34374 /sys | |
| parent | ce1e7a70b91ae50711ef301422abe54758167ca8 (diff) | |
Notes
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/sparc64/include/frame.h | 16 | ||||
| -rw-r--r-- | sys/sparc64/include/pcb.h | 8 | ||||
| -rw-r--r-- | sys/sparc64/include/wstate.h | 90 | ||||
| -rw-r--r-- | sys/sparc64/sparc64/exception.S | 1821 | ||||
| -rw-r--r-- | sys/sparc64/sparc64/exception.s | 1821 | ||||
| -rw-r--r-- | sys/sparc64/sparc64/rwindow.c | 100 |
6 files changed, 2348 insertions, 1508 deletions
diff --git a/sys/sparc64/include/frame.h b/sys/sparc64/include/frame.h index 883a45b7c39ba..1a0d4c40fce9f 100644 --- a/sys/sparc64/include/frame.h +++ b/sys/sparc64/include/frame.h @@ -39,7 +39,8 @@ struct trapframe { u_long tf_tpc; u_long tf_tstate; u_long tf_type; - void *tf_arg; + u_long tf_wstate; + uintptr_t tf_arg; }; #define tf_sp tf_out[6] @@ -74,13 +75,16 @@ struct frame { /* * Frame used for pcb_wscratch. */ -struct wsframe { - u_long wsf_local[8]; - u_long wsf_in[8]; - u_long wsf_sp; - u_long wsf_inuse; +struct rwindow { + u_long rw_local[8]; + u_long rw_in[8]; }; +struct proc; + +int rwindow_save(struct proc *p); +int rwindow_load(struct proc *p, struct trapframe *tf, int n); + int kdb_trap(struct trapframe *tf); #endif /* !_MACHINE_FRAME_H_ */ diff --git a/sys/sparc64/include/pcb.h b/sys/sparc64/include/pcb.h index 92e9699ecf96d..6ef98c998940c 100644 --- a/sys/sparc64/include/pcb.h +++ b/sys/sparc64/include/pcb.h @@ -44,14 +44,14 @@ /* NOTE: pcb_fpstate must be aligned on a 64 byte boundary. */ struct pcb { struct fpstate pcb_fpstate; + u_long pcb_cwp; u_long pcb_fp; u_long pcb_pc; u_long pcb_y; caddr_t pcb_onfault; - u_long pcb_inwinop; - u_long pcb_cwp; - u_long pcb_ws_inuse; - struct wsframe pcb_wscratch[MAXWIN]; + u_long pcb_nsaved; + u_long pcb_rwsp[MAXWIN]; + struct rwindow pcb_rw[MAXWIN]; }; struct md_coredump { diff --git a/sys/sparc64/include/wstate.h b/sys/sparc64/include/wstate.h new file mode 100644 index 0000000000000..089480d311acc --- /dev/null +++ b/sys/sparc64/include/wstate.h @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Berkeley Software Design Inc's name may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: BSDI: wstate.h,v 1.4 1997/09/18 13:05:51 torek Exp + * $FreeBSD$ + */ + +#ifndef _MACHINE_WSTATE_H_ +#define _MACHINE_WSTATE_H_ + +/* + * Window state register bits. + * + * There really are no bits per se, just the two fields WSTATE.NORMAL + * and WSTATE.OTHER. The rest is up to software. + * + * We use WSTATE_NORMAL to represent user mode or kernel mode saves + * (whichever is currently in effect) and WSTATE_OTHER to represent + * user mode saves (only). + * + * We use the low bit to suggest 32-bit mode, with the next bit set + * once we succeed in saving in some mode. That is, if the WSTATE_ASSUME + * bit is set, the spill or fill handler we use will be one that makes + * an assumption about the proper window-save mode. If the spill or + * fill fails with an alignment fault, the spill or fill op should + * take the `assume' bit away retry the instruction that caused the + * spill or fill. This will use the new %wstate, which will test for + * which mode to use. The alignment fault code helps us out here by + * resuming the spill vector at offset +70, where we are allowed to + * execute two instructions (i.e., write to %wstate and RETRY). + * + * If the ASSUME bit is not set when the alignment fault occurs, the + * given stack pointer is hopelessly wrong (and the spill, if it is a + * spill, should be done as a sort of "panic spill") -- so those two + * instructions will be a branch sequence. + * + * Note that locore.s assumes this same bit layout (since the translation + * from "bits" to "{spill,fill}_N_{normal,other}" is done in hardware). + * + * The value 0 is preferred for unknown to make it easy to start in + * unknown state and continue in whichever state unknown succeeds in -- + * a successful "other" save, for instance, can just set %wstate to + * ASSUMExx << USERSHIFT and thus leave the kernel state "unknown". + * + * We also need values for managing the somewhat tricky transition from + * user to kernel and back, so we use the one remaining free bit to mean + * "although this looks like kernel mode, the window(s) involved are + * user windows and should be saved ASI_AIUP". Everything else is + * otherwise the same, but we need not bother with assumptions in this + * mode (we expect it to apply to at most one window spill or fill), + * i.e., WSTATE_TRANSITION can ignore WSTATE_ASSUME if it likes. + */ + +#define WSTATE_32BIT 1 /* if set, probably 32-bit mode */ +#define WSTATE_ASSUME 2 /* if set, assume 32 or 64 */ +#define WSTATE_TRANSITION 4 /* if set, force user window */ + +#define WSTATE_TEST64 0 /* test, but anticipate 64-bit mode */ +#define WSTATE_TEST32 1 /* test, but anticipate 32-bit mode */ +#define WSTATE_ASSUME64 2 /* assume 64-bit mode */ +#define WSTATE_ASSUME32 3 /* assume 32-bit mode */ + +#define WSTATE_MASK 7 /* for WSTATE.NORMAL */ +#define WSTATE_USERSHIFT 3 /* for WSTATE.OTHER / user */ + +#endif /* !_MACHINE_WSTATE_H_ */ diff --git a/sys/sparc64/sparc64/exception.S b/sys/sparc64/sparc64/exception.S index 281464b18b209..8a10c17a1b4e1 100644 --- a/sys/sparc64/sparc64/exception.S +++ b/sys/sparc64/sparc64/exception.S @@ -59,69 +59,168 @@ #include <machine/asi.h> #include <machine/asmacros.h> +#include <machine/ktr.h> +#include <machine/pstate.h> #include <machine/trap.h> +#include <machine/tstate.h> +#include <machine/wstate.h> #include "assym.s" /* - * This is more or less relatively straight forward, except for the register - * window handling, which can get ugly. - * There are two situations where this can happen: - * - a normal (non spill/fill) trap from user space, where the windows are - * still filled with user data - * - a trap in a spill/fill trap handler that spills/fills userland windows - * In both cases, the spills of the user data may fault in a way that requires - * the C fault handler to be invoked, which needs a register window, so we would - * try to spill again... ad infinitum. - * The traps in question are dmmu_miss, dmmu_prot (both possibly fatal), - * data_access and alignment (fatal). - * So, on entry from user space, we set up a special %wstate (to handle a - * possible spill triggered by the first save), and later set %otherwin to - * split the window between kernel windows and user windows. - * The spill handler that is called with this %wstate or %otherwin != 0 spills - * to pcb_wscratch, indexed by %cwp, and notes the number of spilled registers - * in pcb_ws_inuse. Elements of pcb_wstate that are in use are marked by setting - * the wsf_inuse field. When the trap has completed, %otherwin is set so that - * user space spills/fills for windows that are still stored in pcb_wscratch are - * handled by directly filling from pcb_wscratch or spilling from pcb_wscratch - * to user space. + * Macros for spilling and filling live windows. + * + * NOTE: These macros use exactly 16 instructions, and it is assumed that the + * handler will not use more than 24 instructions total, to leave room for + * resume vectors which occupy the last 8 instructions. + */ + +#define SPILL(storer, base, size, asi) \ + storer %l0, [base + (0 * size)] asi ; \ + storer %l1, [base + (1 * size)] asi ; \ + storer %l2, [base + (2 * size)] asi ; \ + storer %l3, [base + (3 * size)] asi ; \ + storer %l4, [base + (4 * size)] asi ; \ + storer %l5, [base + (5 * size)] asi ; \ + storer %l6, [base + (6 * size)] asi ; \ + storer %l7, [base + (7 * size)] asi ; \ + storer %i0, [base + (8 * size)] asi ; \ + storer %i1, [base + (9 * size)] asi ; \ + storer %i2, [base + (10 * size)] asi ; \ + storer %i3, [base + (11 * size)] asi ; \ + storer %i4, [base + (12 * size)] asi ; \ + storer %i5, [base + (13 * size)] asi ; \ + storer %i6, [base + (14 * size)] asi ; \ + storer %i7, [base + (15 * size)] asi + +#define FILL(loader, base, size, asi) \ + loader [base + (0 * size)] asi, %l0 ; \ + loader [base + (1 * size)] asi, %l1 ; \ + loader [base + (2 * size)] asi, %l2 ; \ + loader [base + (3 * size)] asi, %l3 ; \ + loader [base + (4 * size)] asi, %l4 ; \ + loader [base + (5 * size)] asi, %l5 ; \ + loader [base + (6 * size)] asi, %l6 ; \ + loader [base + (7 * size)] asi, %l7 ; \ + loader [base + (8 * size)] asi, %i0 ; \ + loader [base + (9 * size)] asi, %i1 ; \ + loader [base + (10 * size)] asi, %i2 ; \ + loader [base + (11 * size)] asi, %i3 ; \ + loader [base + (12 * size)] asi, %i4 ; \ + loader [base + (13 * size)] asi, %i5 ; \ + loader [base + (14 * size)] asi, %i6 ; \ + loader [base + (15 * size)] asi, %i7 + +#define ERRATUM50(reg) mov reg, reg + +/* + * Magic to resume from a spill or fill trap. If we get an alignment or an + * mmu fault during a spill or a fill, this macro will detect the fault and + * resume at a set instruction offset in the trap handler, which will try to + * get help. + * + * To check if the previous trap was a spill/fill we convert the the trapped + * pc to a trap type and verify that it is in the range of spill/fill vectors. + * The spill/fill vectors are types 0x80-0xff and 0x280-0x2ff, masking off the + * tl bit allows us to detect both ranges with one test. + * + * This is: + * (((%tpc - %tba) >> 5) & ~0x200) >= 0x80 && <= 0xff + * + * Values outside of the trap table will produce negative or large positive + * results. + * + * To calculate the new pc we take advantage of the xor feature of wrpr. + * Forcing all the low bits of the trapped pc on we can produce any offset + * into the spill/fill vector. The size of a spill/fill trap vector is 0x80. + * + * 0x7f ^ 0x1f == 0x60 + * 0x1f == (0x80 - 0x60) - 1 + * + * Which are the offset and xor value used to resume from mmu faults. */ -#define SPILL(storer, base, asi, struct) \ - storer %l0, [base + struct ## _L0] asi ; \ - storer %l1, [base + struct ## _L1] asi ; \ - storer %l2, [base + struct ## _L2] asi ; \ - storer %l3, [base + struct ## _L3] asi ; \ - storer %l4, [base + struct ## _L4] asi ; \ - storer %l5, [base + struct ## _L5] asi ; \ - storer %l6, [base + struct ## _L6] asi ; \ - storer %l7, [base + struct ## _L7] asi ; \ - storer %i0, [base + struct ## _I0] asi ; \ - storer %i1, [base + struct ## _I1] asi ; \ - storer %i2, [base + struct ## _I2] asi ; \ - storer %i3, [base + struct ## _I3] asi ; \ - storer %i4, [base + struct ## _I4] asi ; \ - storer %i5, [base + struct ## _I5] asi ; \ - storer %i6, [base + struct ## _I6] asi ; \ - storer %i7, [base + struct ## _I7] asi +/* + * If a spill/fill trap is not detected this macro will branch to the label l1. + * Otherwise the caller should do any necesary cleanup and execute a done. + */ +#define RESUME_SPILLFILL_MAGIC(r1, r2, xor, l1) \ + rdpr %tpc, r1 ; \ + ERRATUM50(r1) ; \ + rdpr %tba, r2 ; \ + sub r1, r2, r2 ; \ + srlx r2, 5, r2 ; \ + andn r2, 0x200, r2 ; \ + sub r2, 0x80, r2 ; \ + brlz r2, l1 ; \ + sub r2, 0x7f, r2 ; \ + brgz r2, l1 ; \ + or r1, 0x7f, r1 ; \ + wrpr r1, xor, %tnpc ; \ + +#define RSF_XOR(off) ((0x80 - off) - 1) -#define FILL(loader, base, asi, struct) \ - loader [base + struct ## _L0] asi, %l0 ; \ - loader [base + struct ## _L1] asi, %l1 ; \ - loader [base + struct ## _L2] asi, %l2 ; \ - loader [base + struct ## _L3] asi, %l3 ; \ - loader [base + struct ## _L4] asi, %l4 ; \ - loader [base + struct ## _L5] asi, %l5 ; \ - loader [base + struct ## _L6] asi, %l6 ; \ - loader [base + struct ## _L7] asi, %l7 ; \ - loader [base + struct ## _I0] asi, %i0 ; \ - loader [base + struct ## _I1] asi, %i1 ; \ - loader [base + struct ## _I2] asi, %i2 ; \ - loader [base + struct ## _I3] asi, %i3 ; \ - loader [base + struct ## _I4] asi, %i4 ; \ - loader [base + struct ## _I5] asi, %i5 ; \ - loader [base + struct ## _I6] asi, %i6 ; \ - loader [base + struct ## _I7] asi, %i7 +/* + * Instruction offsets in spill and fill trap handlers for handling certain + * nested traps, and corresponding xor constants for wrpr. + */ +#define RSF_OFF_MMU 0x60 +#define RSF_OFF_ALIGN 0x70 + +#define RSF_MMU RSF_XOR(RSF_OFF_MMU) +#define RSF_ALIGN RSF_XOR(RSF_OFF_ALIGN) + +/* + * Constant to add to %tnpc when taking a fill trap just before returning to + * user mode. The instruction sequence looks like restore, wrpr, retry; we + * want to skip over the wrpr and retry and execute code to call back into the + * kernel. It is useful to add tracing between these instructions, which would + * change the size of the sequence, so we demark with labels and subtract. + */ +#define RSF_FILL_INC tl0_ret_fill_end - tl0_ret_fill + +/* + * Retry a spill or fill with a different wstate due to an alignment fault. + * We may just be using the wrong stack offset. + */ +#define RSF_ALIGN_RETRY(ws) \ + wrpr %g0, (ws), %wstate ; \ + retry ; \ + .align 16 + +/* + * Generate a T_SPILL or T_FILL trap if the window operation fails. + */ +#define RSF_TRAP(type) \ + b %xcc, tl0_sftrap ; \ + mov type, %g2 ; \ + .align 16 + +/* + * Game over if the window operation fails. + */ +#define RSF_FATAL(type) \ + sir type ; \ + .align 16 + +/* + * Magic to resume from a failed fill a few instructions after the corrsponding + * restore. This is used on return from the kernel to usermode. + */ +#define RSF_FILL_MAGIC \ + rdpr %tnpc, %g1 ; \ + add %g1, RSF_FILL_INC, %g1 ; \ + wrpr %g1, 0, %tnpc ; \ + done ; \ + .align 16 + +/* + * Spill to the pcb if a spill to the user stack in kernel mode fails. + */ +#define RSF_SPILL_TOPCB \ + b,a %xcc, tl1_spill_topcb ; \ + nop ; \ + .align 16 DATA(intrnames) .asciz "foo" @@ -131,6 +230,26 @@ DATA(intrcnt) .long 0 DATA(eintrcnt) +/* + * Trap table and associated macros + * + * Due to its size a trap table is an inherently hard thing to represent in + * code in a clean way. There are approximately 1024 vectors, of 8 or 32 + * instructions each, many of which are identical. The way that this is + * layed out is the instructions (8 or 32) for the actual trap vector appear + * as an AS macro. In general this code branches to tl0_trap or tl1_trap, + * but if not supporting code can be placed just after the definition of the + * macro. The macros are then instantiated in a different section (.trap), + * which is setup to be placed by the linker at the beginning of .text, and the + * code around the macros is moved to the end of trap table. In this way the + * code that must be sequential in memory can be split up, and located near + * its supporting code so that it is easier to follow. + */ + + /* + * Clean window traps occur when %cleanwin is zero to ensure that data + * is not leaked between address spaces in registers. + */ .macro clean_window clr %o0 clr %o1 @@ -155,109 +274,125 @@ DATA(eintrcnt) .align 128 .endm - /* Fixups for kernel entry from tl0. */ - /* - * Split the register window using %otherwin. This is an optimization - * to not have to flush all the register windows on kernel entry. - * Set %wstate so that spills go to the pcb; this is valid because there - * is always at least one frame. - * A spill with %wstate == 1 will invoke the same spill handler - * regardless of %otherwin (tl1_spill_1_n and tl1_spill_0_o are the - * same). - * Before the next save (that is, in tl0_trap_*), we finish the - * splitting setup and set %otherwin correctly. - * Note that the alternate %g7 must always be valid in places where we - * could spill. + * Stack fixups for entry from user mode. We are still running on the + * user stack, and with its live registers, so we must save soon. We + * are on alternate globals so we do have some registers. Set the + * transitional window state, save, and call a routine to get onto + * the kernel stack. If the save traps we attempt to spill a window + * to the user stack. If this fails, we spill the window to the pcb + * and continue. + * + * NOTE: Must be called with alternate globals and clobbers %g1. */ - .macro tl0_split_save - wrpr %g0, 1, %wstate + + .macro tl0_kstack + rdpr %wstate, %g1 + wrpr %g1, WSTATE_TRANSITION, %wstate save + call tl0_kstack_fixup + rdpr %canrestore, %o0 .endm - /* - * Flush out all but one of the user windows to the pcb register - * window scratch space. At the end of the trap, the windows are - * restored. - */ - .macro tl0_flush_save - wrpr %g0, 1, %wstate - save - flushw - wrpr %g0, 0, %wstate + .macro tl0_setup type + tl0_kstack + rdpr %pil, %o2 + b %xcc, tl0_trap + mov \type, %o0 .endm +/* + * Setup the kernel stack and split the register windows when faulting from + * user space. + * %canrestore is passed in %o0 and %wstate in (alternate) %g1. + */ +ENTRY(tl0_kstack_fixup) + mov %g1, %o3 + and %o3, WSTATE_MASK, %o1 + sllx %o0, WSTATE_USERSHIFT, %o1 + wrpr %o1, 0, %wstate + wrpr %o0, 0, %otherwin + wrpr %g0, 0, %canrestore + ldx [PCPU(CURPCB)], %o0 + set UPAGES * PAGE_SIZE - SPOFF - CCFSZ, %o1 + retl + add %o0, %o1, %sp +END(tl0_kstack_fixup) + /* - * Setup the kernel stack when faulting from user space. + * Generic trap type. Call trap() with the specified type. */ - .macro tl0_setup_stack tmp1, sz - /* Set up the kernel stack. */ - setx UPAGES * PAGE_SIZE - SPOFF - CCFSZ - TF_SIZEOF - \sz, \tmp1, %sp - ldx [PCPU(CURPCB)], \tmp1 - add %sp, \tmp1, %sp - .endm - .macro tl0_gen type - tl0_split_save - rdpr %pil, %o0 - b %xcc, tl0_trap - mov \type, %o1 + tl0_setup \type .align 32 .endm .macro tl0_wide type - tl0_split_save - rdpr %pil, %o0 - b %xcc, tl0_trap - mov \type, %o1 + tl0_setup \type .align 128 .endm + /* + * This is used to suck up the massive swaths of reserved trap types. + * Generates count "reserved" trap vectors. + */ .macro tl0_reserved count .rept \count tl0_gen T_RESERVED .endr .endm + /* + * NOTE: we cannot use mmu globals here because tl0_kstack may cause + * an mmu fault. + */ + .macro tl0_data_excptn + wrpr %g0, PSTATE_ALT, %pstate + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_SFAR] %asi, %g3 + ldxa [%g0 + AA_DMMU_SFSR] %asi, %g4 + ldxa [%g0 + AA_DMMU_TAR] %asi, %g5 + b %xcc, tl0_sfsr_trap + mov T_DATA_EXCPTN, %g2 + .align 32 + .endm + .macro tl0_align - rdpr %pstate, %g1 - wrpr %g1, PSTATE_MG | PSTATE_AG, %pstate + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_SFAR] %asi, %g3 + ldxa [%g0 + AA_DMMU_SFSR] %asi, %g4 b %xcc, tl0_sfsr_trap - mov T_ALIGN, %g4 + mov T_ALIGN, %g2 .align 32 .endm -/* - * This must be called with MMU globals active, otherwise the spill handler - * might clobber the globals we use to transfer the sfar and sfsr. - */ ENTRY(tl0_sfsr_trap) - wr %g0, ASI_DMMU, %asi - ldxa [%g0 + AA_DMMU_SFAR] %asi, %g1 - ldxa [%g0 + AA_DMMU_SFSR] %asi, %g2 + /* + * Clear the sfsr. + */ stxa %g0, [%g0 + AA_DMMU_SFSR] %asi membar #Sync - tl0_split_save - mov %g1, %l1 - mov %g2, %l2 - mov %g4, %o1 - rdpr %pstate, %l3 - wrpr %l3, PSTATE_MG | PSTATE_AG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFAR] - stx %l2, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFSR] - rdpr %pil, %o0 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 + /* + * Get onto the kernel stack, save the mmu registers, and call + * common code. + */ + tl0_kstack + sub %sp, MF_SIZEOF, %sp + stx %g3, [%sp + SPOFF + CCFSZ + MF_SFAR] + stx %g4, [%sp + SPOFF + CCFSZ + MF_SFSR] + stx %g5, [%sp + SPOFF + CCFSZ + MF_TAR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl0_trap + mov %g2, %o0 END(tl0_sfsr_trap) - .macro tl0_intr level, mask, type - tl0_split_save - set \level, %o3 + .macro tl0_intr level, mask + tl0_kstack set \mask, %o2 b %xcc, tl0_intr_call_trap - mov \type, %o1 + mov \level, %o1 .align 32 .endm @@ -266,18 +401,18 @@ END(tl0_sfsr_trap) * because of space constraints. */ ENTRY(tl0_intr_call_trap) - rdpr %pil, %o0 - wrpr %g0, %o3, %pil + wr %o2, 0, %asr21 + rdpr %pil, %o2 + wrpr %g0, %o1, %pil b %xcc, tl0_trap - wr %o2, 0, %asr21 + mov T_INTR, %o0 END(tl0_intr_call_trap) #define INTR(level, traplvl) \ - tl ## traplvl ## _intr level, 1 << level, \ - T_INTR | (level << T_LEVEL_SHIFT) + tl ## traplvl ## _intr level, 1 << level #define TICK(traplvl) \ - tl ## traplvl ## _intr 14, 1, T_INTR | (14 << T_LEVEL_SHIFT) + tl ## traplvl ## _intr PIL_TICK, 1 #define INTR_LEVEL(tl) \ INTR(1, tl) ; \ @@ -307,6 +442,11 @@ END(tl0_intr_call_trap) .macro tl0_immu_miss /* + * Force kernel store order. + */ + wrpr %g0, PSTATE_MMU, %pstate + + /* * Extract the 8KB pointer and convert to an index. */ ldxa [%g0] ASI_IMMU_TSB_8KB_PTR_REG, %g1 @@ -369,7 +509,7 @@ END(tl0_intr_call_trap) * Set the reference bit, if it's currently clear. */ andcc %g7, TD_REF, %g0 - bz,a,pn %xcc, immu_miss_user_set_ref + bz,a,pn %xcc, tl0_immu_miss_set_ref nop /* @@ -385,11 +525,11 @@ END(tl0_intr_call_trap) andcc %g2, TSB_PRIMARY_STTE_MASK, %g0 bnz %xcc, 1b nop - b,a %xcc, immu_miss_user_call_trap + b,a %xcc, tl0_immu_miss_trap .align 128 .endm -ENTRY(immu_miss_user_set_ref) +ENTRY(tl0_immu_miss_set_ref) /* * Set the reference bit. */ @@ -400,6 +540,12 @@ ENTRY(immu_miss_user_set_ref) bne,a,pn %xcc, 1b mov %g1, %g7 +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_immu_miss: set ref" + , %g2, %g3, %g4, 7, 8, 9) +9: +#endif + /* * May have become invalid, in which case start over. */ @@ -411,30 +557,39 @@ ENTRY(immu_miss_user_set_ref) */ stxa %g1, [%g0] ASI_ITLB_DATA_IN_REG 2: retry -END(immu_miss_user_set_ref) +END(tl0_immu_miss_set_ref) + +ENTRY(tl0_immu_miss_trap) + /* + * Switch to alternate globals. + */ + wrpr %g0, PSTATE_ALT, %pstate -ENTRY(immu_miss_user_call_trap) /* * Load the tar, sfar and sfsr aren't valid. */ - mov AA_IMMU_TAR, %g1 - ldxa [%g1] ASI_IMMU, %g1 + wr %g0, ASI_IMMU, %asi + ldxa [%g0 + AA_IMMU_TAR] %asi, %g2 + +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_immu_miss: trap sp=%#lx tar=%#lx" + , %g3, %g4, %g5, 7, 8, 9) + stx %sp, [%g3 + KTR_PARM1] + stx %g2, [%g3 + KTR_PARM2] +9: +#endif /* - * Save the mmu registers on the stack, switch to alternate globals, - * and call common trap code. + * Save the mmu registers on the stack, and call common trap code. */ - tl0_split_save - mov %g1, %l1 - rdpr %pstate, %l3 - wrpr %l3, PSTATE_AG | PSTATE_MG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_TAR] - rdpr %pil, %o0 - mov T_IMMU_MISS, %o1 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 -END(immu_miss_user_call_trap) + tl0_kstack + sub %sp, MF_SIZEOF, %sp + stx %g2, [%sp + SPOFF + CCFSZ + MF_TAR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl0_trap + mov T_IMMU_MISS, %o0 +END(tl0_immu_miss_trap) .macro dmmu_miss_user /* @@ -502,13 +657,6 @@ END(immu_miss_user_call_trap) nop /* - * If the mod bit is clear, clear the write bit too. - */ - andcc %g7, TD_MOD, %g1 - movz %xcc, TD_W, %g1 - andn %g7, %g1, %g7 - - /* * Load the tte data into the tlb and retry the instruction. */ stxa %g7, [%g0] ASI_DTLB_DATA_IN_REG @@ -534,6 +682,12 @@ ENTRY(dmmu_miss_user_set_ref) bne,a,pn %xcc, 1b mov %g1, %g7 +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_dmmu_miss: set ref" + , %g2, %g3, %g4, 7, 8, 9) +9: +#endif + /* * May have become invalid, in which case start over. */ @@ -541,13 +695,6 @@ ENTRY(dmmu_miss_user_set_ref) nop /* - * If the mod bit is clear, clear the write bit too. - */ - andcc %g1, TD_MOD, %g2 - movz %xcc, TD_W, %g2 - andn %g1, %g2, %g1 - - /* * Load the tte data into the tlb and retry the instruction. */ stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG @@ -556,6 +703,11 @@ END(dmmu_miss_user_set_ref) .macro tl0_dmmu_miss /* + * Force kernel store order. + */ + wrpr %g0, PSTATE_MMU, %pstate + + /* * Try a fast inline lookup of the primary tsb. */ dmmu_miss_user @@ -569,151 +721,49 @@ END(dmmu_miss_user_set_ref) ENTRY(tl0_dmmu_miss_trap) /* - * Load the tar, sfar and sfsr aren't valid. + * Switch to alternate globals. */ - mov AA_DMMU_TAR, %g1 - ldxa [%g1] ASI_DMMU, %g1 + wrpr %g0, PSTATE_ALT, %pstate /* - * Save the mmu registers on the stack, switch to alternate globals, - * and call common trap code. - */ - tl0_split_save - mov %g1, %l1 - rdpr %pstate, %l3 - wrpr %l3, PSTATE_AG | PSTATE_MG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_TAR] - rdpr %pil, %o0 - mov T_DMMU_MISS, %o1 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 -END(tl0_dmmu_miss_trap) - - .macro dmmu_prot_user - /* - * Extract the 8KB pointer and convert to an index. - */ - ldxa [%g0] ASI_DMMU_TSB_8KB_PTR_REG, %g1 - srax %g1, TTE_SHIFT, %g1 - - /* - * Compute the stte address in the primary used tsb. - */ - and %g1, (1 << TSB_PRIMARY_MASK_WIDTH) - 1, %g2 - sllx %g2, TSB_PRIMARY_STTE_SHIFT, %g2 - setx TSB_USER_MIN_ADDRESS, %g4, %g3 - add %g2, %g3, %g2 - - /* - * Preload the tte tag target. - */ - ldxa [%g0] ASI_DMMU_TAG_TARGET_REG, %g3 - - /* - * Preload tte data bits to check inside the bucket loop. - */ - and %g1, TD_VA_LOW_MASK >> TD_VA_LOW_SHIFT, %g4 - sllx %g4, TD_VA_LOW_SHIFT, %g4 - - /* - * Preload mask for tte data check. - */ - setx TD_VA_LOW_MASK, %g5, %g1 - or %g1, TD_W, %g1 - - /* - * Loop over the sttes in this bucket - */ - - /* - * Load the tte. - */ -1: ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %g6 - - /* - * Compare the tag. - */ - cmp %g6, %g3 - bne,pn %xcc, 2f - - /* - * Compare the data. - */ - xor %g7, %g4, %g5 - brgez,pn %g7, 2f - andcc %g5, %g1, %g0 - - /* - * On a match, jump to code to finish up. - */ - bz,pn %xcc, dmmu_prot_user_set_mod - nop - - /* - * Check the low bits to see if we've finished the bucket. - */ -2: add %g2, STTE_SIZEOF, %g2 - andcc %g2, TSB_PRIMARY_STTE_MASK, %g0 - bnz %xcc, 1b - nop - .endm - -ENTRY(dmmu_prot_user_set_mod) - /* - * Set the modify bit. - */ - add %g2, TTE_DATA, %g2 -1: or %g7, TD_MOD, %g1 - casxa [%g2] ASI_N, %g7, %g1 - cmp %g1, %g7 - bne,a,pn %xcc, 1b - mov %g1, %g7 - - /* - * Delete the old tsb entry. + * Load the tar, sfar and sfsr aren't valid. */ wr %g0, ASI_DMMU, %asi - ldxa [%g0 + AA_DMMU_TAR] %asi, %g3 - andn %g3, PAGE_MASK, %g3 - stxa %g0, [%g3] ASI_DMMU_DEMAP + ldxa [%g0 + AA_DMMU_TAR] %asi, %g2 - /* - * May have become invalid, in which case start over. - */ - brgez,pn %g1, 2f - nop +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_dmmu_miss: trap sp=%#lx tar=%#lx" + , %g3, %g4, %g5, 7, 8, 9) + stx %sp, [%g3 + KTR_PARM1] + stx %g2, [%g3 + KTR_PARM2] +9: +#endif /* - * Load the tte data into the tlb, clear the sfsr and retry the - * instruction. + * Save the mmu registers on the stack and call common trap code. */ - stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG - stxa %g0, [%g0 + AA_DMMU_SFSR] %asi -2: retry -END(dmmu_prot_user_set_mod) + tl0_kstack + sub %sp, MF_SIZEOF, %sp + stx %g2, [%sp + SPOFF + CCFSZ + MF_TAR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl0_trap + mov T_DMMU_MISS, %o0 +END(tl0_dmmu_miss_trap) .macro tl0_dmmu_prot /* - * Try a fast inline lookup of the primary tsb. + * Switch to alternate globals. */ - dmmu_prot_user - - /* - * Not in primary tsb, call c code. Nothing else fits inline. - */ - b,a tl0_dmmu_prot_trap - .align 128 - .endm + wrpr %g0, PSTATE_ALT, %pstate -ENTRY(tl0_dmmu_prot_trap) /* * Load the tar, sfar and sfsr. */ wr %g0, ASI_DMMU, %asi ldxa [%g0 + AA_DMMU_SFAR] %asi, %g2 ldxa [%g0 + AA_DMMU_SFSR] %asi, %g3 - ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 + ldxa [%g0 + AA_DMMU_TAR] %asi, %g4 stxa %g0, [%g0 + AA_DMMU_SFSR] %asi membar #Sync @@ -721,115 +771,129 @@ ENTRY(tl0_dmmu_prot_trap) * Save the mmu registers on the stack, switch to alternate globals, * and call common trap code. */ - tl0_split_save - mov %g1, %l1 - mov %g2, %l2 - mov %g3, %l3 - rdpr %pstate, %l4 - wrpr %l4, PSTATE_AG | PSTATE_MG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_TAR] - stx %l2, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFAR] - stx %l3, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFSR] - rdpr %pil, %o0 - mov T_DMMU_PROT, %o1 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 -END(tl0_dmmu_prot_trap) + tl0_kstack + sub %sp, MF_SIZEOF, %sp + stx %g2, [%sp + SPOFF + CCFSZ + MF_TAR] + stx %g3, [%sp + SPOFF + CCFSZ + MF_SFAR] + stx %g4, [%sp + SPOFF + CCFSZ + MF_SFSR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl0_trap + mov T_DMMU_PROT, %o0 + .align 128 + .endm .macro tl0_spill_0_n - ldx [PCPU(CURPCB)], %g1 - stx %g1, [%g1 + PCB_INWINOP] ! something != 0 - wr %g0, ASI_AIUP, %asi - SPILL(stxa, %sp + SPOFF, %asi, F) - stx %g0, [%g1 + PCB_INWINOP] + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: SPILL(stxa, %sp + SPOFF, 8, %asi) saved + wrpr %g0, WSTATE_ASSUME64, %wstate retry - .align 128 + .align 32 + RSF_TRAP(T_SPILL) + RSF_TRAP(T_SPILL) .endm - .macro tl0_spill_0_o - b,a tl0_spill_frompcb - .align 128 - .endm - -#define LDSTA(tmp, from, to) \ - ldx [from], tmp ; \ - stxa tmp, [to] %asi + .macro tl0_spill_1_n + andcc %sp, 1, %g0 + bnz %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + wrpr %g0, WSTATE_ASSUME32, %wstate + retry + .align 32 + RSF_TRAP(T_SPILL) + RSF_TRAP(T_SPILL) + .endm -/* - * A window that was spilled to the pcb during the last trap, was marked with - * %otherwin, but was not filled back in again yet. In this case, we need to - * spill the data from the pcb directly to user space. Traps while writing to - * user space are handled as normally. - */ -ENTRY(tl0_spill_frompcb) - ldx [PCPU(CURPCB)], %g1 - /* We may fault while spilling to user space, prepare for that. */ - stx %g1, [%g1 + PCB_INWINOP] ! something != 0 - rdpr %cwp, %g2 - mulx %g2, WSF_SIZEOF, %g3 - add %g1, %g3, %g3 - ldx [%g3 + PCB_WSCRATCH + WSF_SP], %g4 + .macro tl0_spill_2_n wr %g0, ASI_AIUP, %asi - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I0, %g4 + SPOFF + F_I0) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I1, %g4 + SPOFF + F_I1) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I2, %g4 + SPOFF + F_I2) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I3, %g4 + SPOFF + F_I3) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I4, %g4 + SPOFF + F_I4) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I5, %g4 + SPOFF + F_I5) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I6, %g4 + SPOFF + F_I6) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I7, %g4 + SPOFF + F_I7) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L0, %g4 + SPOFF + F_L0) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L1, %g4 + SPOFF + F_L1) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L2, %g4 + SPOFF + F_L2) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L3, %g4 + SPOFF + F_L3) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L4, %g4 + SPOFF + F_L4) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L5, %g4 + SPOFF + F_L5) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L6, %g4 + SPOFF + F_L6) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L7, %g4 + SPOFF + F_L7) - stx %g0, [%g1 + PCB_INWINOP] - /* wscratch window becomes unused. */ - stx %g0, [%g3 + WSF_INUSE] - rdpr %otherwin, %g4 - sub %g4, 1, %g4 - stx %g4, [%g1 + PCB_WS_INUSE] + SPILL(stxa, %sp + SPOFF, 8, %asi) saved retry -END(tl0_spill_frompcb) + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST32) + RSF_TRAP(T_SPILL) + .endm - .macro tl0_spill_bad count - .rept \count - tl0_wide T_SPILL - .endr + .macro tl0_spill_3_n + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST64) + RSF_TRAP(T_SPILL) .endm .macro tl0_fill_0_n - ldx [PCPU(CURPCB)], %g1 - stx %g1, [%g1 + PCB_INWINOP] ! something != 0 + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: FILL(ldxa, %sp + SPOFF, 8, %asi) + restored + wrpr %g0, WSTATE_ASSUME64, %wstate + retry + .align 32 + RSF_TRAP(T_FILL) + RSF_TRAP(T_FILL) + .endm + + .macro tl0_fill_1_n + andcc %sp, 1, %g0 + bnz %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + FILL(lduwa, %sp, 4, %asi) + restored + wrpr %g0, WSTATE_ASSUME32, %wstate + retry + .align 32 + RSF_TRAP(T_FILL) + RSF_TRAP(T_FILL) + .endm + + .macro tl0_fill_2_n wr %g0, ASI_AIUP, %asi - FILL(ldxa, %sp + SPOFF, %asi, F) - stx %g0, [%g1 + PCB_INWINOP] + FILL(ldxa, %sp + SPOFF, 8, %asi) restored retry - .align 128 + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST32) + RSF_TRAP(T_FILL) .endm - .macro tl0_fill_0_o - ldx [PCPU(CURPCB)], %g1 - rdpr %cwp, %g2 - mulx %g2, WSF_SIZEOF, %g3 - add %g1, %g3, %g3 - FILL(ldx, %g3 + PCB_WSCRATCH, EMPTY, WSF) - /* wscratch window becomes unused. */ - stx %g0, [%g3 + PCB_WSCRATCH + WSF_INUSE] - rdpr %otherwin, %g4 - sub %g4, 1, %g4 - stx %g4, [%g1 + PCB_WS_INUSE] + .macro tl0_fill_3_n + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + FILL(lduwa, %sp, 4, %asi) restored retry - .align 128 - .endm + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST64) + RSF_TRAP(T_FILL) + .endm + +ENTRY(tl0_sftrap) + rdpr %tstate, %g1 + and %g1, TSTATE_CWP_MASK, %g1 + wrpr %g1, 0, %cwp + tl0_kstack + rdpr %pil, %o2 + b %xcc, tl0_trap + mov %g2, %o0 +END(tl0_sftrap) + + .macro tl0_spill_bad count + .rept \count + tl0_wide T_SPILL + .endr + .endm .macro tl0_fill_bad count .rept \count @@ -838,22 +902,29 @@ END(tl0_spill_frompcb) .endm .macro tl0_soft count - tl0_reserved \count + .rept \count + tl0_gen T_SOFT + .endr .endm - .macro tl1_gen type + .macro tl1_kstack save %sp, -CCFSZ, %sp - rdpr %pil, %o0 + .endm + + .macro tl1_setup type + tl1_kstack + mov \type | T_KERNEL, %o0 b %xcc, tl1_trap - mov \type | T_KERNEL, %o1 + rdpr %pil, %o2 + .endm + + .macro tl1_gen type + tl1_setup \type .align 32 .endm .macro tl1_wide type - save %sp, -CCFSZ, %sp - rdpr %pil, %o0 - b %xcc, tl1_trap - mov \type | T_KERNEL, %o1 + tl1_setup \type .align 128 .endm @@ -864,103 +935,78 @@ END(tl0_spill_frompcb) .endm .macro tl1_insn_excptn - save %sp, -CCFSZ, %sp - rdpr %pstate, %o0 - wrpr %o0, PSTATE_MG | PSTATE_AG, %pstate - rdpr %pil, %o0 + tl1_kstack + wrpr %g0, PSTATE_ALT, %pstate + rdpr %pil, %o2 b %xcc, tl1_trap - mov T_INSN_EXCPTN | T_KERNEL, %o1 + mov T_INSN_EXCPTN | T_KERNEL, %o0 .align 32 .endm .macro tl1_data_excptn - b %xcc, tl1_sfsr_trap - mov T_DATA_EXCPTN, %g4 + b,a %xcc, tl1_data_exceptn_trap + nop .align 32 .endm - .macro tl1_align - rdpr %pstate, %g1 - wrpr %g1, PSTATE_MG | PSTATE_AG, %pstate +ENTRY(tl1_data_exceptn_trap) + wr %g0, ASI_DMMU, %asi + RESUME_SPILLFILL_MAGIC(%g1, %g2, RSF_MMU, 1f) + stxa %g0, [%g0 + AA_DMMU_SFSR] %asi + done + +1: wrpr %g0, PSTATE_ALT, %pstate b %xcc, tl1_sfsr_trap - mov T_ALIGN, %g4 + mov T_DATA_EXCPTN | T_KERNEL, %g1 +END(tl1_data_exceptn) + + /* + * NOTE: We switch to mmu globals here, to avoid needing to save + * alternates, which may be live. + */ + .macro tl1_align + b %xcc, tl1_align_trap + wrpr %g0, PSTATE_MMU, %pstate .align 32 .endm -/* - * Handle traps that require only sfsr and sfar to be saved. %g4 holds the trap - * type to be used (T_KERNEL is set if appropriate). - * Call with memory globals active. - */ -ENTRY(tl1_sfsr_trap) +ENTRY(tl1_align_trap) wr %g0, ASI_DMMU, %asi + RESUME_SPILLFILL_MAGIC(%g1, %g2, RSF_ALIGN, 1f) + stxa %g0, [%g0 + AA_DMMU_SFSR] %asi + done + +1: wrpr %g0, PSTATE_ALT, %pstate + b %xcc, tl1_sfsr_trap + mov T_ALIGN | T_KERNEL, %g1 +END(tl1_align_trap) + +ENTRY(tl1_sfsr_trap) +! wr %g0, ASI_DMMU, %asi ldxa [%g0 + AA_DMMU_SFAR] %asi, %g2 ldxa [%g0 + AA_DMMU_SFSR] %asi, %g3 stxa %g0, [%g0 + AA_DMMU_SFSR] %asi membar #Sync - /* Fall through. */ -END(tl1_sfsr_trap) -/* - * Handle traps that require MMU frames to be written. The values for TAR, SFAR - * and SFSR are passed in %g1, %g2 and %g3, respectively. - * All traps that may happen during spill/fill for user processes should be - * handled here. - * %g4 contains the trap type, T_KERNEL is set if appropriate. - */ -ENTRY(tl1_mmu_trap) - /* Handle faults during window spill/fill. */ - mov %o1, %g5 - mov %o2, %g6 - rdpr %pstate, %o1 - wrpr %o1, PSTATE_MG | PSTATE_AG, %pstate - ldx [PCPU(CURPCB)], %o2 - ldx [%o2 + PCB_INWINOP], %o2 - rdpr %pstate, %o1 - wrpr %o1, PSTATE_MG | PSTATE_AG, %pstate - mov %g5, %o1 - brz,pt %o2, 1f - mov %g6, %o2 - - wrpr 1, %tl ! go to tl 1 - rdpr %tstate, %g5 - and %g5, TSTATE_CWP_MASK, %g5 - wrpr %g5, %cwp - tl0_split_save - mov %g1, %l1 - mov %g2, %l2 - mov %g3, %l3 - mov %g4, %o1 - rdpr %pstate, %l4 - wrpr %l4, PSTATE_MG | PSTATE_AG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_TAR] - stx %l2, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFAR] - stx %l3, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFSR] - rdpr %pil, %o0 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 - -1: save %sp, -(CCFSZ + MF_SIZEOF), %sp - stx %g1, [%sp + SPOFF + CCFSZ + MF_TAR] + tl1_kstack + sub %sp, MF_SIZEOF, %sp stx %g2, [%sp + SPOFF + CCFSZ + MF_SFAR] stx %g3, [%sp + SPOFF + CCFSZ + MF_SFSR] - or %g4, T_KERNEL, %o1 - rdpr %pstate, %g1 - wrpr %g1, PSTATE_MG | PSTATE_AG, %pstate - rdpr %pil, %o0 + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 b %xcc, tl1_trap - add %sp, SPOFF + CCFSZ, %o2 -END(tl1_mmu_trap) + mov %g1, %o0 +END(tl1_align_trap) .macro tl1_intr level, mask, type - save %sp, -CCFSZ, %sp - rdpr %pil, %o0 + tl1_kstack + rdpr %pil, %o2 wrpr %g0, \level, %pil - set \mask, %o2 - wr %o2, 0, %asr21 + set \mask, %o3 + wr %o3, 0, %asr21 + mov T_INTR | T_KERNEL, %o0 b %xcc, tl1_trap - mov \type | T_KERNEL, %o1 + mov \level, %o1 .align 32 .endm @@ -974,6 +1020,21 @@ END(tl1_mmu_trap) .endm ENTRY(intr_enqueue) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "intr_enqueue: p=%p (%s) tl=%#lx pc=%#lx sp=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + ldx [PCPU(CURPROC)], %g2 + stx %g2, [%g1 + KTR_PARM1] + add %g2, P_COMM, %g2 + stx %g2, [%g1 + KTR_PARM2] + rdpr %tl, %g2 + stx %g2, [%g1 + KTR_PARM3] + rdpr %tpc, %g2 + stx %g2, [%g1 + KTR_PARM4] + stx %sp, [%g1 + KTR_PARM5] +9: +#endif + /* * Find the head of the queue and advance it. */ @@ -983,6 +1044,19 @@ ENTRY(intr_enqueue) and %g3, IQ_MASK, %g3 stx %g3, [%g1 + IQ_HEAD] +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "intr_enqueue: cpu=%d head=%d tail=%d iqe=%d" + , %g4, %g5, %g6, 7, 8, 9) + lduw [PCPU(CPUID)], %g5 + stx %g5, [%g4 + KTR_PARM1] + stx %g3, [%g4 + KTR_PARM2] + ldx [%g1 + IQ_TAIL], %g5 + stx %g5, [%g4 + KTR_PARM3] + stx %g2, [%g4 + KTR_PARM4] +9: +#endif + +#ifdef INVARIANTS /* * If the new head is the same as the tail, the next interrupt will * overwrite unserviced packets. This is bad. @@ -991,6 +1065,7 @@ ENTRY(intr_enqueue) cmp %g4, %g3 be %xcc, 3f nop +#endif /* * Load the interrupt packet from the hardware. @@ -1047,6 +1122,21 @@ ENTRY(intr_enqueue) mov 1, %g3 sllx %g3, %g4, %g3 wr %g3, 0, %asr20 + +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "intr_enqueue: tag=%#lx vec=%#lx pri=%d func=%p arg=%p" + , %g1, %g3, %g4, 7, 8, 9) + lduw [%g2 + IQE_TAG], %g3 + stx %g3, [%g1 + KTR_PARM1] + ldx [%g2 + IQE_VEC], %g3 + stx %g3, [%g1 + KTR_PARM2] + lduw [%g2 + IQE_PRI], %g3 + stx %g3, [%g1 + KTR_PARM3] + stx %g5, [%g1 + KTR_PARM4] + stx %g6, [%g1 + KTR_PARM5] +9: +#endif + retry /* @@ -1056,19 +1146,20 @@ ENTRY(intr_enqueue) */ 2: DEBUGGER() +#ifdef INVARIANTS /* * The interrupt queue is about to overflow. We are in big trouble. */ 3: DEBUGGER() +#endif END(intr_enqueue) .macro tl1_immu_miss - save %sp, -CCFSZ, %sp - rdpr %pstate, %o0 - wrpr %o0, PSTATE_MG | PSTATE_AG, %pstate - rdpr %pil, %o0 + wrpr %g0, PSTATE_ALT, %pstate + tl1_kstack + rdpr %pil, %o2 b %xcc, tl1_trap - mov T_IMMU_MISS | T_KERNEL, %o1 + mov T_IMMU_MISS | T_KERNEL, %o0 .align 128 .endm @@ -1115,19 +1206,27 @@ END(intr_enqueue) stx %g1, [%g2 + ST_TTE + TTE_DATA] /* - * If the mod bit is clear, clear the write bit too. + * Load the tte data into the TLB and retry the instruction. */ -1: andcc %g5, TD_MOD, %g1 - movz %xcc, TD_W, %g1 - andn %g5, %g1, %g5 +1: stxa %g5, [%g0] ASI_DTLB_DATA_IN_REG + retry /* - * Load the tte data into the TLB and retry the instruction. + * Switch to alternate globals. */ - stxa %g5, [%g0] ASI_DTLB_DATA_IN_REG - retry +2: wrpr %g0, PSTATE_ALT, %pstate -2: b,a %xcc, tl1_dmmu_miss_trap + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 + + tl1_kstack + sub %sp, MF_SIZEOF, %sp + stx %g1, [%sp + SPOFF + CCFSZ + MF_TAR] + wrpr %g0, PSTATE_ALT, %pstate + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl1_trap + mov T_DMMU_MISS | T_KERNEL, %o0 .align 128 .endm @@ -1137,217 +1236,290 @@ ENTRY(tl1_dmmu_miss_user) */ dmmu_miss_user - /* Fallthrough. */ -END(tl1_dmmu_miss_user) + /* Handle faults during window spill/fill. */ + RESUME_SPILLFILL_MAGIC(%g1, %g2, RSF_MMU, 1f) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl1_dmmu_miss_user: resume spillfill npc=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + rdpr %tnpc, %g2 + stx %g2, [%g1 + KTR_PARM1] +9: +#endif + done +1: -ENTRY(tl1_dmmu_miss_trap) - /* - * Not in primary tsb, call c code. - * Load the tar, sfar and sfsr aren't valid. - */ - mov AA_DMMU_TAR, %g1 - ldxa [%g1] ASI_DMMU, %g1 - b %xcc, tl1_mmu_trap - mov T_DMMU_MISS, %g4 -END(tl1_dmmu_miss_user) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl1_dmmu_miss_user: trap", %g1, %g2, %g3, 7, 8, 9) +9: +#endif - .macro tl1_dmmu_prot /* - * Load the target tte tag, and extract the context. If the context - * is non-zero handle as user space access. In either case, load the - * tsb 8k pointer. + * Switch to alternate globals. */ - ldxa [%g0] ASI_DMMU_TAG_TARGET_REG, %g1 - srlx %g1, TT_CTX_SHIFT, %g2 - brnz,pn %g2, tl1_dmmu_prot_user - ldxa [%g0] ASI_DMMU_TSB_8KB_PTR_REG, %g2 + wrpr %g0, PSTATE_ALT, %pstate - /* - * Convert the tte pointer to an stte pointer, and add extra bits to - * accomodate for large tsb. - */ - sllx %g2, STTE_SHIFT - TTE_SHIFT, %g2 -#ifdef notyet - mov AA_DMMU_TAR, %g3 - ldxa [%g3] ASI_DMMU, %g3 - srlx %g3, TSB_1M_STTE_SHIFT, %g3 - and %g3, TSB_KERNEL_MASK >> TSB_1M_STTE_SHIFT, %g3 - sllx %g3, TSB_1M_STTE_SHIFT, %g3 - add %g2, %g3, %g2 + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl1_dmmu_miss: trap sp=%#lx tar=%#lx" + , %g2, %g3, %g4, 7, 8, 9) + stx %sp, [%g2 + KTR_PARM1] + stx %g1, [%g2 + KTR_PARM2] +9: #endif - /* - * Load the tte, check that it's valid, writeable, and that the - * tags match. - */ - ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %g4 - brgez,pn %g5, 2f - andcc %g5, TD_W, %g0 - bz,pn %xcc, 2f - cmp %g4, %g1 - bne %xcc, 2f - EMPTY - - /* - * Set the mod bit in the tte. - */ - or %g5, TD_MOD, %g5 - stx %g5, [%g2 + TTE_DATA] + tl1_kstack + sub %sp, MF_SIZEOF, %sp + stx %g1, [%sp + SPOFF + CCFSZ + MF_TAR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl1_trap + mov T_DMMU_MISS | T_KERNEL, %o0 +END(tl1_dmmu_miss_user) - /* - * Delete the old tlb entry. - */ + .macro tl1_dmmu_prot wr %g0, ASI_DMMU, %asi - ldxa [%g0 + AA_DMMU_TAR] %asi, %g6 - or %g6, TLB_DEMAP_NUCLEUS, %g6 - stxa %g0, [%g6] ASI_DMMU_DEMAP - - /* - * Load the tte data into the tlb, clear the sfsr and retry the - * instruction. - */ - stxa %g5, [%g0] ASI_DTLB_DATA_IN_REG + RESUME_SPILLFILL_MAGIC(%g1, %g2, RSF_MMU, 1f) stxa %g0, [%g0 + AA_DMMU_SFSR] %asi - retry + done /* - * For now just bail. This might cause a red state exception, - * but oh well. - */ -2: DEBUGGER() - .align 128 - .endm - -ENTRY(tl1_dmmu_prot_user) - /* - * Try a fast inline lookup of the primary tsb. + * Switch to alternate globals. */ - dmmu_prot_user +1: wrpr %g0, PSTATE_ALT, %pstate /* - * Not in primary tsb, call c code. * Load the sfar, sfsr and tar. Clear the sfsr. */ - wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 ldxa [%g0 + AA_DMMU_SFAR] %asi, %g2 ldxa [%g0 + AA_DMMU_SFSR] %asi, %g3 - ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 stxa %g0, [%g0 + AA_DMMU_SFSR] %asi membar #Sync - b %xcc, tl1_mmu_trap - mov T_DMMU_PROT, %g4 -END(tl1_dmmu_prot_user) + tl1_kstack + sub %sp, MF_SIZEOF, %sp + stx %g1, [%sp + SPOFF + CCFSZ + MF_TAR] + stx %g2, [%sp + SPOFF + CCFSZ + MF_SFAR] + stx %g3, [%sp + SPOFF + CCFSZ + MF_SFSR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl1_trap + mov T_DMMU_PROT | T_KERNEL, %o0 + .align 128 + .endm .macro tl1_spill_0_n - SPILL(stx, %sp + SPOFF, EMPTY, F) + SPILL(stx, %sp + SPOFF, 8, EMPTY) saved retry - .align 128 + .align 32 + RSF_FATAL(T_SPILL) + RSF_FATAL(T_SPILL) .endm - .macro tl1_spill_1_n - b,a tl1_spill_topcb - .align 128 + .macro tl1_spill_4_n + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: SPILL(stxa, %sp + SPOFF, 8, %asi) + saved + retry + .align 32 + RSF_SPILL_TOPCB + RSF_SPILL_TOPCB + .endm + + .macro tl1_spill_5_n + andcc %sp, 1, %g0 + bnz %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + retry + .align 32 + RSF_SPILL_TOPCB + RSF_SPILL_TOPCB + .endm + + .macro tl1_spill_6_n + wr %g0, ASI_AIUP, %asi + SPILL(stxa, %sp + SPOFF, 8, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TRANSITION | WSTATE_TEST32) + RSF_SPILL_TOPCB + .endm + + .macro tl1_spill_7_n + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TRANSITION | WSTATE_TEST64) + RSF_SPILL_TOPCB .endm - /* - * The following is equivalent to tl1_spill_1_n and is used for - * splitting. - */ .macro tl1_spill_0_o - tl1_spill_1_n + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: SPILL(stxa, %sp + SPOFF, 8, %asi) + saved + wrpr %g0, WSTATE_ASSUME64 << WSTATE_USERSHIFT, %wstate + retry + .align 32 + RSF_SPILL_TOPCB + RSF_SPILL_TOPCB .endm - -/* - * This is used to spill windows that are still occupied with user - * data on kernel entry to the pcb using tl0_flush_save. - */ -ENTRY(tl1_spill_topcb) - /* Free some globals for our use. */ - sub %g6, 32, %g6 - stx %g1, [%g6] - stx %g2, [%g6 + 8] - stx %g3, [%g6 + 16] - stx %g4, [%g6 + 24] - ldx [PCPU(CURPCB)], %g1 - rdpr %cwp, %g2 - mulx %g2, WSF_SIZEOF, %g3 - add %g1, %g3, %g3 - ldx [%g3 + PCB_WSCRATCH + WSF_INUSE], %g4 - brnz,pn %g4, 1f ! window was already spilled to pcb - stx %g1, [%g3 + PCB_WSCRATCH + WSF_INUSE] ! just write sth. != 0 - stx %sp, [%g3 + PCB_WSCRATCH + WSF_SP] - SPILL(stx, %g3 + PCB_WSCRATCH, EMPTY, WSF) - ldx [%g1 + PCB_WS_INUSE], %g4 - add %g4, 1, %g4 - stx %g4, [%g1 + PCB_WS_INUSE] -1: ldx [%g6], %g1 - ldx [%g6 + 8], %g2 - ldx [%g6 + 16], %g3 - ldx [%g6 + 24], %g4 - add %g6, 32, %g6 + + .macro tl1_spill_1_o + andcc %sp, 1, %g0 + bnz %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) saved + wrpr %g0, WSTATE_ASSUME32 << WSTATE_USERSHIFT, %wstate retry -END(tl1_spill_topcb) + .align 32 + RSF_SPILL_TOPCB + RSF_SPILL_TOPCB + .endm - .macro tl1_spill_bad count - .rept \count - tl1_wide T_SPILL - .endr + .macro tl1_spill_2_o + wr %g0, ASI_AIUP, %asi + SPILL(stxa, %sp + SPOFF, 8, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST32 << WSTATE_USERSHIFT) + RSF_SPILL_TOPCB + .endm + + .macro tl1_spill_3_o + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST64 << WSTATE_USERSHIFT) + RSF_SPILL_TOPCB .endm .macro tl1_fill_0_n - FILL(ldx, %sp + SPOFF, EMPTY, F) + FILL(ldx, %sp + SPOFF, 8, EMPTY) restored retry - .align 128 + .align 32 + RSF_FATAL(T_FILL) + RSF_FATAL(T_FILL) .endm - .macro tl1_fill_1_n - b,a tl1_fill_frompcb - .align 128 + .macro tl1_fill_4_n + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: FILL(ldxa, %sp + SPOFF, 8, %asi) + restored + retry + .align 32 + RSF_FILL_MAGIC + RSF_FILL_MAGIC .endm - /* Same as tl1_fill_1_n, used for splitting. */ - .macro tl1_fill_0_o - tl1_fill_1_n + .macro tl1_fill_5_n + andcc %sp, 1, %g0 + bnz,pn %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + FILL(lduwa, %sp, 4, %asi) + restored + retry + .align 32 + RSF_FILL_MAGIC + RSF_FILL_MAGIC + .endm + + .macro tl1_fill_6_n + wr %g0, ASI_AIUP, %asi + FILL(ldxa, %sp + SPOFF, 8, %asi) + restored + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST32 | WSTATE_TRANSITION) + RSF_FILL_MAGIC + .endm + + .macro tl1_fill_7_n + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + FILL(lduwa, %sp, 4, %asi) + restored + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST64 | WSTATE_TRANSITION) + RSF_FILL_MAGIC .endm /* - * This is invoked only once when a user process is in the kernel: - * to restore the topmost window on user return. We just look up whether - * the window at %cwp was already spilled to the pcb (as inducated by the - * wsf_inuse flag). If so, we indeed need to fill from the pcb, otherwise the - * window is valid and we can just return. + * This is used to spill windows that are still occupied with user + * data on kernel entry to the pcb. */ -ENTRY(tl1_fill_frompcb) +ENTRY(tl1_spill_topcb) + wrpr %g0, PSTATE_ALT, %pstate + /* Free some globals for our use. */ - sub %g6, 32, %g6 + sub %g6, 24, %g6 stx %g1, [%g6] stx %g2, [%g6 + 8] stx %g3, [%g6 + 16] - stx %g4, [%g6 + 24] + ldx [PCPU(CURPCB)], %g1 - rdpr %cwp, %g2 - mulx %g2, WSF_SIZEOF, %g3 - add %g1, %g3, %g3 - ldx [%g3 + PCB_WSCRATCH + WSF_INUSE], %g4 - brz,pn %g4, 1f ! window not spilled and is valid - stx %g0, [%g3 + PCB_WSCRATCH + WSF_INUSE] - FILL(ldx, %g3 + PCB_WSCRATCH, EMPTY, WSF) - ldx [%g1 + PCB_WS_INUSE], %g4 - sub %g4, 1, %g4 - stx %g4, [%g1 + PCB_WS_INUSE] - /* Restore the registers. */ -1: ldx [%g6], %g1 - ldx [%g6 + 8], %g2 + ldx [%g1 + PCB_NSAVED], %g2 + + sllx %g2, 3, %g3 + add %g3, %g1, %g3 + stx %sp, [%g3 + PCB_RWSP] + + sllx %g2, 7, %g3 + add %g3, %g1, %g3 + SPILL(stx, %g3 + PCB_RW, 8, EMPTY) + + inc %g2 + stx %g2, [%g1 + PCB_NSAVED] + +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl1_spill_topcb: pc=%lx sp=%#lx nsaved=%d" + , %g1, %g2, %g3, 7, 8, 9) + rdpr %tpc, %g2 + stx %g2, [%g1 + KTR_PARM1] + stx %sp, [%g1 + KTR_PARM2] + ldx [PCPU(CURPCB)], %g2 + ldx [%g2 + PCB_NSAVED], %g2 + stx %g2, [%g1 + KTR_PARM3] +9: +#endif + + saved + ldx [%g6 + 16], %g3 - ldx [%g6 + 24], %g4 - add %g6, 32, %g6 - restored + ldx [%g6 + 8], %g2 + ldx [%g6], %g1 + add %g6, 24, %g6 retry -END(tl1_fill_frompcb) +END(tl1_spill_topcb) + + .macro tl1_spill_bad count + .rept \count + tl1_wide T_SPILL + .endr + .endm .macro tl1_fill_bad count .rept \count @@ -1361,17 +1533,20 @@ END(tl1_fill_frompcb) .endm ENTRY(tl1_breakpoint_trap) - save %sp, -(CCFSZ + KF_SIZEOF), %sp + tl1_kstack + sub %sp, KF_SIZEOF, %sp flushw stx %fp, [%sp + SPOFF + CCFSZ + KF_FP] - rdpr %pil, %o0 - mov T_BREAKPOINT | T_KERNEL, %o1 + mov T_BREAKPOINT | T_KERNEL, %o0 + add %sp, SPOFF + CCFSZ, %o1 b %xcc, tl1_trap - add %sp, SPOFF + CCFSZ, %o2 + rdpr %pil, %o2 END(tl1_breakpoint_trap) .macro tl1_soft count - tl1_reserved \count + .rept \count + tl1_gen T_SOFT | T_KERNEL + .endr .endm .sect .trap @@ -1416,7 +1591,7 @@ tl0_divide: tl0_gen T_DIVIDE ! 0x28 division by zero tl0_reserved 7 ! 0x29-0x2f reserved tl0_data_excptn: - tl0_gen T_DATA_EXCPTN ! 0x30 data access exception + tl0_data_excptn ! 0x30 data access exception tl0_reserved 1 ! 0x31 reserved tl0_data_error: tl0_gen T_DATA_ERROR ! 0x32 data access error @@ -1450,26 +1625,28 @@ tl0_dmmu_prot: tl0_reserved 16 ! 0x70-0x7f reserved tl0_spill_0_n: tl0_spill_0_n ! 0x80 spill 0 normal -tl0_spill_bad_n: - tl0_spill_bad 7 ! 0x84-0x9f spill normal, other -tl0_spill_0_o: - tl0_spill_0_o ! 0xa0 spill 0 other -tl0_spill_bad_o: - tl0_spill_bad 7 ! 0xa4-0xbf spill normal, other +tl0_spill_1_n: + tl0_spill_1_n ! 0x84 spill 1 normal +tl0_spill_2_n: + tl0_spill_2_n ! 0x88 spill 2 normal +tl0_spill_3_n: + tl0_spill_3_n ! 0x8c spill 3 normal + tl0_spill_bad 12 ! 0x90-0xbf spill normal, other tl0_fill_0_n: tl0_fill_0_n ! 0xc0 fill 0 normal -tl0_fill_bad_n: - tl0_fill_bad 7 ! 0xc4-0xdf fill normal -tl0_fill_0_o: - tl0_fill_0_o ! 0xe0 fill 0 normal -tl0_fill_bad_o: - tl0_fill_bad 7 ! 0xe4-0xff fill other +tl0_fill_1_n: + tl0_fill_1_n ! 0xc4 fill 1 normal +tl0_fill_2_n: + tl0_fill_2_n ! 0xc8 fill 2 normal +tl0_fill_3_n: + tl0_fill_3_n ! 0xcc fill 3 normal + tl0_fill_bad 12 ! 0xc4-0xff fill normal, other tl0_sun_syscall: tl0_reserved 1 ! 0x100 sun system call tl0_breakpoint: tl0_gen T_BREAKPOINT ! 0x101 breakpoint - tl0_soft 7 ! 0x102-0x107 trap instruction - tl0_reserved ! 0x109 SVr4 syscall + tl0_soft 6 ! 0x102-0x107 trap instruction + tl0_soft 1 ! 0x108 SVr4 syscall tl0_gen T_SYSCALL ! 0x109 BSD syscall tl0_soft 118 ! 0x110-0x17f trap instruction tl0_reserved 128 ! 0x180-0x1ff reserved @@ -1546,50 +1723,73 @@ tl1_dmmu_prot: tl1_reserved 16 ! 0x270-0x27f reserved tl1_spill_0_n: tl1_spill_0_n ! 0x280 spill 0 normal -tl1_spill_1_n: - tl1_spill_1_n ! 0x284 spill 1 normal -tl1_spill_bad_n: - tl1_spill_bad 6 ! 0x288-0x29f spill normal + tl1_spill_bad 3 ! 0x284-0x28f spill normal +tl1_spill_4_n: + tl1_spill_4_n ! 0x290 spill 4 normal +tl1_spill_5_n: + tl1_spill_5_n ! 0x294 spill 5 normal +tl1_spill_6_n: + tl1_spill_6_n ! 0x298 spill 6 normal +tl1_spill_7_n: + tl1_spill_7_n ! 0x29c spill 7 normal tl1_spill_0_o: tl1_spill_0_o ! 0x2a0 spill 0 other -tl1_spill_bad_o: - tl1_spill_bad 7 ! 0x2a8-0x2bf spill other +tl1_spill_1_o: + tl1_spill_1_o ! 0x2a4 spill 1 other +tl1_spill_2_o: + tl1_spill_2_o ! 0x2a8 spill 2 other +tl1_spill_3_o: + tl1_spill_3_o ! 0x2ac spill 3 other + tl1_spill_bad 4 ! 0x2a0-0x2bf spill other tl1_fill_0_n: tl1_fill_0_n ! 0x2c0 fill 0 normal -tl1_fill_1_n: - tl1_fill_1_n ! 0x2c4 fill 1 normal -tl1_fill_bad_n: - tl1_fill_bad 6 ! 0x2c8-0x2df fill normal, other -tl1_fill_0_o: - tl1_fill_0_o ! 0x2e0 fill 0 other -tl1_fill_bad_o: - tl1_fill_bad 7 ! 0x2e4-0x2ff fill other + tl1_fill_bad 3 ! 0x2c4-0x2cf fill normal +tl1_fill_4_n: + tl1_fill_4_n ! 0x2d0 fill 4 normal +tl1_fill_5_n: + tl1_fill_5_n ! 0x2d4 fill 5 normal +tl1_fill_6_n: + tl1_fill_6_n ! 0x2d8 fill 6 normal +tl1_fill_7_n: + tl1_fill_7_n ! 0x2dc fill 7 normal + tl1_fill_bad 8 ! 0x2e0-0x2ff fill other tl1_reserved 1 ! 0x300 trap instruction tl1_breakpoint: tl1_breakpoint ! 0x301 breakpoint tl1_gen T_RESTOREWP ! 0x302 restore watchpoint (debug) - tl1_soft 126 ! 0x303-0x37f trap instruction + tl1_soft 125 ! 0x303-0x37f trap instruction tl1_reserved 128 ! 0x380-0x3ff reserved /* - * void tl0_trap(u_long o0, u_long o1, u_long o2, u_long type) + * User trap entry point. + * + * void tl0_trap(u_long type, u_long arg, u_long pil, u_long wstate) + * + * The following setup has been performed: + * - the windows have been split and the active user window has been saved + * (maybe just to the pcb) + * - we are on the current kernel stack and a frame has been setup, there + * may be extra trap specific stuff below the frame + * - we are on alternate globals and interrupts are disabled + * + * We build a trapframe, switch to normal globals, enable interrupts and call + * trap. + * + * NOTE: Due to a chip bug, we must save the trap state registers in memory + * early. + * + * NOTE: We must be very careful setting up the per-cpu pointer. We know that + * it has been pre-set in alternate globals, so we read it from there and setup + * the normal %g7 *before* enabling interrupts. This avoids any possibility + * of cpu migration and using the wrong globalp. */ ENTRY(tl0_trap) - tl0_setup_stack %l0, 0 - /* Fallthrough */ -END(tl0_trap) + /* + * Force kernel store order. + */ + wrpr %g0, PSTATE_ALT, %pstate -ENTRY(tl0_trap_withstack) - ldx [PCPU(CURPCB)], %l1 - rdpr %cwp, %l2 - stx %l2, [%l1 + PCB_CWP] - /* Finish setting up splitted windows. */ - wrpr %g0, 0, %wstate - rdpr %canrestore, %l0 - rdpr %otherwin, %l1 - add %l0, %l1, %l0 - wrpr %g0, 0, %canrestore - wrpr %l0, %otherwin + sub %sp, TF_SIZEOF, %sp rdpr %tstate, %l0 stx %l0, [%sp + SPOFF + CCFSZ + TF_TSTATE] @@ -1598,9 +1798,16 @@ ENTRY(tl0_trap_withstack) rdpr %tnpc, %l2 stx %l2, [%sp + SPOFF + CCFSZ + TF_TNPC] + stx %o0, [%sp + SPOFF + CCFSZ + TF_TYPE] + stx %o1, [%sp + SPOFF + CCFSZ + TF_ARG] + stx %o2, [%sp + SPOFF + CCFSZ + TF_PIL] + stx %o3, [%sp + SPOFF + CCFSZ + TF_WSTATE] + +.Ltl0_trap_fill: mov %g7, %l0 - rdpr %pstate, %l1 - wrpr %l1, PSTATE_AG, %pstate + wrpr %g0, PSTATE_NORMAL, %pstate + mov %l0, %g7 /* set up the normal %g7 */ + wrpr %g0, PSTATE_KERNEL, %pstate stx %g1, [%sp + SPOFF + CCFSZ + TF_G1] stx %g2, [%sp + SPOFF + CCFSZ + TF_G2] @@ -1610,10 +1817,17 @@ ENTRY(tl0_trap_withstack) stx %g6, [%sp + SPOFF + CCFSZ + TF_G6] stx %g7, [%sp + SPOFF + CCFSZ + TF_G7] - mov %l0, %g7 /* set up the normal %g7 */ - - rdpr %pstate, %l1 - wrpr %l1, PSTATE_IE, %pstate +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_trap: p=%p type=%#x arg=%#lx pil=%#lx ws=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + ldx [PCPU(CURPROC)], %g2 + stx %g2, [%g1 + KTR_PARM1] + stx %o0, [%g1 + KTR_PARM2] + stx %o1, [%g1 + KTR_PARM3] + stx %o2, [%g1 + KTR_PARM4] + stx %o3, [%g1 + KTR_PARM5] +9: +#endif stx %i0, [%sp + SPOFF + CCFSZ + TF_O0] stx %i1, [%sp + SPOFF + CCFSZ + TF_O1] @@ -1624,18 +1838,44 @@ ENTRY(tl0_trap_withstack) stx %i6, [%sp + SPOFF + CCFSZ + TF_O6] stx %i7, [%sp + SPOFF + CCFSZ + TF_O7] - stx %o0, [%sp + SPOFF + CCFSZ + TF_PIL] - stx %o1, [%sp + SPOFF + CCFSZ + TF_TYPE] - stx %o2, [%sp + SPOFF + CCFSZ + TF_ARG] - +.Ltl0_trap_spill: call trap add %sp, CCFSZ + SPOFF, %o0 /* Fallthough. */ -END(tl0_trap_withstack) +END(tl0_trap) /* Return to tl0 (user process). */ ENTRY(tl0_ret) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_ret: p=%p (%s) pil=%#lx sflag=%#x" + , %g1, %g2, %g3, 7, 8, 9) + ldx [PCPU(CURPROC)], %g2 + stx %g2, [%g1 + KTR_PARM1] + add %g2, P_COMM, %g3 + stx %g3, [%g1 + KTR_PARM2] + rdpr %pil, %g3 + stx %g3, [%g1 + KTR_PARM3] + lduw [%g2 + P_SFLAG], %g3 + stx %g3, [%g1 + KTR_PARM4] +9: +#endif + + wrpr %g0, PIL_TICK, %pil + ldx [PCPU(CURPROC)], %o0 + lduw [%o0 + P_SFLAG], %o1 + and %o1, PS_ASTPENDING | PS_NEEDRESCHED, %o1 + brz,pt %o1, 1f + nop + call ast + add %sp, CCFSZ + SPOFF, %o0 + +1: ldx [PCPU(CURPCB)], %o0 + ldx [%o0 + PCB_NSAVED], %o1 + mov T_SPILL, %o0 + brnz,a,pn %o1, .Ltl0_trap_spill + stx %o0, [%sp + SPOFF + CCFSZ + TF_TYPE] + ldx [%sp + SPOFF + CCFSZ + TF_G1], %g1 ldx [%sp + SPOFF + CCFSZ + TF_G2], %g2 ldx [%sp + SPOFF + CCFSZ + TF_G3], %g3 @@ -1644,71 +1884,99 @@ ENTRY(tl0_ret) ldx [%sp + SPOFF + CCFSZ + TF_G6], %g6 ldx [%sp + SPOFF + CCFSZ + TF_G7], %g7 - rdpr %pstate, %o0 - wrpr %o0, PSTATE_IE | PSTATE_AG, %pstate - mov %sp, %g1 + ldx [%sp + SPOFF + CCFSZ + TF_O0], %i0 + ldx [%sp + SPOFF + CCFSZ + TF_O1], %i1 + ldx [%sp + SPOFF + CCFSZ + TF_O2], %i2 + ldx [%sp + SPOFF + CCFSZ + TF_O3], %i3 + ldx [%sp + SPOFF + CCFSZ + TF_O4], %i4 + ldx [%sp + SPOFF + CCFSZ + TF_O5], %i5 + ldx [%sp + SPOFF + CCFSZ + TF_O6], %i6 + ldx [%sp + SPOFF + CCFSZ + TF_O7], %i7 + + ldx [%sp + SPOFF + CCFSZ + TF_PIL], %l0 + ldx [%sp + SPOFF + CCFSZ + TF_TSTATE], %l1 + ldx [%sp + SPOFF + CCFSZ + TF_TPC], %l2 + ldx [%sp + SPOFF + CCFSZ + TF_TNPC], %l3 + ldx [%sp + SPOFF + CCFSZ + TF_WSTATE], %l4 + + wrpr %g0, PSTATE_ALT, %pstate + + wrpr %l0, 0, %pil + + wrpr %l1, 0, %tstate + wrpr %l2, 0, %tpc + wrpr %l3, 0, %tnpc /* * Restore the user window state. - * Note: whenever we come here, it should be with %canrestore = 0. + * NOTE: whenever we come here, it should be with %canrestore = 0. */ - ldx [PCPU(CURPCB)], %g4 - ldx [%g4 + PCB_CWP], %g2 - wrpr %g2, %cwp + srlx %l4, WSTATE_USERSHIFT, %g1 + wrpr %g1, WSTATE_TRANSITION, %wstate + rdpr %otherwin, %g2 + wrpr %g2, 0, %canrestore + wrpr %g0, 0, %otherwin + wrpr %g2, 0, %cleanwin /* - * Set up window state for restore. If all windows were spilled, - * %otherwin may be 0, so just set %wstate to 1 to invoke a - * special fill handler (fill traps with %wstate == 1 invoke the - * same handler regardless of %otherwin). + * If this instruction causes a fill trap which fails to fill a window + * from the user stack, we will resume at tl0_ret_fill_end and call + * back into the kernel. */ - wrpr %g0, 1, %wstate - restore ! This will invoke the otherwin fill handler. - wrpr %g0, 0, %wstate - - /* Set up window state for return. */ - ldx [%g4 + PCB_WS_INUSE], %g2 - rdpr %otherwin, %g3 - sub %g3, %g2, %g3 - wrpr %g2, 0, %otherwin - movrlz %g3, %g0, %g3 - wrpr %g3, %canrestore - add %g2, %g3, %g2 - rdpr %ver, %g3 - and %g3, VER_MAXWIN_MASK, %g3 - sub %g3, 1, %g3 ! VER.MAXWIN is NWINDOWS - 1. - sub %g3, %g2, %g3 - wrpr %g3, %cansave - - ldx [%g1 + SPOFF + CCFSZ + TF_O0], %o0 - ldx [%g1 + SPOFF + CCFSZ + TF_O1], %o1 - ldx [%g1 + SPOFF + CCFSZ + TF_O2], %o2 - ldx [%g1 + SPOFF + CCFSZ + TF_O3], %o3 - ldx [%g1 + SPOFF + CCFSZ + TF_O4], %o4 - ldx [%g1 + SPOFF + CCFSZ + TF_O5], %o5 - ldx [%g1 + SPOFF + CCFSZ + TF_O6], %o6 - ldx [%g1 + SPOFF + CCFSZ + TF_O7], %o7 + restore +tl0_ret_fill: - ldx [%g1 + SPOFF + CCFSZ + TF_PIL], %g2 - wrpr %g2, 0, %pil - ldx [%g1 + SPOFF + CCFSZ + TF_TSTATE], %g2 - andn %g2, TSTATE_CWP_MASK, %g2 - rdpr %cwp, %g3 - or %g2, %g3, %g2 - wrpr %g2, %tstate - ldx [%g1 + SPOFF + CCFSZ + TF_TPC], %g2 - wrpr %g2, 0, %tpc - ldx [%g1 + SPOFF + CCFSZ + TF_TNPC], %g2 - wrpr %g2, 0, %tnpc +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_ret: return p=%#lx pil=%#lx ts=%#lx pc=%#lx sp=%#lx" + , %g2, %g3, %g4, 7, 8, 9) + ldx [PCPU(CURPROC)], %g3 + stx %g3, [%g2 + KTR_PARM1] + rdpr %tstate, %g3 + stx %g3, [%g2 + KTR_PARM2] + rdpr %tpc, %g3 + stx %g3, [%g2 + KTR_PARM3] + stx %sp, [%g2 + KTR_PARM4] + stx %g1, [%g2 + KTR_PARM5] +9: +#endif + wrpr %g1, 0, %wstate retry +tl0_ret_fill_end: + +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_ret: fill magic wstate=%#lx sp=%#lx" + , %l0, %l1, %l2, 7, 8, 9) + stx %l4, [%l0 + KTR_PARM1] + stx %sp, [%l0 + KTR_PARM2] +9: +#endif + + /* + * The fill failed and magic has been preformed. Call trap again, + * which will copyin the window on the user's behalf. + */ + wrpr %l4, 0, %wstate + mov T_FILL, %o0 + b %xcc, .Ltl0_trap_fill + stx %o0, [%sp + SPOFF + CCFSZ + TF_TYPE] END(tl0_ret) /* - * void tl1_trap(u_long o0, u_long o1, u_long o2, u_long type) + * Kernel trap entry point + * + * void tl1_trap(u_long type, u_long arg, u_long pil) + * + * This is easy because the stack is already setup and the windows don't need + * to be split. We build a trapframe and call trap(), the same as above, but + * the outs don't need to be saved. + * + * NOTE: See comments above tl0_trap for song and dance about chip bugs and + * setting up globalp. */ ENTRY(tl1_trap) sub %sp, TF_SIZEOF, %sp + rdpr %tstate, %l0 stx %l0, [%sp + SPOFF + CCFSZ + TF_TSTATE] rdpr %tpc, %l1 @@ -1716,15 +1984,42 @@ ENTRY(tl1_trap) rdpr %tnpc, %l2 stx %l2, [%sp + SPOFF + CCFSZ + TF_TNPC] +#if KTR_COMPILE & KTR_CT1 + setx trap_mask, %l4, %l3 + andn %o1, T_KERNEL, %l4 + mov 1, %l5 + sllx %l5, %l4, %l4 + ldx [%l3], %l5 + and %l4, %l5, %l4 + brz %l4, 9f + nop + CATR(KTR_CT1, "tl1_trap: p=%p pil=%#lx type=%#lx arg=%#lx pc=%#lx" + , %l3, %l4, %l5, 7, 8, 9) + ldx [PCPU(CURPROC)], %l4 + stx %l4, [%l3 + KTR_PARM1] +#if 0 + add %l4, P_COMM, %l4 + stx %l4, [%l3 + KTR_PARM2] +#else + stx %o2, [%l3 + KTR_PARM2] +#endif + andn %o0, T_KERNEL, %l4 + stx %l4, [%l3 + KTR_PARM3] + stx %o1, [%l3 + KTR_PARM4] + stx %l1, [%l3 + KTR_PARM5] +9: +#endif + wrpr %g0, 1, %tl /* We may have trapped before %g7 was set up correctly. */ - mov %g7, %l3 - rdpr %pstate, %l0 - wrpr %l0, PSTATE_AG, %pstate + mov %g7, %l0 + wrpr %g0, PSTATE_NORMAL, %pstate + mov %l0, %g7 + wrpr %g0, PSTATE_KERNEL, %pstate - stx %o0, [%sp + SPOFF + CCFSZ + TF_PIL] - stx %o1, [%sp + SPOFF + CCFSZ + TF_TYPE] - stx %o2, [%sp + SPOFF + CCFSZ + TF_ARG] + stx %o0, [%sp + SPOFF + CCFSZ + TF_TYPE] + stx %o1, [%sp + SPOFF + CCFSZ + TF_ARG] + stx %o2, [%sp + SPOFF + CCFSZ + TF_PIL] stx %g1, [%sp + SPOFF + CCFSZ + TF_G1] stx %g2, [%sp + SPOFF + CCFSZ + TF_G2] @@ -1732,12 +2027,7 @@ ENTRY(tl1_trap) stx %g4, [%sp + SPOFF + CCFSZ + TF_G4] stx %g5, [%sp + SPOFF + CCFSZ + TF_G5] stx %g6, [%sp + SPOFF + CCFSZ + TF_G6] - stx %g7, [%sp + SPOFF + CCFSZ + TF_G7] - mov %l3, %g7 - rdpr %pstate, %l0 - wrpr %l0, PSTATE_IE, %pstate - call trap add %sp, CCFSZ + SPOFF, %o0 @@ -1747,16 +2037,13 @@ ENTRY(tl1_trap) ldx [%sp + SPOFF + CCFSZ + TF_G4], %g4 ldx [%sp + SPOFF + CCFSZ + TF_G5], %g5 ldx [%sp + SPOFF + CCFSZ + TF_G6], %g6 - ldx [%sp + SPOFF + CCFSZ + TF_G7], %g7 ldx [%sp + SPOFF + CCFSZ + TF_PIL], %l0 ldx [%sp + SPOFF + CCFSZ + TF_TSTATE], %l1 ldx [%sp + SPOFF + CCFSZ + TF_TPC], %l2 ldx [%sp + SPOFF + CCFSZ + TF_TNPC], %l3 - rdpr %pstate, %o0 - andn %o0, PSTATE_IE, %o0 - wrpr %o0, 0, %pstate + wrpr %g0, PSTATE_ALT, %pstate wrpr %l0, 0, %pil @@ -1765,11 +2052,47 @@ ENTRY(tl1_trap) wrpr %l2, 0, %tpc wrpr %l3, 0, %tnpc +#if KTR_COMPILE & KTR_CT1 + ldx [%sp + SPOFF + CCFSZ + TF_TYPE], %l5 + andn %l5, T_KERNEL, %l4 + mov 1, %l5 + sllx %l5, %l4, %l4 + setx trap_mask, %l4, %l3 + ldx [%l3], %l5 + and %l4, %l5, %l4 + brz %l4, 9f + nop + CATR(KTR_CT1, "tl1_trap: return p=%p pil=%#lx sp=%#lx pc=%#lx" + , %l3, %l4, %l5, 7, 8, 9) + ldx [PCPU(CURPROC)], %l4 + stx %l4, [%l3 + KTR_PARM1] + stx %l0, [%l3 + KTR_PARM2] + stx %sp, [%l3 + KTR_PARM3] + stx %l2, [%l3 + KTR_PARM4] +9: +#endif + restore retry END(tl1_trap) +/* + * Freshly forked processes come here when switched to for the first time. + * The arguments to fork_exit() have been setup in the locals, we must move + * them to the outs. + */ ENTRY(fork_trampoline) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "fork_trampoline: p=%p (%s) cwp=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + ldx [PCPU(CURPROC)], %g2 + stx %g2, [%g1 + KTR_PARM1] + add %g2, P_COMM, %g2 + stx %g2, [%g1 + KTR_PARM2] + rdpr %cwp, %g2 + stx %g2, [%g1 + KTR_PARM3] +9: +#endif mov %l0, %o0 mov %l1, %o1 mov %l2, %o2 diff --git a/sys/sparc64/sparc64/exception.s b/sys/sparc64/sparc64/exception.s index 281464b18b209..8a10c17a1b4e1 100644 --- a/sys/sparc64/sparc64/exception.s +++ b/sys/sparc64/sparc64/exception.s @@ -59,69 +59,168 @@ #include <machine/asi.h> #include <machine/asmacros.h> +#include <machine/ktr.h> +#include <machine/pstate.h> #include <machine/trap.h> +#include <machine/tstate.h> +#include <machine/wstate.h> #include "assym.s" /* - * This is more or less relatively straight forward, except for the register - * window handling, which can get ugly. - * There are two situations where this can happen: - * - a normal (non spill/fill) trap from user space, where the windows are - * still filled with user data - * - a trap in a spill/fill trap handler that spills/fills userland windows - * In both cases, the spills of the user data may fault in a way that requires - * the C fault handler to be invoked, which needs a register window, so we would - * try to spill again... ad infinitum. - * The traps in question are dmmu_miss, dmmu_prot (both possibly fatal), - * data_access and alignment (fatal). - * So, on entry from user space, we set up a special %wstate (to handle a - * possible spill triggered by the first save), and later set %otherwin to - * split the window between kernel windows and user windows. - * The spill handler that is called with this %wstate or %otherwin != 0 spills - * to pcb_wscratch, indexed by %cwp, and notes the number of spilled registers - * in pcb_ws_inuse. Elements of pcb_wstate that are in use are marked by setting - * the wsf_inuse field. When the trap has completed, %otherwin is set so that - * user space spills/fills for windows that are still stored in pcb_wscratch are - * handled by directly filling from pcb_wscratch or spilling from pcb_wscratch - * to user space. + * Macros for spilling and filling live windows. + * + * NOTE: These macros use exactly 16 instructions, and it is assumed that the + * handler will not use more than 24 instructions total, to leave room for + * resume vectors which occupy the last 8 instructions. + */ + +#define SPILL(storer, base, size, asi) \ + storer %l0, [base + (0 * size)] asi ; \ + storer %l1, [base + (1 * size)] asi ; \ + storer %l2, [base + (2 * size)] asi ; \ + storer %l3, [base + (3 * size)] asi ; \ + storer %l4, [base + (4 * size)] asi ; \ + storer %l5, [base + (5 * size)] asi ; \ + storer %l6, [base + (6 * size)] asi ; \ + storer %l7, [base + (7 * size)] asi ; \ + storer %i0, [base + (8 * size)] asi ; \ + storer %i1, [base + (9 * size)] asi ; \ + storer %i2, [base + (10 * size)] asi ; \ + storer %i3, [base + (11 * size)] asi ; \ + storer %i4, [base + (12 * size)] asi ; \ + storer %i5, [base + (13 * size)] asi ; \ + storer %i6, [base + (14 * size)] asi ; \ + storer %i7, [base + (15 * size)] asi + +#define FILL(loader, base, size, asi) \ + loader [base + (0 * size)] asi, %l0 ; \ + loader [base + (1 * size)] asi, %l1 ; \ + loader [base + (2 * size)] asi, %l2 ; \ + loader [base + (3 * size)] asi, %l3 ; \ + loader [base + (4 * size)] asi, %l4 ; \ + loader [base + (5 * size)] asi, %l5 ; \ + loader [base + (6 * size)] asi, %l6 ; \ + loader [base + (7 * size)] asi, %l7 ; \ + loader [base + (8 * size)] asi, %i0 ; \ + loader [base + (9 * size)] asi, %i1 ; \ + loader [base + (10 * size)] asi, %i2 ; \ + loader [base + (11 * size)] asi, %i3 ; \ + loader [base + (12 * size)] asi, %i4 ; \ + loader [base + (13 * size)] asi, %i5 ; \ + loader [base + (14 * size)] asi, %i6 ; \ + loader [base + (15 * size)] asi, %i7 + +#define ERRATUM50(reg) mov reg, reg + +/* + * Magic to resume from a spill or fill trap. If we get an alignment or an + * mmu fault during a spill or a fill, this macro will detect the fault and + * resume at a set instruction offset in the trap handler, which will try to + * get help. + * + * To check if the previous trap was a spill/fill we convert the the trapped + * pc to a trap type and verify that it is in the range of spill/fill vectors. + * The spill/fill vectors are types 0x80-0xff and 0x280-0x2ff, masking off the + * tl bit allows us to detect both ranges with one test. + * + * This is: + * (((%tpc - %tba) >> 5) & ~0x200) >= 0x80 && <= 0xff + * + * Values outside of the trap table will produce negative or large positive + * results. + * + * To calculate the new pc we take advantage of the xor feature of wrpr. + * Forcing all the low bits of the trapped pc on we can produce any offset + * into the spill/fill vector. The size of a spill/fill trap vector is 0x80. + * + * 0x7f ^ 0x1f == 0x60 + * 0x1f == (0x80 - 0x60) - 1 + * + * Which are the offset and xor value used to resume from mmu faults. */ -#define SPILL(storer, base, asi, struct) \ - storer %l0, [base + struct ## _L0] asi ; \ - storer %l1, [base + struct ## _L1] asi ; \ - storer %l2, [base + struct ## _L2] asi ; \ - storer %l3, [base + struct ## _L3] asi ; \ - storer %l4, [base + struct ## _L4] asi ; \ - storer %l5, [base + struct ## _L5] asi ; \ - storer %l6, [base + struct ## _L6] asi ; \ - storer %l7, [base + struct ## _L7] asi ; \ - storer %i0, [base + struct ## _I0] asi ; \ - storer %i1, [base + struct ## _I1] asi ; \ - storer %i2, [base + struct ## _I2] asi ; \ - storer %i3, [base + struct ## _I3] asi ; \ - storer %i4, [base + struct ## _I4] asi ; \ - storer %i5, [base + struct ## _I5] asi ; \ - storer %i6, [base + struct ## _I6] asi ; \ - storer %i7, [base + struct ## _I7] asi +/* + * If a spill/fill trap is not detected this macro will branch to the label l1. + * Otherwise the caller should do any necesary cleanup and execute a done. + */ +#define RESUME_SPILLFILL_MAGIC(r1, r2, xor, l1) \ + rdpr %tpc, r1 ; \ + ERRATUM50(r1) ; \ + rdpr %tba, r2 ; \ + sub r1, r2, r2 ; \ + srlx r2, 5, r2 ; \ + andn r2, 0x200, r2 ; \ + sub r2, 0x80, r2 ; \ + brlz r2, l1 ; \ + sub r2, 0x7f, r2 ; \ + brgz r2, l1 ; \ + or r1, 0x7f, r1 ; \ + wrpr r1, xor, %tnpc ; \ + +#define RSF_XOR(off) ((0x80 - off) - 1) -#define FILL(loader, base, asi, struct) \ - loader [base + struct ## _L0] asi, %l0 ; \ - loader [base + struct ## _L1] asi, %l1 ; \ - loader [base + struct ## _L2] asi, %l2 ; \ - loader [base + struct ## _L3] asi, %l3 ; \ - loader [base + struct ## _L4] asi, %l4 ; \ - loader [base + struct ## _L5] asi, %l5 ; \ - loader [base + struct ## _L6] asi, %l6 ; \ - loader [base + struct ## _L7] asi, %l7 ; \ - loader [base + struct ## _I0] asi, %i0 ; \ - loader [base + struct ## _I1] asi, %i1 ; \ - loader [base + struct ## _I2] asi, %i2 ; \ - loader [base + struct ## _I3] asi, %i3 ; \ - loader [base + struct ## _I4] asi, %i4 ; \ - loader [base + struct ## _I5] asi, %i5 ; \ - loader [base + struct ## _I6] asi, %i6 ; \ - loader [base + struct ## _I7] asi, %i7 +/* + * Instruction offsets in spill and fill trap handlers for handling certain + * nested traps, and corresponding xor constants for wrpr. + */ +#define RSF_OFF_MMU 0x60 +#define RSF_OFF_ALIGN 0x70 + +#define RSF_MMU RSF_XOR(RSF_OFF_MMU) +#define RSF_ALIGN RSF_XOR(RSF_OFF_ALIGN) + +/* + * Constant to add to %tnpc when taking a fill trap just before returning to + * user mode. The instruction sequence looks like restore, wrpr, retry; we + * want to skip over the wrpr and retry and execute code to call back into the + * kernel. It is useful to add tracing between these instructions, which would + * change the size of the sequence, so we demark with labels and subtract. + */ +#define RSF_FILL_INC tl0_ret_fill_end - tl0_ret_fill + +/* + * Retry a spill or fill with a different wstate due to an alignment fault. + * We may just be using the wrong stack offset. + */ +#define RSF_ALIGN_RETRY(ws) \ + wrpr %g0, (ws), %wstate ; \ + retry ; \ + .align 16 + +/* + * Generate a T_SPILL or T_FILL trap if the window operation fails. + */ +#define RSF_TRAP(type) \ + b %xcc, tl0_sftrap ; \ + mov type, %g2 ; \ + .align 16 + +/* + * Game over if the window operation fails. + */ +#define RSF_FATAL(type) \ + sir type ; \ + .align 16 + +/* + * Magic to resume from a failed fill a few instructions after the corrsponding + * restore. This is used on return from the kernel to usermode. + */ +#define RSF_FILL_MAGIC \ + rdpr %tnpc, %g1 ; \ + add %g1, RSF_FILL_INC, %g1 ; \ + wrpr %g1, 0, %tnpc ; \ + done ; \ + .align 16 + +/* + * Spill to the pcb if a spill to the user stack in kernel mode fails. + */ +#define RSF_SPILL_TOPCB \ + b,a %xcc, tl1_spill_topcb ; \ + nop ; \ + .align 16 DATA(intrnames) .asciz "foo" @@ -131,6 +230,26 @@ DATA(intrcnt) .long 0 DATA(eintrcnt) +/* + * Trap table and associated macros + * + * Due to its size a trap table is an inherently hard thing to represent in + * code in a clean way. There are approximately 1024 vectors, of 8 or 32 + * instructions each, many of which are identical. The way that this is + * layed out is the instructions (8 or 32) for the actual trap vector appear + * as an AS macro. In general this code branches to tl0_trap or tl1_trap, + * but if not supporting code can be placed just after the definition of the + * macro. The macros are then instantiated in a different section (.trap), + * which is setup to be placed by the linker at the beginning of .text, and the + * code around the macros is moved to the end of trap table. In this way the + * code that must be sequential in memory can be split up, and located near + * its supporting code so that it is easier to follow. + */ + + /* + * Clean window traps occur when %cleanwin is zero to ensure that data + * is not leaked between address spaces in registers. + */ .macro clean_window clr %o0 clr %o1 @@ -155,109 +274,125 @@ DATA(eintrcnt) .align 128 .endm - /* Fixups for kernel entry from tl0. */ - /* - * Split the register window using %otherwin. This is an optimization - * to not have to flush all the register windows on kernel entry. - * Set %wstate so that spills go to the pcb; this is valid because there - * is always at least one frame. - * A spill with %wstate == 1 will invoke the same spill handler - * regardless of %otherwin (tl1_spill_1_n and tl1_spill_0_o are the - * same). - * Before the next save (that is, in tl0_trap_*), we finish the - * splitting setup and set %otherwin correctly. - * Note that the alternate %g7 must always be valid in places where we - * could spill. + * Stack fixups for entry from user mode. We are still running on the + * user stack, and with its live registers, so we must save soon. We + * are on alternate globals so we do have some registers. Set the + * transitional window state, save, and call a routine to get onto + * the kernel stack. If the save traps we attempt to spill a window + * to the user stack. If this fails, we spill the window to the pcb + * and continue. + * + * NOTE: Must be called with alternate globals and clobbers %g1. */ - .macro tl0_split_save - wrpr %g0, 1, %wstate + + .macro tl0_kstack + rdpr %wstate, %g1 + wrpr %g1, WSTATE_TRANSITION, %wstate save + call tl0_kstack_fixup + rdpr %canrestore, %o0 .endm - /* - * Flush out all but one of the user windows to the pcb register - * window scratch space. At the end of the trap, the windows are - * restored. - */ - .macro tl0_flush_save - wrpr %g0, 1, %wstate - save - flushw - wrpr %g0, 0, %wstate + .macro tl0_setup type + tl0_kstack + rdpr %pil, %o2 + b %xcc, tl0_trap + mov \type, %o0 .endm +/* + * Setup the kernel stack and split the register windows when faulting from + * user space. + * %canrestore is passed in %o0 and %wstate in (alternate) %g1. + */ +ENTRY(tl0_kstack_fixup) + mov %g1, %o3 + and %o3, WSTATE_MASK, %o1 + sllx %o0, WSTATE_USERSHIFT, %o1 + wrpr %o1, 0, %wstate + wrpr %o0, 0, %otherwin + wrpr %g0, 0, %canrestore + ldx [PCPU(CURPCB)], %o0 + set UPAGES * PAGE_SIZE - SPOFF - CCFSZ, %o1 + retl + add %o0, %o1, %sp +END(tl0_kstack_fixup) + /* - * Setup the kernel stack when faulting from user space. + * Generic trap type. Call trap() with the specified type. */ - .macro tl0_setup_stack tmp1, sz - /* Set up the kernel stack. */ - setx UPAGES * PAGE_SIZE - SPOFF - CCFSZ - TF_SIZEOF - \sz, \tmp1, %sp - ldx [PCPU(CURPCB)], \tmp1 - add %sp, \tmp1, %sp - .endm - .macro tl0_gen type - tl0_split_save - rdpr %pil, %o0 - b %xcc, tl0_trap - mov \type, %o1 + tl0_setup \type .align 32 .endm .macro tl0_wide type - tl0_split_save - rdpr %pil, %o0 - b %xcc, tl0_trap - mov \type, %o1 + tl0_setup \type .align 128 .endm + /* + * This is used to suck up the massive swaths of reserved trap types. + * Generates count "reserved" trap vectors. + */ .macro tl0_reserved count .rept \count tl0_gen T_RESERVED .endr .endm + /* + * NOTE: we cannot use mmu globals here because tl0_kstack may cause + * an mmu fault. + */ + .macro tl0_data_excptn + wrpr %g0, PSTATE_ALT, %pstate + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_SFAR] %asi, %g3 + ldxa [%g0 + AA_DMMU_SFSR] %asi, %g4 + ldxa [%g0 + AA_DMMU_TAR] %asi, %g5 + b %xcc, tl0_sfsr_trap + mov T_DATA_EXCPTN, %g2 + .align 32 + .endm + .macro tl0_align - rdpr %pstate, %g1 - wrpr %g1, PSTATE_MG | PSTATE_AG, %pstate + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_SFAR] %asi, %g3 + ldxa [%g0 + AA_DMMU_SFSR] %asi, %g4 b %xcc, tl0_sfsr_trap - mov T_ALIGN, %g4 + mov T_ALIGN, %g2 .align 32 .endm -/* - * This must be called with MMU globals active, otherwise the spill handler - * might clobber the globals we use to transfer the sfar and sfsr. - */ ENTRY(tl0_sfsr_trap) - wr %g0, ASI_DMMU, %asi - ldxa [%g0 + AA_DMMU_SFAR] %asi, %g1 - ldxa [%g0 + AA_DMMU_SFSR] %asi, %g2 + /* + * Clear the sfsr. + */ stxa %g0, [%g0 + AA_DMMU_SFSR] %asi membar #Sync - tl0_split_save - mov %g1, %l1 - mov %g2, %l2 - mov %g4, %o1 - rdpr %pstate, %l3 - wrpr %l3, PSTATE_MG | PSTATE_AG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFAR] - stx %l2, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFSR] - rdpr %pil, %o0 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 + /* + * Get onto the kernel stack, save the mmu registers, and call + * common code. + */ + tl0_kstack + sub %sp, MF_SIZEOF, %sp + stx %g3, [%sp + SPOFF + CCFSZ + MF_SFAR] + stx %g4, [%sp + SPOFF + CCFSZ + MF_SFSR] + stx %g5, [%sp + SPOFF + CCFSZ + MF_TAR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl0_trap + mov %g2, %o0 END(tl0_sfsr_trap) - .macro tl0_intr level, mask, type - tl0_split_save - set \level, %o3 + .macro tl0_intr level, mask + tl0_kstack set \mask, %o2 b %xcc, tl0_intr_call_trap - mov \type, %o1 + mov \level, %o1 .align 32 .endm @@ -266,18 +401,18 @@ END(tl0_sfsr_trap) * because of space constraints. */ ENTRY(tl0_intr_call_trap) - rdpr %pil, %o0 - wrpr %g0, %o3, %pil + wr %o2, 0, %asr21 + rdpr %pil, %o2 + wrpr %g0, %o1, %pil b %xcc, tl0_trap - wr %o2, 0, %asr21 + mov T_INTR, %o0 END(tl0_intr_call_trap) #define INTR(level, traplvl) \ - tl ## traplvl ## _intr level, 1 << level, \ - T_INTR | (level << T_LEVEL_SHIFT) + tl ## traplvl ## _intr level, 1 << level #define TICK(traplvl) \ - tl ## traplvl ## _intr 14, 1, T_INTR | (14 << T_LEVEL_SHIFT) + tl ## traplvl ## _intr PIL_TICK, 1 #define INTR_LEVEL(tl) \ INTR(1, tl) ; \ @@ -307,6 +442,11 @@ END(tl0_intr_call_trap) .macro tl0_immu_miss /* + * Force kernel store order. + */ + wrpr %g0, PSTATE_MMU, %pstate + + /* * Extract the 8KB pointer and convert to an index. */ ldxa [%g0] ASI_IMMU_TSB_8KB_PTR_REG, %g1 @@ -369,7 +509,7 @@ END(tl0_intr_call_trap) * Set the reference bit, if it's currently clear. */ andcc %g7, TD_REF, %g0 - bz,a,pn %xcc, immu_miss_user_set_ref + bz,a,pn %xcc, tl0_immu_miss_set_ref nop /* @@ -385,11 +525,11 @@ END(tl0_intr_call_trap) andcc %g2, TSB_PRIMARY_STTE_MASK, %g0 bnz %xcc, 1b nop - b,a %xcc, immu_miss_user_call_trap + b,a %xcc, tl0_immu_miss_trap .align 128 .endm -ENTRY(immu_miss_user_set_ref) +ENTRY(tl0_immu_miss_set_ref) /* * Set the reference bit. */ @@ -400,6 +540,12 @@ ENTRY(immu_miss_user_set_ref) bne,a,pn %xcc, 1b mov %g1, %g7 +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_immu_miss: set ref" + , %g2, %g3, %g4, 7, 8, 9) +9: +#endif + /* * May have become invalid, in which case start over. */ @@ -411,30 +557,39 @@ ENTRY(immu_miss_user_set_ref) */ stxa %g1, [%g0] ASI_ITLB_DATA_IN_REG 2: retry -END(immu_miss_user_set_ref) +END(tl0_immu_miss_set_ref) + +ENTRY(tl0_immu_miss_trap) + /* + * Switch to alternate globals. + */ + wrpr %g0, PSTATE_ALT, %pstate -ENTRY(immu_miss_user_call_trap) /* * Load the tar, sfar and sfsr aren't valid. */ - mov AA_IMMU_TAR, %g1 - ldxa [%g1] ASI_IMMU, %g1 + wr %g0, ASI_IMMU, %asi + ldxa [%g0 + AA_IMMU_TAR] %asi, %g2 + +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_immu_miss: trap sp=%#lx tar=%#lx" + , %g3, %g4, %g5, 7, 8, 9) + stx %sp, [%g3 + KTR_PARM1] + stx %g2, [%g3 + KTR_PARM2] +9: +#endif /* - * Save the mmu registers on the stack, switch to alternate globals, - * and call common trap code. + * Save the mmu registers on the stack, and call common trap code. */ - tl0_split_save - mov %g1, %l1 - rdpr %pstate, %l3 - wrpr %l3, PSTATE_AG | PSTATE_MG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_TAR] - rdpr %pil, %o0 - mov T_IMMU_MISS, %o1 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 -END(immu_miss_user_call_trap) + tl0_kstack + sub %sp, MF_SIZEOF, %sp + stx %g2, [%sp + SPOFF + CCFSZ + MF_TAR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl0_trap + mov T_IMMU_MISS, %o0 +END(tl0_immu_miss_trap) .macro dmmu_miss_user /* @@ -502,13 +657,6 @@ END(immu_miss_user_call_trap) nop /* - * If the mod bit is clear, clear the write bit too. - */ - andcc %g7, TD_MOD, %g1 - movz %xcc, TD_W, %g1 - andn %g7, %g1, %g7 - - /* * Load the tte data into the tlb and retry the instruction. */ stxa %g7, [%g0] ASI_DTLB_DATA_IN_REG @@ -534,6 +682,12 @@ ENTRY(dmmu_miss_user_set_ref) bne,a,pn %xcc, 1b mov %g1, %g7 +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_dmmu_miss: set ref" + , %g2, %g3, %g4, 7, 8, 9) +9: +#endif + /* * May have become invalid, in which case start over. */ @@ -541,13 +695,6 @@ ENTRY(dmmu_miss_user_set_ref) nop /* - * If the mod bit is clear, clear the write bit too. - */ - andcc %g1, TD_MOD, %g2 - movz %xcc, TD_W, %g2 - andn %g1, %g2, %g1 - - /* * Load the tte data into the tlb and retry the instruction. */ stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG @@ -556,6 +703,11 @@ END(dmmu_miss_user_set_ref) .macro tl0_dmmu_miss /* + * Force kernel store order. + */ + wrpr %g0, PSTATE_MMU, %pstate + + /* * Try a fast inline lookup of the primary tsb. */ dmmu_miss_user @@ -569,151 +721,49 @@ END(dmmu_miss_user_set_ref) ENTRY(tl0_dmmu_miss_trap) /* - * Load the tar, sfar and sfsr aren't valid. + * Switch to alternate globals. */ - mov AA_DMMU_TAR, %g1 - ldxa [%g1] ASI_DMMU, %g1 + wrpr %g0, PSTATE_ALT, %pstate /* - * Save the mmu registers on the stack, switch to alternate globals, - * and call common trap code. - */ - tl0_split_save - mov %g1, %l1 - rdpr %pstate, %l3 - wrpr %l3, PSTATE_AG | PSTATE_MG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_TAR] - rdpr %pil, %o0 - mov T_DMMU_MISS, %o1 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 -END(tl0_dmmu_miss_trap) - - .macro dmmu_prot_user - /* - * Extract the 8KB pointer and convert to an index. - */ - ldxa [%g0] ASI_DMMU_TSB_8KB_PTR_REG, %g1 - srax %g1, TTE_SHIFT, %g1 - - /* - * Compute the stte address in the primary used tsb. - */ - and %g1, (1 << TSB_PRIMARY_MASK_WIDTH) - 1, %g2 - sllx %g2, TSB_PRIMARY_STTE_SHIFT, %g2 - setx TSB_USER_MIN_ADDRESS, %g4, %g3 - add %g2, %g3, %g2 - - /* - * Preload the tte tag target. - */ - ldxa [%g0] ASI_DMMU_TAG_TARGET_REG, %g3 - - /* - * Preload tte data bits to check inside the bucket loop. - */ - and %g1, TD_VA_LOW_MASK >> TD_VA_LOW_SHIFT, %g4 - sllx %g4, TD_VA_LOW_SHIFT, %g4 - - /* - * Preload mask for tte data check. - */ - setx TD_VA_LOW_MASK, %g5, %g1 - or %g1, TD_W, %g1 - - /* - * Loop over the sttes in this bucket - */ - - /* - * Load the tte. - */ -1: ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %g6 - - /* - * Compare the tag. - */ - cmp %g6, %g3 - bne,pn %xcc, 2f - - /* - * Compare the data. - */ - xor %g7, %g4, %g5 - brgez,pn %g7, 2f - andcc %g5, %g1, %g0 - - /* - * On a match, jump to code to finish up. - */ - bz,pn %xcc, dmmu_prot_user_set_mod - nop - - /* - * Check the low bits to see if we've finished the bucket. - */ -2: add %g2, STTE_SIZEOF, %g2 - andcc %g2, TSB_PRIMARY_STTE_MASK, %g0 - bnz %xcc, 1b - nop - .endm - -ENTRY(dmmu_prot_user_set_mod) - /* - * Set the modify bit. - */ - add %g2, TTE_DATA, %g2 -1: or %g7, TD_MOD, %g1 - casxa [%g2] ASI_N, %g7, %g1 - cmp %g1, %g7 - bne,a,pn %xcc, 1b - mov %g1, %g7 - - /* - * Delete the old tsb entry. + * Load the tar, sfar and sfsr aren't valid. */ wr %g0, ASI_DMMU, %asi - ldxa [%g0 + AA_DMMU_TAR] %asi, %g3 - andn %g3, PAGE_MASK, %g3 - stxa %g0, [%g3] ASI_DMMU_DEMAP + ldxa [%g0 + AA_DMMU_TAR] %asi, %g2 - /* - * May have become invalid, in which case start over. - */ - brgez,pn %g1, 2f - nop +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_dmmu_miss: trap sp=%#lx tar=%#lx" + , %g3, %g4, %g5, 7, 8, 9) + stx %sp, [%g3 + KTR_PARM1] + stx %g2, [%g3 + KTR_PARM2] +9: +#endif /* - * Load the tte data into the tlb, clear the sfsr and retry the - * instruction. + * Save the mmu registers on the stack and call common trap code. */ - stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG - stxa %g0, [%g0 + AA_DMMU_SFSR] %asi -2: retry -END(dmmu_prot_user_set_mod) + tl0_kstack + sub %sp, MF_SIZEOF, %sp + stx %g2, [%sp + SPOFF + CCFSZ + MF_TAR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl0_trap + mov T_DMMU_MISS, %o0 +END(tl0_dmmu_miss_trap) .macro tl0_dmmu_prot /* - * Try a fast inline lookup of the primary tsb. + * Switch to alternate globals. */ - dmmu_prot_user - - /* - * Not in primary tsb, call c code. Nothing else fits inline. - */ - b,a tl0_dmmu_prot_trap - .align 128 - .endm + wrpr %g0, PSTATE_ALT, %pstate -ENTRY(tl0_dmmu_prot_trap) /* * Load the tar, sfar and sfsr. */ wr %g0, ASI_DMMU, %asi ldxa [%g0 + AA_DMMU_SFAR] %asi, %g2 ldxa [%g0 + AA_DMMU_SFSR] %asi, %g3 - ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 + ldxa [%g0 + AA_DMMU_TAR] %asi, %g4 stxa %g0, [%g0 + AA_DMMU_SFSR] %asi membar #Sync @@ -721,115 +771,129 @@ ENTRY(tl0_dmmu_prot_trap) * Save the mmu registers on the stack, switch to alternate globals, * and call common trap code. */ - tl0_split_save - mov %g1, %l1 - mov %g2, %l2 - mov %g3, %l3 - rdpr %pstate, %l4 - wrpr %l4, PSTATE_AG | PSTATE_MG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_TAR] - stx %l2, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFAR] - stx %l3, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFSR] - rdpr %pil, %o0 - mov T_DMMU_PROT, %o1 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 -END(tl0_dmmu_prot_trap) + tl0_kstack + sub %sp, MF_SIZEOF, %sp + stx %g2, [%sp + SPOFF + CCFSZ + MF_TAR] + stx %g3, [%sp + SPOFF + CCFSZ + MF_SFAR] + stx %g4, [%sp + SPOFF + CCFSZ + MF_SFSR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl0_trap + mov T_DMMU_PROT, %o0 + .align 128 + .endm .macro tl0_spill_0_n - ldx [PCPU(CURPCB)], %g1 - stx %g1, [%g1 + PCB_INWINOP] ! something != 0 - wr %g0, ASI_AIUP, %asi - SPILL(stxa, %sp + SPOFF, %asi, F) - stx %g0, [%g1 + PCB_INWINOP] + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: SPILL(stxa, %sp + SPOFF, 8, %asi) saved + wrpr %g0, WSTATE_ASSUME64, %wstate retry - .align 128 + .align 32 + RSF_TRAP(T_SPILL) + RSF_TRAP(T_SPILL) .endm - .macro tl0_spill_0_o - b,a tl0_spill_frompcb - .align 128 - .endm - -#define LDSTA(tmp, from, to) \ - ldx [from], tmp ; \ - stxa tmp, [to] %asi + .macro tl0_spill_1_n + andcc %sp, 1, %g0 + bnz %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + wrpr %g0, WSTATE_ASSUME32, %wstate + retry + .align 32 + RSF_TRAP(T_SPILL) + RSF_TRAP(T_SPILL) + .endm -/* - * A window that was spilled to the pcb during the last trap, was marked with - * %otherwin, but was not filled back in again yet. In this case, we need to - * spill the data from the pcb directly to user space. Traps while writing to - * user space are handled as normally. - */ -ENTRY(tl0_spill_frompcb) - ldx [PCPU(CURPCB)], %g1 - /* We may fault while spilling to user space, prepare for that. */ - stx %g1, [%g1 + PCB_INWINOP] ! something != 0 - rdpr %cwp, %g2 - mulx %g2, WSF_SIZEOF, %g3 - add %g1, %g3, %g3 - ldx [%g3 + PCB_WSCRATCH + WSF_SP], %g4 + .macro tl0_spill_2_n wr %g0, ASI_AIUP, %asi - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I0, %g4 + SPOFF + F_I0) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I1, %g4 + SPOFF + F_I1) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I2, %g4 + SPOFF + F_I2) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I3, %g4 + SPOFF + F_I3) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I4, %g4 + SPOFF + F_I4) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I5, %g4 + SPOFF + F_I5) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I6, %g4 + SPOFF + F_I6) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_I7, %g4 + SPOFF + F_I7) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L0, %g4 + SPOFF + F_L0) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L1, %g4 + SPOFF + F_L1) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L2, %g4 + SPOFF + F_L2) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L3, %g4 + SPOFF + F_L3) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L4, %g4 + SPOFF + F_L4) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L5, %g4 + SPOFF + F_L5) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L6, %g4 + SPOFF + F_L6) - LDSTA(%g2, %g3 + PCB_WSCRATCH + WSF_L7, %g4 + SPOFF + F_L7) - stx %g0, [%g1 + PCB_INWINOP] - /* wscratch window becomes unused. */ - stx %g0, [%g3 + WSF_INUSE] - rdpr %otherwin, %g4 - sub %g4, 1, %g4 - stx %g4, [%g1 + PCB_WS_INUSE] + SPILL(stxa, %sp + SPOFF, 8, %asi) saved retry -END(tl0_spill_frompcb) + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST32) + RSF_TRAP(T_SPILL) + .endm - .macro tl0_spill_bad count - .rept \count - tl0_wide T_SPILL - .endr + .macro tl0_spill_3_n + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST64) + RSF_TRAP(T_SPILL) .endm .macro tl0_fill_0_n - ldx [PCPU(CURPCB)], %g1 - stx %g1, [%g1 + PCB_INWINOP] ! something != 0 + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: FILL(ldxa, %sp + SPOFF, 8, %asi) + restored + wrpr %g0, WSTATE_ASSUME64, %wstate + retry + .align 32 + RSF_TRAP(T_FILL) + RSF_TRAP(T_FILL) + .endm + + .macro tl0_fill_1_n + andcc %sp, 1, %g0 + bnz %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + FILL(lduwa, %sp, 4, %asi) + restored + wrpr %g0, WSTATE_ASSUME32, %wstate + retry + .align 32 + RSF_TRAP(T_FILL) + RSF_TRAP(T_FILL) + .endm + + .macro tl0_fill_2_n wr %g0, ASI_AIUP, %asi - FILL(ldxa, %sp + SPOFF, %asi, F) - stx %g0, [%g1 + PCB_INWINOP] + FILL(ldxa, %sp + SPOFF, 8, %asi) restored retry - .align 128 + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST32) + RSF_TRAP(T_FILL) .endm - .macro tl0_fill_0_o - ldx [PCPU(CURPCB)], %g1 - rdpr %cwp, %g2 - mulx %g2, WSF_SIZEOF, %g3 - add %g1, %g3, %g3 - FILL(ldx, %g3 + PCB_WSCRATCH, EMPTY, WSF) - /* wscratch window becomes unused. */ - stx %g0, [%g3 + PCB_WSCRATCH + WSF_INUSE] - rdpr %otherwin, %g4 - sub %g4, 1, %g4 - stx %g4, [%g1 + PCB_WS_INUSE] + .macro tl0_fill_3_n + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + FILL(lduwa, %sp, 4, %asi) restored retry - .align 128 - .endm + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST64) + RSF_TRAP(T_FILL) + .endm + +ENTRY(tl0_sftrap) + rdpr %tstate, %g1 + and %g1, TSTATE_CWP_MASK, %g1 + wrpr %g1, 0, %cwp + tl0_kstack + rdpr %pil, %o2 + b %xcc, tl0_trap + mov %g2, %o0 +END(tl0_sftrap) + + .macro tl0_spill_bad count + .rept \count + tl0_wide T_SPILL + .endr + .endm .macro tl0_fill_bad count .rept \count @@ -838,22 +902,29 @@ END(tl0_spill_frompcb) .endm .macro tl0_soft count - tl0_reserved \count + .rept \count + tl0_gen T_SOFT + .endr .endm - .macro tl1_gen type + .macro tl1_kstack save %sp, -CCFSZ, %sp - rdpr %pil, %o0 + .endm + + .macro tl1_setup type + tl1_kstack + mov \type | T_KERNEL, %o0 b %xcc, tl1_trap - mov \type | T_KERNEL, %o1 + rdpr %pil, %o2 + .endm + + .macro tl1_gen type + tl1_setup \type .align 32 .endm .macro tl1_wide type - save %sp, -CCFSZ, %sp - rdpr %pil, %o0 - b %xcc, tl1_trap - mov \type | T_KERNEL, %o1 + tl1_setup \type .align 128 .endm @@ -864,103 +935,78 @@ END(tl0_spill_frompcb) .endm .macro tl1_insn_excptn - save %sp, -CCFSZ, %sp - rdpr %pstate, %o0 - wrpr %o0, PSTATE_MG | PSTATE_AG, %pstate - rdpr %pil, %o0 + tl1_kstack + wrpr %g0, PSTATE_ALT, %pstate + rdpr %pil, %o2 b %xcc, tl1_trap - mov T_INSN_EXCPTN | T_KERNEL, %o1 + mov T_INSN_EXCPTN | T_KERNEL, %o0 .align 32 .endm .macro tl1_data_excptn - b %xcc, tl1_sfsr_trap - mov T_DATA_EXCPTN, %g4 + b,a %xcc, tl1_data_exceptn_trap + nop .align 32 .endm - .macro tl1_align - rdpr %pstate, %g1 - wrpr %g1, PSTATE_MG | PSTATE_AG, %pstate +ENTRY(tl1_data_exceptn_trap) + wr %g0, ASI_DMMU, %asi + RESUME_SPILLFILL_MAGIC(%g1, %g2, RSF_MMU, 1f) + stxa %g0, [%g0 + AA_DMMU_SFSR] %asi + done + +1: wrpr %g0, PSTATE_ALT, %pstate b %xcc, tl1_sfsr_trap - mov T_ALIGN, %g4 + mov T_DATA_EXCPTN | T_KERNEL, %g1 +END(tl1_data_exceptn) + + /* + * NOTE: We switch to mmu globals here, to avoid needing to save + * alternates, which may be live. + */ + .macro tl1_align + b %xcc, tl1_align_trap + wrpr %g0, PSTATE_MMU, %pstate .align 32 .endm -/* - * Handle traps that require only sfsr and sfar to be saved. %g4 holds the trap - * type to be used (T_KERNEL is set if appropriate). - * Call with memory globals active. - */ -ENTRY(tl1_sfsr_trap) +ENTRY(tl1_align_trap) wr %g0, ASI_DMMU, %asi + RESUME_SPILLFILL_MAGIC(%g1, %g2, RSF_ALIGN, 1f) + stxa %g0, [%g0 + AA_DMMU_SFSR] %asi + done + +1: wrpr %g0, PSTATE_ALT, %pstate + b %xcc, tl1_sfsr_trap + mov T_ALIGN | T_KERNEL, %g1 +END(tl1_align_trap) + +ENTRY(tl1_sfsr_trap) +! wr %g0, ASI_DMMU, %asi ldxa [%g0 + AA_DMMU_SFAR] %asi, %g2 ldxa [%g0 + AA_DMMU_SFSR] %asi, %g3 stxa %g0, [%g0 + AA_DMMU_SFSR] %asi membar #Sync - /* Fall through. */ -END(tl1_sfsr_trap) -/* - * Handle traps that require MMU frames to be written. The values for TAR, SFAR - * and SFSR are passed in %g1, %g2 and %g3, respectively. - * All traps that may happen during spill/fill for user processes should be - * handled here. - * %g4 contains the trap type, T_KERNEL is set if appropriate. - */ -ENTRY(tl1_mmu_trap) - /* Handle faults during window spill/fill. */ - mov %o1, %g5 - mov %o2, %g6 - rdpr %pstate, %o1 - wrpr %o1, PSTATE_MG | PSTATE_AG, %pstate - ldx [PCPU(CURPCB)], %o2 - ldx [%o2 + PCB_INWINOP], %o2 - rdpr %pstate, %o1 - wrpr %o1, PSTATE_MG | PSTATE_AG, %pstate - mov %g5, %o1 - brz,pt %o2, 1f - mov %g6, %o2 - - wrpr 1, %tl ! go to tl 1 - rdpr %tstate, %g5 - and %g5, TSTATE_CWP_MASK, %g5 - wrpr %g5, %cwp - tl0_split_save - mov %g1, %l1 - mov %g2, %l2 - mov %g3, %l3 - mov %g4, %o1 - rdpr %pstate, %l4 - wrpr %l4, PSTATE_MG | PSTATE_AG, %pstate - tl0_setup_stack %l0, MF_SIZEOF - stx %l1, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_TAR] - stx %l2, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFAR] - stx %l3, [%sp + SPOFF + CCFSZ + TF_SIZEOF + MF_SFSR] - rdpr %pil, %o0 - b %xcc, tl0_trap_withstack - add %sp, SPOFF + CCFSZ + TF_SIZEOF, %o2 - -1: save %sp, -(CCFSZ + MF_SIZEOF), %sp - stx %g1, [%sp + SPOFF + CCFSZ + MF_TAR] + tl1_kstack + sub %sp, MF_SIZEOF, %sp stx %g2, [%sp + SPOFF + CCFSZ + MF_SFAR] stx %g3, [%sp + SPOFF + CCFSZ + MF_SFSR] - or %g4, T_KERNEL, %o1 - rdpr %pstate, %g1 - wrpr %g1, PSTATE_MG | PSTATE_AG, %pstate - rdpr %pil, %o0 + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 b %xcc, tl1_trap - add %sp, SPOFF + CCFSZ, %o2 -END(tl1_mmu_trap) + mov %g1, %o0 +END(tl1_align_trap) .macro tl1_intr level, mask, type - save %sp, -CCFSZ, %sp - rdpr %pil, %o0 + tl1_kstack + rdpr %pil, %o2 wrpr %g0, \level, %pil - set \mask, %o2 - wr %o2, 0, %asr21 + set \mask, %o3 + wr %o3, 0, %asr21 + mov T_INTR | T_KERNEL, %o0 b %xcc, tl1_trap - mov \type | T_KERNEL, %o1 + mov \level, %o1 .align 32 .endm @@ -974,6 +1020,21 @@ END(tl1_mmu_trap) .endm ENTRY(intr_enqueue) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "intr_enqueue: p=%p (%s) tl=%#lx pc=%#lx sp=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + ldx [PCPU(CURPROC)], %g2 + stx %g2, [%g1 + KTR_PARM1] + add %g2, P_COMM, %g2 + stx %g2, [%g1 + KTR_PARM2] + rdpr %tl, %g2 + stx %g2, [%g1 + KTR_PARM3] + rdpr %tpc, %g2 + stx %g2, [%g1 + KTR_PARM4] + stx %sp, [%g1 + KTR_PARM5] +9: +#endif + /* * Find the head of the queue and advance it. */ @@ -983,6 +1044,19 @@ ENTRY(intr_enqueue) and %g3, IQ_MASK, %g3 stx %g3, [%g1 + IQ_HEAD] +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "intr_enqueue: cpu=%d head=%d tail=%d iqe=%d" + , %g4, %g5, %g6, 7, 8, 9) + lduw [PCPU(CPUID)], %g5 + stx %g5, [%g4 + KTR_PARM1] + stx %g3, [%g4 + KTR_PARM2] + ldx [%g1 + IQ_TAIL], %g5 + stx %g5, [%g4 + KTR_PARM3] + stx %g2, [%g4 + KTR_PARM4] +9: +#endif + +#ifdef INVARIANTS /* * If the new head is the same as the tail, the next interrupt will * overwrite unserviced packets. This is bad. @@ -991,6 +1065,7 @@ ENTRY(intr_enqueue) cmp %g4, %g3 be %xcc, 3f nop +#endif /* * Load the interrupt packet from the hardware. @@ -1047,6 +1122,21 @@ ENTRY(intr_enqueue) mov 1, %g3 sllx %g3, %g4, %g3 wr %g3, 0, %asr20 + +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "intr_enqueue: tag=%#lx vec=%#lx pri=%d func=%p arg=%p" + , %g1, %g3, %g4, 7, 8, 9) + lduw [%g2 + IQE_TAG], %g3 + stx %g3, [%g1 + KTR_PARM1] + ldx [%g2 + IQE_VEC], %g3 + stx %g3, [%g1 + KTR_PARM2] + lduw [%g2 + IQE_PRI], %g3 + stx %g3, [%g1 + KTR_PARM3] + stx %g5, [%g1 + KTR_PARM4] + stx %g6, [%g1 + KTR_PARM5] +9: +#endif + retry /* @@ -1056,19 +1146,20 @@ ENTRY(intr_enqueue) */ 2: DEBUGGER() +#ifdef INVARIANTS /* * The interrupt queue is about to overflow. We are in big trouble. */ 3: DEBUGGER() +#endif END(intr_enqueue) .macro tl1_immu_miss - save %sp, -CCFSZ, %sp - rdpr %pstate, %o0 - wrpr %o0, PSTATE_MG | PSTATE_AG, %pstate - rdpr %pil, %o0 + wrpr %g0, PSTATE_ALT, %pstate + tl1_kstack + rdpr %pil, %o2 b %xcc, tl1_trap - mov T_IMMU_MISS | T_KERNEL, %o1 + mov T_IMMU_MISS | T_KERNEL, %o0 .align 128 .endm @@ -1115,19 +1206,27 @@ END(intr_enqueue) stx %g1, [%g2 + ST_TTE + TTE_DATA] /* - * If the mod bit is clear, clear the write bit too. + * Load the tte data into the TLB and retry the instruction. */ -1: andcc %g5, TD_MOD, %g1 - movz %xcc, TD_W, %g1 - andn %g5, %g1, %g5 +1: stxa %g5, [%g0] ASI_DTLB_DATA_IN_REG + retry /* - * Load the tte data into the TLB and retry the instruction. + * Switch to alternate globals. */ - stxa %g5, [%g0] ASI_DTLB_DATA_IN_REG - retry +2: wrpr %g0, PSTATE_ALT, %pstate -2: b,a %xcc, tl1_dmmu_miss_trap + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 + + tl1_kstack + sub %sp, MF_SIZEOF, %sp + stx %g1, [%sp + SPOFF + CCFSZ + MF_TAR] + wrpr %g0, PSTATE_ALT, %pstate + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl1_trap + mov T_DMMU_MISS | T_KERNEL, %o0 .align 128 .endm @@ -1137,217 +1236,290 @@ ENTRY(tl1_dmmu_miss_user) */ dmmu_miss_user - /* Fallthrough. */ -END(tl1_dmmu_miss_user) + /* Handle faults during window spill/fill. */ + RESUME_SPILLFILL_MAGIC(%g1, %g2, RSF_MMU, 1f) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl1_dmmu_miss_user: resume spillfill npc=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + rdpr %tnpc, %g2 + stx %g2, [%g1 + KTR_PARM1] +9: +#endif + done +1: -ENTRY(tl1_dmmu_miss_trap) - /* - * Not in primary tsb, call c code. - * Load the tar, sfar and sfsr aren't valid. - */ - mov AA_DMMU_TAR, %g1 - ldxa [%g1] ASI_DMMU, %g1 - b %xcc, tl1_mmu_trap - mov T_DMMU_MISS, %g4 -END(tl1_dmmu_miss_user) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl1_dmmu_miss_user: trap", %g1, %g2, %g3, 7, 8, 9) +9: +#endif - .macro tl1_dmmu_prot /* - * Load the target tte tag, and extract the context. If the context - * is non-zero handle as user space access. In either case, load the - * tsb 8k pointer. + * Switch to alternate globals. */ - ldxa [%g0] ASI_DMMU_TAG_TARGET_REG, %g1 - srlx %g1, TT_CTX_SHIFT, %g2 - brnz,pn %g2, tl1_dmmu_prot_user - ldxa [%g0] ASI_DMMU_TSB_8KB_PTR_REG, %g2 + wrpr %g0, PSTATE_ALT, %pstate - /* - * Convert the tte pointer to an stte pointer, and add extra bits to - * accomodate for large tsb. - */ - sllx %g2, STTE_SHIFT - TTE_SHIFT, %g2 -#ifdef notyet - mov AA_DMMU_TAR, %g3 - ldxa [%g3] ASI_DMMU, %g3 - srlx %g3, TSB_1M_STTE_SHIFT, %g3 - and %g3, TSB_KERNEL_MASK >> TSB_1M_STTE_SHIFT, %g3 - sllx %g3, TSB_1M_STTE_SHIFT, %g3 - add %g2, %g3, %g2 + wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl1_dmmu_miss: trap sp=%#lx tar=%#lx" + , %g2, %g3, %g4, 7, 8, 9) + stx %sp, [%g2 + KTR_PARM1] + stx %g1, [%g2 + KTR_PARM2] +9: #endif - /* - * Load the tte, check that it's valid, writeable, and that the - * tags match. - */ - ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %g4 - brgez,pn %g5, 2f - andcc %g5, TD_W, %g0 - bz,pn %xcc, 2f - cmp %g4, %g1 - bne %xcc, 2f - EMPTY - - /* - * Set the mod bit in the tte. - */ - or %g5, TD_MOD, %g5 - stx %g5, [%g2 + TTE_DATA] + tl1_kstack + sub %sp, MF_SIZEOF, %sp + stx %g1, [%sp + SPOFF + CCFSZ + MF_TAR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl1_trap + mov T_DMMU_MISS | T_KERNEL, %o0 +END(tl1_dmmu_miss_user) - /* - * Delete the old tlb entry. - */ + .macro tl1_dmmu_prot wr %g0, ASI_DMMU, %asi - ldxa [%g0 + AA_DMMU_TAR] %asi, %g6 - or %g6, TLB_DEMAP_NUCLEUS, %g6 - stxa %g0, [%g6] ASI_DMMU_DEMAP - - /* - * Load the tte data into the tlb, clear the sfsr and retry the - * instruction. - */ - stxa %g5, [%g0] ASI_DTLB_DATA_IN_REG + RESUME_SPILLFILL_MAGIC(%g1, %g2, RSF_MMU, 1f) stxa %g0, [%g0 + AA_DMMU_SFSR] %asi - retry + done /* - * For now just bail. This might cause a red state exception, - * but oh well. - */ -2: DEBUGGER() - .align 128 - .endm - -ENTRY(tl1_dmmu_prot_user) - /* - * Try a fast inline lookup of the primary tsb. + * Switch to alternate globals. */ - dmmu_prot_user +1: wrpr %g0, PSTATE_ALT, %pstate /* - * Not in primary tsb, call c code. * Load the sfar, sfsr and tar. Clear the sfsr. */ - wr %g0, ASI_DMMU, %asi + ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 ldxa [%g0 + AA_DMMU_SFAR] %asi, %g2 ldxa [%g0 + AA_DMMU_SFSR] %asi, %g3 - ldxa [%g0 + AA_DMMU_TAR] %asi, %g1 stxa %g0, [%g0 + AA_DMMU_SFSR] %asi membar #Sync - b %xcc, tl1_mmu_trap - mov T_DMMU_PROT, %g4 -END(tl1_dmmu_prot_user) + tl1_kstack + sub %sp, MF_SIZEOF, %sp + stx %g1, [%sp + SPOFF + CCFSZ + MF_TAR] + stx %g2, [%sp + SPOFF + CCFSZ + MF_SFAR] + stx %g3, [%sp + SPOFF + CCFSZ + MF_SFSR] + rdpr %pil, %o2 + add %sp, SPOFF + CCFSZ, %o1 + b %xcc, tl1_trap + mov T_DMMU_PROT | T_KERNEL, %o0 + .align 128 + .endm .macro tl1_spill_0_n - SPILL(stx, %sp + SPOFF, EMPTY, F) + SPILL(stx, %sp + SPOFF, 8, EMPTY) saved retry - .align 128 + .align 32 + RSF_FATAL(T_SPILL) + RSF_FATAL(T_SPILL) .endm - .macro tl1_spill_1_n - b,a tl1_spill_topcb - .align 128 + .macro tl1_spill_4_n + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: SPILL(stxa, %sp + SPOFF, 8, %asi) + saved + retry + .align 32 + RSF_SPILL_TOPCB + RSF_SPILL_TOPCB + .endm + + .macro tl1_spill_5_n + andcc %sp, 1, %g0 + bnz %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + retry + .align 32 + RSF_SPILL_TOPCB + RSF_SPILL_TOPCB + .endm + + .macro tl1_spill_6_n + wr %g0, ASI_AIUP, %asi + SPILL(stxa, %sp + SPOFF, 8, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TRANSITION | WSTATE_TEST32) + RSF_SPILL_TOPCB + .endm + + .macro tl1_spill_7_n + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TRANSITION | WSTATE_TEST64) + RSF_SPILL_TOPCB .endm - /* - * The following is equivalent to tl1_spill_1_n and is used for - * splitting. - */ .macro tl1_spill_0_o - tl1_spill_1_n + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: SPILL(stxa, %sp + SPOFF, 8, %asi) + saved + wrpr %g0, WSTATE_ASSUME64 << WSTATE_USERSHIFT, %wstate + retry + .align 32 + RSF_SPILL_TOPCB + RSF_SPILL_TOPCB .endm - -/* - * This is used to spill windows that are still occupied with user - * data on kernel entry to the pcb using tl0_flush_save. - */ -ENTRY(tl1_spill_topcb) - /* Free some globals for our use. */ - sub %g6, 32, %g6 - stx %g1, [%g6] - stx %g2, [%g6 + 8] - stx %g3, [%g6 + 16] - stx %g4, [%g6 + 24] - ldx [PCPU(CURPCB)], %g1 - rdpr %cwp, %g2 - mulx %g2, WSF_SIZEOF, %g3 - add %g1, %g3, %g3 - ldx [%g3 + PCB_WSCRATCH + WSF_INUSE], %g4 - brnz,pn %g4, 1f ! window was already spilled to pcb - stx %g1, [%g3 + PCB_WSCRATCH + WSF_INUSE] ! just write sth. != 0 - stx %sp, [%g3 + PCB_WSCRATCH + WSF_SP] - SPILL(stx, %g3 + PCB_WSCRATCH, EMPTY, WSF) - ldx [%g1 + PCB_WS_INUSE], %g4 - add %g4, 1, %g4 - stx %g4, [%g1 + PCB_WS_INUSE] -1: ldx [%g6], %g1 - ldx [%g6 + 8], %g2 - ldx [%g6 + 16], %g3 - ldx [%g6 + 24], %g4 - add %g6, 32, %g6 + + .macro tl1_spill_1_o + andcc %sp, 1, %g0 + bnz %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) saved + wrpr %g0, WSTATE_ASSUME32 << WSTATE_USERSHIFT, %wstate retry -END(tl1_spill_topcb) + .align 32 + RSF_SPILL_TOPCB + RSF_SPILL_TOPCB + .endm - .macro tl1_spill_bad count - .rept \count - tl1_wide T_SPILL - .endr + .macro tl1_spill_2_o + wr %g0, ASI_AIUP, %asi + SPILL(stxa, %sp + SPOFF, 8, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST32 << WSTATE_USERSHIFT) + RSF_SPILL_TOPCB + .endm + + .macro tl1_spill_3_o + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + SPILL(stwa, %sp, 4, %asi) + saved + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST64 << WSTATE_USERSHIFT) + RSF_SPILL_TOPCB .endm .macro tl1_fill_0_n - FILL(ldx, %sp + SPOFF, EMPTY, F) + FILL(ldx, %sp + SPOFF, 8, EMPTY) restored retry - .align 128 + .align 32 + RSF_FATAL(T_FILL) + RSF_FATAL(T_FILL) .endm - .macro tl1_fill_1_n - b,a tl1_fill_frompcb - .align 128 + .macro tl1_fill_4_n + andcc %sp, 1, %g0 + bz,pn %xcc, 2f + wr %g0, ASI_AIUP, %asi +1: FILL(ldxa, %sp + SPOFF, 8, %asi) + restored + retry + .align 32 + RSF_FILL_MAGIC + RSF_FILL_MAGIC .endm - /* Same as tl1_fill_1_n, used for splitting. */ - .macro tl1_fill_0_o - tl1_fill_1_n + .macro tl1_fill_5_n + andcc %sp, 1, %g0 + bnz,pn %xcc, 1b + wr %g0, ASI_AIUP, %asi +2: wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + FILL(lduwa, %sp, 4, %asi) + restored + retry + .align 32 + RSF_FILL_MAGIC + RSF_FILL_MAGIC + .endm + + .macro tl1_fill_6_n + wr %g0, ASI_AIUP, %asi + FILL(ldxa, %sp + SPOFF, 8, %asi) + restored + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST32 | WSTATE_TRANSITION) + RSF_FILL_MAGIC + .endm + + .macro tl1_fill_7_n + wr %g0, ASI_AIUP, %asi + wrpr %g0, PSTATE_ALT | PSTATE_AM, %pstate + FILL(lduwa, %sp, 4, %asi) + restored + retry + .align 32 + RSF_ALIGN_RETRY(WSTATE_TEST64 | WSTATE_TRANSITION) + RSF_FILL_MAGIC .endm /* - * This is invoked only once when a user process is in the kernel: - * to restore the topmost window on user return. We just look up whether - * the window at %cwp was already spilled to the pcb (as inducated by the - * wsf_inuse flag). If so, we indeed need to fill from the pcb, otherwise the - * window is valid and we can just return. + * This is used to spill windows that are still occupied with user + * data on kernel entry to the pcb. */ -ENTRY(tl1_fill_frompcb) +ENTRY(tl1_spill_topcb) + wrpr %g0, PSTATE_ALT, %pstate + /* Free some globals for our use. */ - sub %g6, 32, %g6 + sub %g6, 24, %g6 stx %g1, [%g6] stx %g2, [%g6 + 8] stx %g3, [%g6 + 16] - stx %g4, [%g6 + 24] + ldx [PCPU(CURPCB)], %g1 - rdpr %cwp, %g2 - mulx %g2, WSF_SIZEOF, %g3 - add %g1, %g3, %g3 - ldx [%g3 + PCB_WSCRATCH + WSF_INUSE], %g4 - brz,pn %g4, 1f ! window not spilled and is valid - stx %g0, [%g3 + PCB_WSCRATCH + WSF_INUSE] - FILL(ldx, %g3 + PCB_WSCRATCH, EMPTY, WSF) - ldx [%g1 + PCB_WS_INUSE], %g4 - sub %g4, 1, %g4 - stx %g4, [%g1 + PCB_WS_INUSE] - /* Restore the registers. */ -1: ldx [%g6], %g1 - ldx [%g6 + 8], %g2 + ldx [%g1 + PCB_NSAVED], %g2 + + sllx %g2, 3, %g3 + add %g3, %g1, %g3 + stx %sp, [%g3 + PCB_RWSP] + + sllx %g2, 7, %g3 + add %g3, %g1, %g3 + SPILL(stx, %g3 + PCB_RW, 8, EMPTY) + + inc %g2 + stx %g2, [%g1 + PCB_NSAVED] + +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl1_spill_topcb: pc=%lx sp=%#lx nsaved=%d" + , %g1, %g2, %g3, 7, 8, 9) + rdpr %tpc, %g2 + stx %g2, [%g1 + KTR_PARM1] + stx %sp, [%g1 + KTR_PARM2] + ldx [PCPU(CURPCB)], %g2 + ldx [%g2 + PCB_NSAVED], %g2 + stx %g2, [%g1 + KTR_PARM3] +9: +#endif + + saved + ldx [%g6 + 16], %g3 - ldx [%g6 + 24], %g4 - add %g6, 32, %g6 - restored + ldx [%g6 + 8], %g2 + ldx [%g6], %g1 + add %g6, 24, %g6 retry -END(tl1_fill_frompcb) +END(tl1_spill_topcb) + + .macro tl1_spill_bad count + .rept \count + tl1_wide T_SPILL + .endr + .endm .macro tl1_fill_bad count .rept \count @@ -1361,17 +1533,20 @@ END(tl1_fill_frompcb) .endm ENTRY(tl1_breakpoint_trap) - save %sp, -(CCFSZ + KF_SIZEOF), %sp + tl1_kstack + sub %sp, KF_SIZEOF, %sp flushw stx %fp, [%sp + SPOFF + CCFSZ + KF_FP] - rdpr %pil, %o0 - mov T_BREAKPOINT | T_KERNEL, %o1 + mov T_BREAKPOINT | T_KERNEL, %o0 + add %sp, SPOFF + CCFSZ, %o1 b %xcc, tl1_trap - add %sp, SPOFF + CCFSZ, %o2 + rdpr %pil, %o2 END(tl1_breakpoint_trap) .macro tl1_soft count - tl1_reserved \count + .rept \count + tl1_gen T_SOFT | T_KERNEL + .endr .endm .sect .trap @@ -1416,7 +1591,7 @@ tl0_divide: tl0_gen T_DIVIDE ! 0x28 division by zero tl0_reserved 7 ! 0x29-0x2f reserved tl0_data_excptn: - tl0_gen T_DATA_EXCPTN ! 0x30 data access exception + tl0_data_excptn ! 0x30 data access exception tl0_reserved 1 ! 0x31 reserved tl0_data_error: tl0_gen T_DATA_ERROR ! 0x32 data access error @@ -1450,26 +1625,28 @@ tl0_dmmu_prot: tl0_reserved 16 ! 0x70-0x7f reserved tl0_spill_0_n: tl0_spill_0_n ! 0x80 spill 0 normal -tl0_spill_bad_n: - tl0_spill_bad 7 ! 0x84-0x9f spill normal, other -tl0_spill_0_o: - tl0_spill_0_o ! 0xa0 spill 0 other -tl0_spill_bad_o: - tl0_spill_bad 7 ! 0xa4-0xbf spill normal, other +tl0_spill_1_n: + tl0_spill_1_n ! 0x84 spill 1 normal +tl0_spill_2_n: + tl0_spill_2_n ! 0x88 spill 2 normal +tl0_spill_3_n: + tl0_spill_3_n ! 0x8c spill 3 normal + tl0_spill_bad 12 ! 0x90-0xbf spill normal, other tl0_fill_0_n: tl0_fill_0_n ! 0xc0 fill 0 normal -tl0_fill_bad_n: - tl0_fill_bad 7 ! 0xc4-0xdf fill normal -tl0_fill_0_o: - tl0_fill_0_o ! 0xe0 fill 0 normal -tl0_fill_bad_o: - tl0_fill_bad 7 ! 0xe4-0xff fill other +tl0_fill_1_n: + tl0_fill_1_n ! 0xc4 fill 1 normal +tl0_fill_2_n: + tl0_fill_2_n ! 0xc8 fill 2 normal +tl0_fill_3_n: + tl0_fill_3_n ! 0xcc fill 3 normal + tl0_fill_bad 12 ! 0xc4-0xff fill normal, other tl0_sun_syscall: tl0_reserved 1 ! 0x100 sun system call tl0_breakpoint: tl0_gen T_BREAKPOINT ! 0x101 breakpoint - tl0_soft 7 ! 0x102-0x107 trap instruction - tl0_reserved ! 0x109 SVr4 syscall + tl0_soft 6 ! 0x102-0x107 trap instruction + tl0_soft 1 ! 0x108 SVr4 syscall tl0_gen T_SYSCALL ! 0x109 BSD syscall tl0_soft 118 ! 0x110-0x17f trap instruction tl0_reserved 128 ! 0x180-0x1ff reserved @@ -1546,50 +1723,73 @@ tl1_dmmu_prot: tl1_reserved 16 ! 0x270-0x27f reserved tl1_spill_0_n: tl1_spill_0_n ! 0x280 spill 0 normal -tl1_spill_1_n: - tl1_spill_1_n ! 0x284 spill 1 normal -tl1_spill_bad_n: - tl1_spill_bad 6 ! 0x288-0x29f spill normal + tl1_spill_bad 3 ! 0x284-0x28f spill normal +tl1_spill_4_n: + tl1_spill_4_n ! 0x290 spill 4 normal +tl1_spill_5_n: + tl1_spill_5_n ! 0x294 spill 5 normal +tl1_spill_6_n: + tl1_spill_6_n ! 0x298 spill 6 normal +tl1_spill_7_n: + tl1_spill_7_n ! 0x29c spill 7 normal tl1_spill_0_o: tl1_spill_0_o ! 0x2a0 spill 0 other -tl1_spill_bad_o: - tl1_spill_bad 7 ! 0x2a8-0x2bf spill other +tl1_spill_1_o: + tl1_spill_1_o ! 0x2a4 spill 1 other +tl1_spill_2_o: + tl1_spill_2_o ! 0x2a8 spill 2 other +tl1_spill_3_o: + tl1_spill_3_o ! 0x2ac spill 3 other + tl1_spill_bad 4 ! 0x2a0-0x2bf spill other tl1_fill_0_n: tl1_fill_0_n ! 0x2c0 fill 0 normal -tl1_fill_1_n: - tl1_fill_1_n ! 0x2c4 fill 1 normal -tl1_fill_bad_n: - tl1_fill_bad 6 ! 0x2c8-0x2df fill normal, other -tl1_fill_0_o: - tl1_fill_0_o ! 0x2e0 fill 0 other -tl1_fill_bad_o: - tl1_fill_bad 7 ! 0x2e4-0x2ff fill other + tl1_fill_bad 3 ! 0x2c4-0x2cf fill normal +tl1_fill_4_n: + tl1_fill_4_n ! 0x2d0 fill 4 normal +tl1_fill_5_n: + tl1_fill_5_n ! 0x2d4 fill 5 normal +tl1_fill_6_n: + tl1_fill_6_n ! 0x2d8 fill 6 normal +tl1_fill_7_n: + tl1_fill_7_n ! 0x2dc fill 7 normal + tl1_fill_bad 8 ! 0x2e0-0x2ff fill other tl1_reserved 1 ! 0x300 trap instruction tl1_breakpoint: tl1_breakpoint ! 0x301 breakpoint tl1_gen T_RESTOREWP ! 0x302 restore watchpoint (debug) - tl1_soft 126 ! 0x303-0x37f trap instruction + tl1_soft 125 ! 0x303-0x37f trap instruction tl1_reserved 128 ! 0x380-0x3ff reserved /* - * void tl0_trap(u_long o0, u_long o1, u_long o2, u_long type) + * User trap entry point. + * + * void tl0_trap(u_long type, u_long arg, u_long pil, u_long wstate) + * + * The following setup has been performed: + * - the windows have been split and the active user window has been saved + * (maybe just to the pcb) + * - we are on the current kernel stack and a frame has been setup, there + * may be extra trap specific stuff below the frame + * - we are on alternate globals and interrupts are disabled + * + * We build a trapframe, switch to normal globals, enable interrupts and call + * trap. + * + * NOTE: Due to a chip bug, we must save the trap state registers in memory + * early. + * + * NOTE: We must be very careful setting up the per-cpu pointer. We know that + * it has been pre-set in alternate globals, so we read it from there and setup + * the normal %g7 *before* enabling interrupts. This avoids any possibility + * of cpu migration and using the wrong globalp. */ ENTRY(tl0_trap) - tl0_setup_stack %l0, 0 - /* Fallthrough */ -END(tl0_trap) + /* + * Force kernel store order. + */ + wrpr %g0, PSTATE_ALT, %pstate -ENTRY(tl0_trap_withstack) - ldx [PCPU(CURPCB)], %l1 - rdpr %cwp, %l2 - stx %l2, [%l1 + PCB_CWP] - /* Finish setting up splitted windows. */ - wrpr %g0, 0, %wstate - rdpr %canrestore, %l0 - rdpr %otherwin, %l1 - add %l0, %l1, %l0 - wrpr %g0, 0, %canrestore - wrpr %l0, %otherwin + sub %sp, TF_SIZEOF, %sp rdpr %tstate, %l0 stx %l0, [%sp + SPOFF + CCFSZ + TF_TSTATE] @@ -1598,9 +1798,16 @@ ENTRY(tl0_trap_withstack) rdpr %tnpc, %l2 stx %l2, [%sp + SPOFF + CCFSZ + TF_TNPC] + stx %o0, [%sp + SPOFF + CCFSZ + TF_TYPE] + stx %o1, [%sp + SPOFF + CCFSZ + TF_ARG] + stx %o2, [%sp + SPOFF + CCFSZ + TF_PIL] + stx %o3, [%sp + SPOFF + CCFSZ + TF_WSTATE] + +.Ltl0_trap_fill: mov %g7, %l0 - rdpr %pstate, %l1 - wrpr %l1, PSTATE_AG, %pstate + wrpr %g0, PSTATE_NORMAL, %pstate + mov %l0, %g7 /* set up the normal %g7 */ + wrpr %g0, PSTATE_KERNEL, %pstate stx %g1, [%sp + SPOFF + CCFSZ + TF_G1] stx %g2, [%sp + SPOFF + CCFSZ + TF_G2] @@ -1610,10 +1817,17 @@ ENTRY(tl0_trap_withstack) stx %g6, [%sp + SPOFF + CCFSZ + TF_G6] stx %g7, [%sp + SPOFF + CCFSZ + TF_G7] - mov %l0, %g7 /* set up the normal %g7 */ - - rdpr %pstate, %l1 - wrpr %l1, PSTATE_IE, %pstate +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_trap: p=%p type=%#x arg=%#lx pil=%#lx ws=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + ldx [PCPU(CURPROC)], %g2 + stx %g2, [%g1 + KTR_PARM1] + stx %o0, [%g1 + KTR_PARM2] + stx %o1, [%g1 + KTR_PARM3] + stx %o2, [%g1 + KTR_PARM4] + stx %o3, [%g1 + KTR_PARM5] +9: +#endif stx %i0, [%sp + SPOFF + CCFSZ + TF_O0] stx %i1, [%sp + SPOFF + CCFSZ + TF_O1] @@ -1624,18 +1838,44 @@ ENTRY(tl0_trap_withstack) stx %i6, [%sp + SPOFF + CCFSZ + TF_O6] stx %i7, [%sp + SPOFF + CCFSZ + TF_O7] - stx %o0, [%sp + SPOFF + CCFSZ + TF_PIL] - stx %o1, [%sp + SPOFF + CCFSZ + TF_TYPE] - stx %o2, [%sp + SPOFF + CCFSZ + TF_ARG] - +.Ltl0_trap_spill: call trap add %sp, CCFSZ + SPOFF, %o0 /* Fallthough. */ -END(tl0_trap_withstack) +END(tl0_trap) /* Return to tl0 (user process). */ ENTRY(tl0_ret) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_ret: p=%p (%s) pil=%#lx sflag=%#x" + , %g1, %g2, %g3, 7, 8, 9) + ldx [PCPU(CURPROC)], %g2 + stx %g2, [%g1 + KTR_PARM1] + add %g2, P_COMM, %g3 + stx %g3, [%g1 + KTR_PARM2] + rdpr %pil, %g3 + stx %g3, [%g1 + KTR_PARM3] + lduw [%g2 + P_SFLAG], %g3 + stx %g3, [%g1 + KTR_PARM4] +9: +#endif + + wrpr %g0, PIL_TICK, %pil + ldx [PCPU(CURPROC)], %o0 + lduw [%o0 + P_SFLAG], %o1 + and %o1, PS_ASTPENDING | PS_NEEDRESCHED, %o1 + brz,pt %o1, 1f + nop + call ast + add %sp, CCFSZ + SPOFF, %o0 + +1: ldx [PCPU(CURPCB)], %o0 + ldx [%o0 + PCB_NSAVED], %o1 + mov T_SPILL, %o0 + brnz,a,pn %o1, .Ltl0_trap_spill + stx %o0, [%sp + SPOFF + CCFSZ + TF_TYPE] + ldx [%sp + SPOFF + CCFSZ + TF_G1], %g1 ldx [%sp + SPOFF + CCFSZ + TF_G2], %g2 ldx [%sp + SPOFF + CCFSZ + TF_G3], %g3 @@ -1644,71 +1884,99 @@ ENTRY(tl0_ret) ldx [%sp + SPOFF + CCFSZ + TF_G6], %g6 ldx [%sp + SPOFF + CCFSZ + TF_G7], %g7 - rdpr %pstate, %o0 - wrpr %o0, PSTATE_IE | PSTATE_AG, %pstate - mov %sp, %g1 + ldx [%sp + SPOFF + CCFSZ + TF_O0], %i0 + ldx [%sp + SPOFF + CCFSZ + TF_O1], %i1 + ldx [%sp + SPOFF + CCFSZ + TF_O2], %i2 + ldx [%sp + SPOFF + CCFSZ + TF_O3], %i3 + ldx [%sp + SPOFF + CCFSZ + TF_O4], %i4 + ldx [%sp + SPOFF + CCFSZ + TF_O5], %i5 + ldx [%sp + SPOFF + CCFSZ + TF_O6], %i6 + ldx [%sp + SPOFF + CCFSZ + TF_O7], %i7 + + ldx [%sp + SPOFF + CCFSZ + TF_PIL], %l0 + ldx [%sp + SPOFF + CCFSZ + TF_TSTATE], %l1 + ldx [%sp + SPOFF + CCFSZ + TF_TPC], %l2 + ldx [%sp + SPOFF + CCFSZ + TF_TNPC], %l3 + ldx [%sp + SPOFF + CCFSZ + TF_WSTATE], %l4 + + wrpr %g0, PSTATE_ALT, %pstate + + wrpr %l0, 0, %pil + + wrpr %l1, 0, %tstate + wrpr %l2, 0, %tpc + wrpr %l3, 0, %tnpc /* * Restore the user window state. - * Note: whenever we come here, it should be with %canrestore = 0. + * NOTE: whenever we come here, it should be with %canrestore = 0. */ - ldx [PCPU(CURPCB)], %g4 - ldx [%g4 + PCB_CWP], %g2 - wrpr %g2, %cwp + srlx %l4, WSTATE_USERSHIFT, %g1 + wrpr %g1, WSTATE_TRANSITION, %wstate + rdpr %otherwin, %g2 + wrpr %g2, 0, %canrestore + wrpr %g0, 0, %otherwin + wrpr %g2, 0, %cleanwin /* - * Set up window state for restore. If all windows were spilled, - * %otherwin may be 0, so just set %wstate to 1 to invoke a - * special fill handler (fill traps with %wstate == 1 invoke the - * same handler regardless of %otherwin). + * If this instruction causes a fill trap which fails to fill a window + * from the user stack, we will resume at tl0_ret_fill_end and call + * back into the kernel. */ - wrpr %g0, 1, %wstate - restore ! This will invoke the otherwin fill handler. - wrpr %g0, 0, %wstate - - /* Set up window state for return. */ - ldx [%g4 + PCB_WS_INUSE], %g2 - rdpr %otherwin, %g3 - sub %g3, %g2, %g3 - wrpr %g2, 0, %otherwin - movrlz %g3, %g0, %g3 - wrpr %g3, %canrestore - add %g2, %g3, %g2 - rdpr %ver, %g3 - and %g3, VER_MAXWIN_MASK, %g3 - sub %g3, 1, %g3 ! VER.MAXWIN is NWINDOWS - 1. - sub %g3, %g2, %g3 - wrpr %g3, %cansave - - ldx [%g1 + SPOFF + CCFSZ + TF_O0], %o0 - ldx [%g1 + SPOFF + CCFSZ + TF_O1], %o1 - ldx [%g1 + SPOFF + CCFSZ + TF_O2], %o2 - ldx [%g1 + SPOFF + CCFSZ + TF_O3], %o3 - ldx [%g1 + SPOFF + CCFSZ + TF_O4], %o4 - ldx [%g1 + SPOFF + CCFSZ + TF_O5], %o5 - ldx [%g1 + SPOFF + CCFSZ + TF_O6], %o6 - ldx [%g1 + SPOFF + CCFSZ + TF_O7], %o7 + restore +tl0_ret_fill: - ldx [%g1 + SPOFF + CCFSZ + TF_PIL], %g2 - wrpr %g2, 0, %pil - ldx [%g1 + SPOFF + CCFSZ + TF_TSTATE], %g2 - andn %g2, TSTATE_CWP_MASK, %g2 - rdpr %cwp, %g3 - or %g2, %g3, %g2 - wrpr %g2, %tstate - ldx [%g1 + SPOFF + CCFSZ + TF_TPC], %g2 - wrpr %g2, 0, %tpc - ldx [%g1 + SPOFF + CCFSZ + TF_TNPC], %g2 - wrpr %g2, 0, %tnpc +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_ret: return p=%#lx pil=%#lx ts=%#lx pc=%#lx sp=%#lx" + , %g2, %g3, %g4, 7, 8, 9) + ldx [PCPU(CURPROC)], %g3 + stx %g3, [%g2 + KTR_PARM1] + rdpr %tstate, %g3 + stx %g3, [%g2 + KTR_PARM2] + rdpr %tpc, %g3 + stx %g3, [%g2 + KTR_PARM3] + stx %sp, [%g2 + KTR_PARM4] + stx %g1, [%g2 + KTR_PARM5] +9: +#endif + wrpr %g1, 0, %wstate retry +tl0_ret_fill_end: + +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "tl0_ret: fill magic wstate=%#lx sp=%#lx" + , %l0, %l1, %l2, 7, 8, 9) + stx %l4, [%l0 + KTR_PARM1] + stx %sp, [%l0 + KTR_PARM2] +9: +#endif + + /* + * The fill failed and magic has been preformed. Call trap again, + * which will copyin the window on the user's behalf. + */ + wrpr %l4, 0, %wstate + mov T_FILL, %o0 + b %xcc, .Ltl0_trap_fill + stx %o0, [%sp + SPOFF + CCFSZ + TF_TYPE] END(tl0_ret) /* - * void tl1_trap(u_long o0, u_long o1, u_long o2, u_long type) + * Kernel trap entry point + * + * void tl1_trap(u_long type, u_long arg, u_long pil) + * + * This is easy because the stack is already setup and the windows don't need + * to be split. We build a trapframe and call trap(), the same as above, but + * the outs don't need to be saved. + * + * NOTE: See comments above tl0_trap for song and dance about chip bugs and + * setting up globalp. */ ENTRY(tl1_trap) sub %sp, TF_SIZEOF, %sp + rdpr %tstate, %l0 stx %l0, [%sp + SPOFF + CCFSZ + TF_TSTATE] rdpr %tpc, %l1 @@ -1716,15 +1984,42 @@ ENTRY(tl1_trap) rdpr %tnpc, %l2 stx %l2, [%sp + SPOFF + CCFSZ + TF_TNPC] +#if KTR_COMPILE & KTR_CT1 + setx trap_mask, %l4, %l3 + andn %o1, T_KERNEL, %l4 + mov 1, %l5 + sllx %l5, %l4, %l4 + ldx [%l3], %l5 + and %l4, %l5, %l4 + brz %l4, 9f + nop + CATR(KTR_CT1, "tl1_trap: p=%p pil=%#lx type=%#lx arg=%#lx pc=%#lx" + , %l3, %l4, %l5, 7, 8, 9) + ldx [PCPU(CURPROC)], %l4 + stx %l4, [%l3 + KTR_PARM1] +#if 0 + add %l4, P_COMM, %l4 + stx %l4, [%l3 + KTR_PARM2] +#else + stx %o2, [%l3 + KTR_PARM2] +#endif + andn %o0, T_KERNEL, %l4 + stx %l4, [%l3 + KTR_PARM3] + stx %o1, [%l3 + KTR_PARM4] + stx %l1, [%l3 + KTR_PARM5] +9: +#endif + wrpr %g0, 1, %tl /* We may have trapped before %g7 was set up correctly. */ - mov %g7, %l3 - rdpr %pstate, %l0 - wrpr %l0, PSTATE_AG, %pstate + mov %g7, %l0 + wrpr %g0, PSTATE_NORMAL, %pstate + mov %l0, %g7 + wrpr %g0, PSTATE_KERNEL, %pstate - stx %o0, [%sp + SPOFF + CCFSZ + TF_PIL] - stx %o1, [%sp + SPOFF + CCFSZ + TF_TYPE] - stx %o2, [%sp + SPOFF + CCFSZ + TF_ARG] + stx %o0, [%sp + SPOFF + CCFSZ + TF_TYPE] + stx %o1, [%sp + SPOFF + CCFSZ + TF_ARG] + stx %o2, [%sp + SPOFF + CCFSZ + TF_PIL] stx %g1, [%sp + SPOFF + CCFSZ + TF_G1] stx %g2, [%sp + SPOFF + CCFSZ + TF_G2] @@ -1732,12 +2027,7 @@ ENTRY(tl1_trap) stx %g4, [%sp + SPOFF + CCFSZ + TF_G4] stx %g5, [%sp + SPOFF + CCFSZ + TF_G5] stx %g6, [%sp + SPOFF + CCFSZ + TF_G6] - stx %g7, [%sp + SPOFF + CCFSZ + TF_G7] - mov %l3, %g7 - rdpr %pstate, %l0 - wrpr %l0, PSTATE_IE, %pstate - call trap add %sp, CCFSZ + SPOFF, %o0 @@ -1747,16 +2037,13 @@ ENTRY(tl1_trap) ldx [%sp + SPOFF + CCFSZ + TF_G4], %g4 ldx [%sp + SPOFF + CCFSZ + TF_G5], %g5 ldx [%sp + SPOFF + CCFSZ + TF_G6], %g6 - ldx [%sp + SPOFF + CCFSZ + TF_G7], %g7 ldx [%sp + SPOFF + CCFSZ + TF_PIL], %l0 ldx [%sp + SPOFF + CCFSZ + TF_TSTATE], %l1 ldx [%sp + SPOFF + CCFSZ + TF_TPC], %l2 ldx [%sp + SPOFF + CCFSZ + TF_TNPC], %l3 - rdpr %pstate, %o0 - andn %o0, PSTATE_IE, %o0 - wrpr %o0, 0, %pstate + wrpr %g0, PSTATE_ALT, %pstate wrpr %l0, 0, %pil @@ -1765,11 +2052,47 @@ ENTRY(tl1_trap) wrpr %l2, 0, %tpc wrpr %l3, 0, %tnpc +#if KTR_COMPILE & KTR_CT1 + ldx [%sp + SPOFF + CCFSZ + TF_TYPE], %l5 + andn %l5, T_KERNEL, %l4 + mov 1, %l5 + sllx %l5, %l4, %l4 + setx trap_mask, %l4, %l3 + ldx [%l3], %l5 + and %l4, %l5, %l4 + brz %l4, 9f + nop + CATR(KTR_CT1, "tl1_trap: return p=%p pil=%#lx sp=%#lx pc=%#lx" + , %l3, %l4, %l5, 7, 8, 9) + ldx [PCPU(CURPROC)], %l4 + stx %l4, [%l3 + KTR_PARM1] + stx %l0, [%l3 + KTR_PARM2] + stx %sp, [%l3 + KTR_PARM3] + stx %l2, [%l3 + KTR_PARM4] +9: +#endif + restore retry END(tl1_trap) +/* + * Freshly forked processes come here when switched to for the first time. + * The arguments to fork_exit() have been setup in the locals, we must move + * them to the outs. + */ ENTRY(fork_trampoline) +#if KTR_COMPILE & KTR_CT1 + CATR(KTR_CT1, "fork_trampoline: p=%p (%s) cwp=%#lx" + , %g1, %g2, %g3, 7, 8, 9) + ldx [PCPU(CURPROC)], %g2 + stx %g2, [%g1 + KTR_PARM1] + add %g2, P_COMM, %g2 + stx %g2, [%g1 + KTR_PARM2] + rdpr %cwp, %g2 + stx %g2, [%g1 + KTR_PARM3] +9: +#endif mov %l0, %o0 mov %l1, %o1 mov %l2, %o2 diff --git a/sys/sparc64/sparc64/rwindow.c b/sys/sparc64/sparc64/rwindow.c new file mode 100644 index 0000000000000..474e6a9a2e958 --- /dev/null +++ b/sys/sparc64/sparc64/rwindow.c @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Berkeley Software Design Inc's name may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: BSDI: trap.c,v 1.17.2.9 1999/10/19 15:29:52 cp Exp + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ktr.h> +#include <sys/proc.h> +#include <sys/user.h> + +#include <machine/frame.h> + +int +rwindow_load(struct proc *p, struct trapframe *tf, int n) +{ + struct rwindow rw; + u_long usp; + int error; + int i; + + /* + * In case current window is still only on-chip, push it out; + * if it cannot get all the way out, we cannot continue either. + */ + if ((error = rwindow_save(p)) != 0) + return (error); + usp = tf->tf_out[6]; + CTR3(KTR_TRAP, "rwindow_load: p=%p (%s) n=%d", + p, p->p_comm, n); + for (i = 0; i < n; i++) { + CTR1(KTR_TRAP, "rwindow_load: usp=%#lx", usp); + usp += SPOFF; + error = copyin((void *)usp, &rw, sizeof rw); + usp = rw.rw_in[6]; + } + CTR1(KTR_TRAP, "rwindow_load: error=%d", error); + return (error); +} + +int +rwindow_save(struct proc *p) +{ + struct rwindow *rw; + struct pcb *pcb; + u_long *ausp; + u_long usp; + int error; + int i; + + flushw(); + pcb = &p->p_addr->u_pcb; + i = pcb->pcb_nsaved; + CTR3(KTR_TRAP, "rwindow_save: p=%p (%s) nsaved=%d", p, p->p_comm, i); + if (i == 0) + return (0); + ausp = pcb->pcb_rwsp; + rw = pcb->pcb_rw; + error = 0; + do { + usp = *ausp; + CTR1(KTR_TRAP, "rwindow_save: usp=%#lx", usp); + usp += SPOFF; + error = copyout(rw, (void *)usp, sizeof *rw); + if (error) + break; + ausp++; + rw++; + } while (--i > 0); + CTR1(KTR_TRAP, "rwindow_save: error=%d", error); + if (error == 0) + pcb->pcb_nsaved = 0; + return (error); +} |
