X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=arch%2Fsparc64%2Fkernel%2Fwinfixup.S;fp=arch%2Fsparc64%2Fkernel%2Fwinfixup.S;h=39160926267b61b7ee816a90c25dbd014b467dfa;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=c4aa110a10e5c25882896b001df4a3e5f89fd771;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index c4aa110a1..391609262 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S @@ -1,6 +1,8 @@ -/* winfixup.S: Handle cases where user stack pointer is found to be bogus. +/* $Id: winfixup.S,v 1.30 2002/02/09 19:49:30 davem Exp $ * - * Copyright (C) 1997, 2006 David S. Miller (davem@davemloft.net) + * winfixup.S: Handle cases where user stack pointer is found to be bogus. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ #include @@ -13,144 +15,374 @@ .text - /* It used to be the case that these register window fault - * handlers could run via the save and restore instructions - * done by the trap entry and exit code. They now do the - * window spill/fill by hand, so that case no longer can occur. - */ +set_pcontext: + sethi %hi(sparc64_kern_pri_context), %l1 + ldx [%l1 + %lo(sparc64_kern_pri_context)], %l1 + mov PRIMARY_CONTEXT, %g1 + stxa %l1, [%g1] ASI_DMMU + flush %g6 + retl + nop .align 32 + + /* Here are the rules, pay attention. + * + * The kernel is disallowed from touching user space while + * the trap level is greater than zero, except for from within + * the window spill/fill handlers. This must be followed + * so that we can easily detect the case where we tried to + * spill/fill with a bogus (or unmapped) user stack pointer. + * + * These are layed out in a special way for cache reasons, + * don't touch... + */ + .globl fill_fixup, spill_fixup fill_fixup: - TRAP_LOAD_THREAD_REG(%g6, %g1) - rdpr %tstate, %g1 - and %g1, TSTATE_CWP, %g1 - or %g4, FAULT_CODE_WINFIXUP, %g4 - stb %g4, [%g6 + TI_FAULT_CODE] - stx %g5, [%g6 + TI_FAULT_ADDR] - wrpr %g1, %cwp - ba,pt %xcc, etrap - rd %pc, %g7 - call do_sparc64_fault - add %sp, PTREGS_OFF, %o0 - ba,pt %xcc, rtrap_clr_l6 + rdpr %tstate, %g1 + andcc %g1, TSTATE_PRIV, %g0 + or %g4, FAULT_CODE_WINFIXUP, %g4 + be,pt %xcc, window_scheisse_from_user_common + and %g1, TSTATE_CWP, %g1 + + /* This is the extremely complex case, but it does happen from + * time to time if things are just right. Essentially the restore + * done in rtrap right before going back to user mode, with tl=1 + * and that levels trap stack registers all setup, took a fill trap, + * the user stack was not mapped in the tlb, and tlb miss occurred, + * the pte found was not valid, and a simple ref bit watch update + * could not satisfy the miss, so we got here. + * + * We must carefully unwind the state so we get back to tl=0, preserve + * all the register values we were going to give to the user. Luckily + * most things are where they need to be, we also have the address + * which triggered the fault handy as well. + * + * Also note that we must preserve %l5 and %l6. If the user was + * returning from a system call, we must make it look this way + * after we process the fill fault on the users stack. + * + * First, get into the window where the original restore was executed. + */ + + rdpr %wstate, %g2 ! Grab user mode wstate. + wrpr %g1, %cwp ! Get into the right window. + sll %g2, 3, %g2 ! NORMAL-->OTHER + + wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + wrpr %g2, 0x0, %wstate ! This must be consistent. + wrpr %g0, 0x0, %otherwin ! We know this. + call set_pcontext ! Change contexts... nop + rdpr %pstate, %l1 ! Prepare to change globals. + mov %g6, %o7 ! Get current. + + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO + stb %g4, [%g6 + TI_FAULT_CODE] + stx %g5, [%g6 + TI_FAULT_ADDR] + wrpr %g0, 0x0, %tl ! Out of trap levels. + wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate + mov %o7, %g6 + ldx [%g6 + TI_TASK], %g4 +#ifdef CONFIG_SMP + mov TSB_REG, %g1 + ldxa [%g1] ASI_IMMU, %g5 +#endif - /* Be very careful about usage of the trap globals here. - * You cannot touch %g5 as that has the fault information. + /* This is the same as below, except we handle this a bit special + * since we must preserve %l5 and %l6, see comment above. + */ + call do_sparc64_fault + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + nop ! yes, nop is correct + + /* Be very careful about usage of the alternate globals here. + * You cannot touch %g4/%g5 as that has the fault information + * should this be from usermode. Also be careful for the case + * where we get here from the save instruction in etrap.S when + * coming from either user or kernel (does not matter which, it + * is the same problem in both cases). Essentially this means + * do not touch %g7 or %g2 so we handle the two cases fine. */ spill_fixup: -spill_fixup_mna: -spill_fixup_dax: - TRAP_LOAD_THREAD_REG(%g6, %g1) - ldx [%g6 + TI_FLAGS], %g1 - andcc %g1, _TIF_32BIT, %g0 - ldub [%g6 + TI_WSAVED], %g1 - sll %g1, 3, %g3 - add %g6, %g3, %g3 - stx %sp, [%g3 + TI_RWIN_SPTRS] - sll %g1, 7, %g3 - bne,pt %xcc, 1f - add %g6, %g3, %g3 - stx %l0, [%g3 + TI_REG_WINDOW + 0x00] - stx %l1, [%g3 + TI_REG_WINDOW + 0x08] - stx %l2, [%g3 + TI_REG_WINDOW + 0x10] - stx %l3, [%g3 + TI_REG_WINDOW + 0x18] - stx %l4, [%g3 + TI_REG_WINDOW + 0x20] - stx %l5, [%g3 + TI_REG_WINDOW + 0x28] - stx %l6, [%g3 + TI_REG_WINDOW + 0x30] - stx %l7, [%g3 + TI_REG_WINDOW + 0x38] - stx %i0, [%g3 + TI_REG_WINDOW + 0x40] - stx %i1, [%g3 + TI_REG_WINDOW + 0x48] - stx %i2, [%g3 + TI_REG_WINDOW + 0x50] - stx %i3, [%g3 + TI_REG_WINDOW + 0x58] - stx %i4, [%g3 + TI_REG_WINDOW + 0x60] - stx %i5, [%g3 + TI_REG_WINDOW + 0x68] - stx %i6, [%g3 + TI_REG_WINDOW + 0x70] - ba,pt %xcc, 2f - stx %i7, [%g3 + TI_REG_WINDOW + 0x78] -1: stw %l0, [%g3 + TI_REG_WINDOW + 0x00] - stw %l1, [%g3 + TI_REG_WINDOW + 0x04] - stw %l2, [%g3 + TI_REG_WINDOW + 0x08] - stw %l3, [%g3 + TI_REG_WINDOW + 0x0c] - stw %l4, [%g3 + TI_REG_WINDOW + 0x10] - stw %l5, [%g3 + TI_REG_WINDOW + 0x14] - stw %l6, [%g3 + TI_REG_WINDOW + 0x18] - stw %l7, [%g3 + TI_REG_WINDOW + 0x1c] - stw %i0, [%g3 + TI_REG_WINDOW + 0x20] - stw %i1, [%g3 + TI_REG_WINDOW + 0x24] - stw %i2, [%g3 + TI_REG_WINDOW + 0x28] - stw %i3, [%g3 + TI_REG_WINDOW + 0x2c] - stw %i4, [%g3 + TI_REG_WINDOW + 0x30] - stw %i5, [%g3 + TI_REG_WINDOW + 0x34] - stw %i6, [%g3 + TI_REG_WINDOW + 0x38] - stw %i7, [%g3 + TI_REG_WINDOW + 0x3c] -2: add %g1, 1, %g1 - stb %g1, [%g6 + TI_WSAVED] - rdpr %tstate, %g1 - andcc %g1, TSTATE_PRIV, %g0 + ldx [%g6 + TI_FLAGS], %g1 + andcc %g1, _TIF_32BIT, %g0 + ldub [%g6 + TI_WSAVED], %g1 + + sll %g1, 3, %g3 + add %g6, %g3, %g3 + stx %sp, [%g3 + TI_RWIN_SPTRS] + sll %g1, 7, %g3 + bne,pt %xcc, 1f + add %g6, %g3, %g3 + stx %l0, [%g3 + TI_REG_WINDOW + 0x00] + stx %l1, [%g3 + TI_REG_WINDOW + 0x08] + + stx %l2, [%g3 + TI_REG_WINDOW + 0x10] + stx %l3, [%g3 + TI_REG_WINDOW + 0x18] + stx %l4, [%g3 + TI_REG_WINDOW + 0x20] + stx %l5, [%g3 + TI_REG_WINDOW + 0x28] + stx %l6, [%g3 + TI_REG_WINDOW + 0x30] + stx %l7, [%g3 + TI_REG_WINDOW + 0x38] + stx %i0, [%g3 + TI_REG_WINDOW + 0x40] + stx %i1, [%g3 + TI_REG_WINDOW + 0x48] + + stx %i2, [%g3 + TI_REG_WINDOW + 0x50] + stx %i3, [%g3 + TI_REG_WINDOW + 0x58] + stx %i4, [%g3 + TI_REG_WINDOW + 0x60] + stx %i5, [%g3 + TI_REG_WINDOW + 0x68] + stx %i6, [%g3 + TI_REG_WINDOW + 0x70] + b,pt %xcc, 2f + stx %i7, [%g3 + TI_REG_WINDOW + 0x78] +1: stw %l0, [%g3 + TI_REG_WINDOW + 0x00] + + stw %l1, [%g3 + TI_REG_WINDOW + 0x04] + stw %l2, [%g3 + TI_REG_WINDOW + 0x08] + stw %l3, [%g3 + TI_REG_WINDOW + 0x0c] + stw %l4, [%g3 + TI_REG_WINDOW + 0x10] + stw %l5, [%g3 + TI_REG_WINDOW + 0x14] + stw %l6, [%g3 + TI_REG_WINDOW + 0x18] + stw %l7, [%g3 + TI_REG_WINDOW + 0x1c] + stw %i0, [%g3 + TI_REG_WINDOW + 0x20] + + stw %i1, [%g3 + TI_REG_WINDOW + 0x24] + stw %i2, [%g3 + TI_REG_WINDOW + 0x28] + stw %i3, [%g3 + TI_REG_WINDOW + 0x2c] + stw %i4, [%g3 + TI_REG_WINDOW + 0x30] + stw %i5, [%g3 + TI_REG_WINDOW + 0x34] + stw %i6, [%g3 + TI_REG_WINDOW + 0x38] + stw %i7, [%g3 + TI_REG_WINDOW + 0x3c] +2: add %g1, 1, %g1 + + stb %g1, [%g6 + TI_WSAVED] + rdpr %tstate, %g1 + andcc %g1, TSTATE_PRIV, %g0 saved - be,pn %xcc, 1f - and %g1, TSTATE_CWP, %g1 + and %g1, TSTATE_CWP, %g1 + be,pn %xcc, window_scheisse_from_user_common + mov FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4 retry -1: mov FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4 - stb %g4, [%g6 + TI_FAULT_CODE] - stx %g5, [%g6 + TI_FAULT_ADDR] - wrpr %g1, %cwp - ba,pt %xcc, etrap - rd %pc, %g7 - call do_sparc64_fault - add %sp, PTREGS_OFF, %o0 - ba,a,pt %xcc, rtrap_clr_l6 +window_scheisse_from_user_common: + stb %g4, [%g6 + TI_FAULT_CODE] + stx %g5, [%g6 + TI_FAULT_ADDR] + wrpr %g1, %cwp + ba,pt %xcc, etrap + rd %pc, %g7 + call do_sparc64_fault + add %sp, PTREGS_OFF, %o0 + ba,a,pt %xcc, rtrap_clr_l6 + + .globl winfix_mna, fill_fixup_mna, spill_fixup_mna winfix_mna: - andn %g3, 0x7f, %g3 - add %g3, 0x78, %g3 - wrpr %g3, %tnpc + andn %g3, 0x7f, %g3 + add %g3, 0x78, %g3 + wrpr %g3, %tnpc done - fill_fixup_mna: - rdpr %tstate, %g1 - and %g1, TSTATE_CWP, %g1 - wrpr %g1, %cwp - ba,pt %xcc, etrap - rd %pc, %g7 - sethi %hi(tlb_type), %g1 - lduw [%g1 + %lo(tlb_type)], %g1 - cmp %g1, 3 - bne,pt %icc, 1f - add %sp, PTREGS_OFF, %o0 - mov %l4, %o2 - call sun4v_do_mna - mov %l5, %o1 - ba,a,pt %xcc, rtrap_clr_l6 -1: mov %l4, %o1 - mov %l5, %o2 - call mem_address_unaligned + rdpr %tstate, %g1 + andcc %g1, TSTATE_PRIV, %g0 + be,pt %xcc, window_mna_from_user_common + and %g1, TSTATE_CWP, %g1 + + /* Please, see fill_fixup commentary about why we must preserve + * %l5 and %l6 to preserve absolute correct semantics. + */ + rdpr %wstate, %g2 ! Grab user mode wstate. + wrpr %g1, %cwp ! Get into the right window. + sll %g2, 3, %g2 ! NORMAL-->OTHER + wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + + wrpr %g2, 0x0, %wstate ! This must be consistent. + wrpr %g0, 0x0, %otherwin ! We know this. + call set_pcontext ! Change contexts... nop - ba,a,pt %xcc, rtrap_clr_l6 + rdpr %pstate, %l1 ! Prepare to change globals. + mov %g4, %o2 ! Setup args for + mov %g5, %o1 ! final call to mem_address_unaligned. + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO + mov %g6, %o7 ! Stash away current. + wrpr %g0, 0x0, %tl ! Out of trap levels. + wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate + mov %o7, %g6 ! Get current back. + ldx [%g6 + TI_TASK], %g4 ! Finish it. +#ifdef CONFIG_SMP + mov TSB_REG, %g1 + ldxa [%g1] ASI_IMMU, %g5 +#endif + call mem_address_unaligned + add %sp, PTREGS_OFF, %o0 + + b,pt %xcc, rtrap + nop ! yes, the nop is correct +spill_fixup_mna: + ldx [%g6 + TI_FLAGS], %g1 + andcc %g1, _TIF_32BIT, %g0 + ldub [%g6 + TI_WSAVED], %g1 + sll %g1, 3, %g3 + add %g6, %g3, %g3 + stx %sp, [%g3 + TI_RWIN_SPTRS] + + sll %g1, 7, %g3 + bne,pt %xcc, 1f + add %g6, %g3, %g3 + stx %l0, [%g3 + TI_REG_WINDOW + 0x00] + stx %l1, [%g3 + TI_REG_WINDOW + 0x08] + stx %l2, [%g3 + TI_REG_WINDOW + 0x10] + stx %l3, [%g3 + TI_REG_WINDOW + 0x18] + stx %l4, [%g3 + TI_REG_WINDOW + 0x20] + + stx %l5, [%g3 + TI_REG_WINDOW + 0x28] + stx %l6, [%g3 + TI_REG_WINDOW + 0x30] + stx %l7, [%g3 + TI_REG_WINDOW + 0x38] + stx %i0, [%g3 + TI_REG_WINDOW + 0x40] + stx %i1, [%g3 + TI_REG_WINDOW + 0x48] + stx %i2, [%g3 + TI_REG_WINDOW + 0x50] + stx %i3, [%g3 + TI_REG_WINDOW + 0x58] + stx %i4, [%g3 + TI_REG_WINDOW + 0x60] + + stx %i5, [%g3 + TI_REG_WINDOW + 0x68] + stx %i6, [%g3 + TI_REG_WINDOW + 0x70] + stx %i7, [%g3 + TI_REG_WINDOW + 0x78] + b,pt %xcc, 2f + add %g1, 1, %g1 +1: std %l0, [%g3 + TI_REG_WINDOW + 0x00] + std %l2, [%g3 + TI_REG_WINDOW + 0x08] + std %l4, [%g3 + TI_REG_WINDOW + 0x10] + + std %l6, [%g3 + TI_REG_WINDOW + 0x18] + std %i0, [%g3 + TI_REG_WINDOW + 0x20] + std %i2, [%g3 + TI_REG_WINDOW + 0x28] + std %i4, [%g3 + TI_REG_WINDOW + 0x30] + std %i6, [%g3 + TI_REG_WINDOW + 0x38] + add %g1, 1, %g1 +2: stb %g1, [%g6 + TI_WSAVED] + rdpr %tstate, %g1 + + andcc %g1, TSTATE_PRIV, %g0 + saved + be,pn %xcc, window_mna_from_user_common + and %g1, TSTATE_CWP, %g1 + retry +window_mna_from_user_common: + wrpr %g1, %cwp + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o2 + mov %l5, %o1 + call mem_address_unaligned + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + clr %l6 + + /* These are only needed for 64-bit mode processes which + * put their stack pointer into the VPTE area and there + * happens to be a VPTE tlb entry mapped there during + * a spill/fill trap to that stack frame. + */ + .globl winfix_dax, fill_fixup_dax, spill_fixup_dax winfix_dax: - andn %g3, 0x7f, %g3 - add %g3, 0x74, %g3 - wrpr %g3, %tnpc + andn %g3, 0x7f, %g3 + add %g3, 0x74, %g3 + wrpr %g3, %tnpc done - fill_fixup_dax: - rdpr %tstate, %g1 - and %g1, TSTATE_CWP, %g1 - wrpr %g1, %cwp - ba,pt %xcc, etrap - rd %pc, %g7 - sethi %hi(tlb_type), %g1 - mov %l4, %o1 - lduw [%g1 + %lo(tlb_type)], %g1 - mov %l5, %o2 - cmp %g1, 3 - bne,pt %icc, 1f - add %sp, PTREGS_OFF, %o0 - call sun4v_data_access_exception - nop - ba,a,pt %xcc, rtrap_clr_l6 -1: call spitfire_data_access_exception + rdpr %tstate, %g1 + andcc %g1, TSTATE_PRIV, %g0 + be,pt %xcc, window_dax_from_user_common + and %g1, TSTATE_CWP, %g1 + + /* Please, see fill_fixup commentary about why we must preserve + * %l5 and %l6 to preserve absolute correct semantics. + */ + rdpr %wstate, %g2 ! Grab user mode wstate. + wrpr %g1, %cwp ! Get into the right window. + sll %g2, 3, %g2 ! NORMAL-->OTHER + wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + + wrpr %g2, 0x0, %wstate ! This must be consistent. + wrpr %g0, 0x0, %otherwin ! We know this. + call set_pcontext ! Change contexts... nop - ba,a,pt %xcc, rtrap_clr_l6 + rdpr %pstate, %l1 ! Prepare to change globals. + mov %g4, %o1 ! Setup args for + mov %g5, %o2 ! final call to spitfire_data_access_exception. + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO + + mov %g6, %o7 ! Stash away current. + wrpr %g0, 0x0, %tl ! Out of trap levels. + wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate + mov %o7, %g6 ! Get current back. + ldx [%g6 + TI_TASK], %g4 ! Finish it. +#ifdef CONFIG_SMP + mov TSB_REG, %g1 + ldxa [%g1] ASI_IMMU, %g5 +#endif + call spitfire_data_access_exception + add %sp, PTREGS_OFF, %o0 + + b,pt %xcc, rtrap + nop ! yes, the nop is correct +spill_fixup_dax: + ldx [%g6 + TI_FLAGS], %g1 + andcc %g1, _TIF_32BIT, %g0 + ldub [%g6 + TI_WSAVED], %g1 + sll %g1, 3, %g3 + add %g6, %g3, %g3 + stx %sp, [%g3 + TI_RWIN_SPTRS] + + sll %g1, 7, %g3 + bne,pt %xcc, 1f + add %g6, %g3, %g3 + stx %l0, [%g3 + TI_REG_WINDOW + 0x00] + stx %l1, [%g3 + TI_REG_WINDOW + 0x08] + stx %l2, [%g3 + TI_REG_WINDOW + 0x10] + stx %l3, [%g3 + TI_REG_WINDOW + 0x18] + stx %l4, [%g3 + TI_REG_WINDOW + 0x20] + + stx %l5, [%g3 + TI_REG_WINDOW + 0x28] + stx %l6, [%g3 + TI_REG_WINDOW + 0x30] + stx %l7, [%g3 + TI_REG_WINDOW + 0x38] + stx %i0, [%g3 + TI_REG_WINDOW + 0x40] + stx %i1, [%g3 + TI_REG_WINDOW + 0x48] + stx %i2, [%g3 + TI_REG_WINDOW + 0x50] + stx %i3, [%g3 + TI_REG_WINDOW + 0x58] + stx %i4, [%g3 + TI_REG_WINDOW + 0x60] + + stx %i5, [%g3 + TI_REG_WINDOW + 0x68] + stx %i6, [%g3 + TI_REG_WINDOW + 0x70] + stx %i7, [%g3 + TI_REG_WINDOW + 0x78] + b,pt %xcc, 2f + add %g1, 1, %g1 +1: std %l0, [%g3 + TI_REG_WINDOW + 0x00] + std %l2, [%g3 + TI_REG_WINDOW + 0x08] + std %l4, [%g3 + TI_REG_WINDOW + 0x10] + + std %l6, [%g3 + TI_REG_WINDOW + 0x18] + std %i0, [%g3 + TI_REG_WINDOW + 0x20] + std %i2, [%g3 + TI_REG_WINDOW + 0x28] + std %i4, [%g3 + TI_REG_WINDOW + 0x30] + std %i6, [%g3 + TI_REG_WINDOW + 0x38] + add %g1, 1, %g1 +2: stb %g1, [%g6 + TI_WSAVED] + rdpr %tstate, %g1 + + andcc %g1, TSTATE_PRIV, %g0 + saved + be,pn %xcc, window_dax_from_user_common + and %g1, TSTATE_CWP, %g1 + retry +window_dax_from_user_common: + wrpr %g1, %cwp + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call spitfire_data_access_exception + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + clr %l6