Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * wuf.S: Window underflow trap handler for the Sparc.
0004  *
0005  * Copyright (C) 1995 David S. Miller
0006  */
0007 
0008 #include <asm/contregs.h>
0009 #include <asm/page.h>
0010 #include <asm/ptrace.h>
0011 #include <asm/psr.h>
0012 #include <asm/smp.h>
0013 #include <asm/asi.h>
0014 #include <asm/winmacro.h>
0015 #include <asm/asmmacro.h>
0016 #include <asm/thread_info.h>
0017 
0018 /* Just like the overflow handler we define macros for registers
0019  * with fixed meanings in this routine.
0020  */
0021 #define t_psr       l0
0022 #define t_pc        l1
0023 #define t_npc       l2
0024 #define t_wim       l3
0025 /* Don't touch the above registers or else you die horribly... */
0026 
0027 /* Now macros for the available scratch registers in this routine. */
0028 #define twin_tmp1    l4
0029 #define twin_tmp2    l5
0030 
0031 #define curptr       g6
0032 
0033     .text
0034     .align  4
0035 
0036     /* The trap entry point has executed the following:
0037      *
0038      * rd    %psr, %l0
0039      * rd    %wim, %l3
0040      * b     fill_window_entry
0041      * andcc %l0, PSR_PS, %g0
0042      */
0043 
0044     /* Datum current_thread_info->uwinmask contains at all times a bitmask
0045      * where if any user windows are active, at least one bit will
0046      * be set in to mask.  If no user windows are active, the bitmask
0047      * will be all zeroes.
0048      */
0049 
0050     /* To get an idea of what has just happened to cause this
0051      * trap take a look at this diagram:
0052      *
0053      *      1  2  3  4     <--  Window number
0054      *      ----------
0055      *      T  O  W  I     <--  Symbolic name
0056      *
0057      *      O == the window that execution was in when
0058      *           the restore was attempted
0059      *
0060      *      T == the trap itself has save'd us into this
0061      *           window
0062      *
0063      *      W == this window is the one which is now invalid
0064      *           and must be made valid plus loaded from the
0065      *           stack
0066      *
0067      *      I == this window will be the invalid one when we
0068      *           are done and return from trap if successful
0069      */
0070 
0071     /* BEGINNING OF PATCH INSTRUCTIONS */
0072 
0073     /* On 7-window Sparc the boot code patches fnwin_patch1
0074      * with the following instruction.
0075      */
0076     .globl  fnwin_patch1_7win, fnwin_patch2_7win
0077 fnwin_patch1_7win:  srl %t_wim, 6, %twin_tmp2
0078 fnwin_patch2_7win:  and %twin_tmp1, 0x7f, %twin_tmp1
0079     /* END OF PATCH INSTRUCTIONS */
0080 
0081     .globl  fill_window_entry, fnwin_patch1, fnwin_patch2
0082 fill_window_entry:
0083     /* LOCATION: Window 'T' */
0084 
0085     /* Compute what the new %wim is going to be if we retrieve
0086      * the proper window off of the stack.
0087      */
0088         sll %t_wim, 1, %twin_tmp1
0089 fnwin_patch1:   srl %t_wim, 7, %twin_tmp2
0090         or  %twin_tmp1, %twin_tmp2, %twin_tmp1
0091 fnwin_patch2:   and %twin_tmp1, 0xff, %twin_tmp1
0092 
0093     wr  %twin_tmp1, 0x0, %wim   /* Make window 'I' invalid */
0094 
0095     andcc   %t_psr, PSR_PS, %g0
0096     be  fwin_from_user
0097      restore    %g0, %g0, %g0       /* Restore to window 'O' */
0098 
0099     /* Trapped from kernel, we trust that the kernel does not
0100      * 'over restore' sorta speak and just grab the window
0101      * from the stack and return.  Easy enough.
0102      */
0103 fwin_from_kernel:
0104     /* LOCATION: Window 'O' */
0105 
0106     restore %g0, %g0, %g0
0107 
0108     /* LOCATION: Window 'W' */
0109 
0110     LOAD_WINDOW(sp)                 /* Load it up */
0111 
0112     /* Spin the wheel... */
0113     save    %g0, %g0, %g0
0114     save    %g0, %g0, %g0
0115     /* I'd like to buy a vowel please... */
0116 
0117     /* LOCATION: Window 'T' */
0118 
0119     /* Now preserve the condition codes in %psr, pause, and
0120      * return from trap.  This is the simplest case of all.
0121      */
0122     wr  %t_psr, 0x0, %psr
0123     WRITE_PAUSE
0124 
0125     jmp %t_pc
0126     rett    %t_npc
0127 
0128 fwin_from_user:
0129     /* LOCATION: Window 'O' */
0130 
0131     restore %g0, %g0, %g0       /* Restore to window 'W' */
0132 
0133     /* LOCATION: Window 'W' */
0134 
0135     /* Branch to the stack validation routine */
0136     b   srmmu_fwin_stackchk
0137      andcc  %sp, 0x7, %g0
0138 
0139 #define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)
0140 
0141 fwin_user_stack_is_bolixed:
0142     /* LOCATION: Window 'W' */
0143 
0144     /* Place a pt_regs frame on the kernel stack, save back
0145      * to the trap window and call c-code to deal with this.
0146      */
0147     LOAD_CURRENT(l4, l5)
0148 
0149     sethi   %hi(STACK_OFFSET), %l5
0150     or  %l5, %lo(STACK_OFFSET), %l5
0151     add %l4, %l5, %l5
0152 
0153     /* Store globals into pt_regs frame. */
0154     STORE_PT_GLOBALS(l5)
0155     STORE_PT_YREG(l5, g3)
0156 
0157     /* Save current in a global while we change windows. */
0158     mov %l4, %curptr
0159 
0160     save    %g0, %g0, %g0
0161 
0162     /* LOCATION: Window 'O' */
0163 
0164     rd  %psr, %g3       /* Read %psr in live user window */
0165     mov %fp, %g4        /* Save bogus frame pointer. */
0166 
0167     save    %g0, %g0, %g0
0168 
0169     /* LOCATION: Window 'T' */
0170 
0171     sethi   %hi(STACK_OFFSET), %l5
0172     or  %l5, %lo(STACK_OFFSET), %l5
0173     add %curptr, %l5, %sp
0174 
0175     /* Build rest of pt_regs. */
0176     STORE_PT_INS(sp)
0177     STORE_PT_PRIV(sp, t_psr, t_pc, t_npc)
0178 
0179     /* re-set trap time %wim value */
0180     wr  %t_wim, 0x0, %wim
0181 
0182     /* Fix users window mask and buffer save count. */
0183     mov 0x1, %g5
0184     sll %g5, %g3, %g5
0185     st  %g5, [%curptr + TI_UWINMASK]        ! one live user window still
0186     st  %g0, [%curptr + TI_W_SAVED]     ! no windows in the buffer
0187 
0188     wr  %t_psr, PSR_ET, %psr            ! enable traps
0189     nop
0190     call    window_underflow_fault
0191      mov    %g4, %o0
0192 
0193     b   ret_trap_entry
0194      clr    %l6
0195 
0196 fwin_user_stack_is_ok:
0197     /* LOCATION: Window 'W' */
0198 
0199     /* The users stack area is kosher and mapped, load the
0200      * window and fall through to the finish up routine.
0201      */
0202     LOAD_WINDOW(sp)
0203 
0204     /* Round and round she goes... */
0205     save    %g0, %g0, %g0       /* Save to window 'O' */
0206     save    %g0, %g0, %g0       /* Save to window 'T' */
0207     /* Where she'll trap nobody knows... */
0208 
0209     /* LOCATION: Window 'T' */
0210 
0211 fwin_user_finish_up:
0212     /* LOCATION: Window 'T' */
0213 
0214     wr  %t_psr, 0x0, %psr
0215     WRITE_PAUSE 
0216 
0217     jmp %t_pc
0218     rett    %t_npc
0219 
0220     /* Here come the architecture specific checks for stack.
0221      * mappings.  Note that unlike the window overflow handler
0222      * we only need to check whether the user can read from
0223      * the appropriate addresses.  Also note that we are in
0224      * an invalid window which will be loaded, and this means
0225      * that until we actually load the window up we are free
0226      * to use any of the local registers contained within.
0227      *
0228      * On success these routine branch to fwin_user_stack_is_ok
0229      * if the area at %sp is user readable and the window still
0230      * needs to be loaded, else fwin_user_finish_up if the
0231      * routine has done the loading itself.  On failure (bogus
0232      * user stack) the routine shall branch to the label called
0233      * fwin_user_stack_is_bolixed.
0234      *
0235      * Contrary to the arch-specific window overflow stack
0236      * check routines in wof.S, these routines are free to use
0237      * any of the local registers they want to as this window
0238      * does not belong to anyone at this point, however the
0239      * outs and ins are still verboten as they are part of
0240      * 'someone elses' window possibly.
0241      */
0242 
0243     .globl  srmmu_fwin_stackchk
0244 srmmu_fwin_stackchk:
0245     /* LOCATION: Window 'W' */
0246 
0247     /* Caller did 'andcc %sp, 0x7, %g0' */
0248     bne fwin_user_stack_is_bolixed
0249      sethi   %hi(PAGE_OFFSET), %l5
0250 
0251     /* Check if the users stack is in kernel vma, then our
0252      * trial and error technique below would succeed for
0253      * the 'wrong' reason.
0254      */
0255     mov AC_M_SFSR, %l4
0256     cmp %l5, %sp
0257     bleu    fwin_user_stack_is_bolixed
0258 LEON_PI( lda    [%l4] ASI_LEON_MMUREGS, %g0)    ! clear fault status
0259 SUN_PI_( lda    [%l4] ASI_M_MMUREGS, %g0)   ! clear fault status
0260 
0261     /* The technique is, turn off faults on this processor,
0262      * just let the load rip, then check the sfsr to see if
0263      * a fault did occur.  Then we turn on fault traps again
0264      * and branch conditionally based upon what happened.
0265      */
0266 LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %l5)    ! read mmu-ctrl reg
0267 SUN_PI_(lda [%g0] ASI_M_MMUREGS, %l5)   ! read mmu-ctrl reg
0268     or  %l5, 0x2, %l5           ! turn on no-fault bit
0269 LEON_PI(sta %l5, [%g0] ASI_LEON_MMUREGS)    ! store it
0270 SUN_PI_(sta %l5, [%g0] ASI_M_MMUREGS)   ! store it
0271 
0272     /* Cross fingers and go for it. */
0273     LOAD_WINDOW(sp)
0274 
0275     /* A penny 'saved'... */
0276     save    %g0, %g0, %g0
0277     save    %g0, %g0, %g0
0278     /* Is a BADTRAP earned... */
0279 
0280     /* LOCATION: Window 'T' */
0281 
0282 LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %twin_tmp1) ! load mmu-ctrl again
0283 SUN_PI_(lda [%g0] ASI_M_MMUREGS, %twin_tmp1)    ! load mmu-ctrl again
0284     andn    %twin_tmp1, 0x2, %twin_tmp1     ! clear no-fault bit
0285 LEON_PI(sta %twin_tmp1, [%g0] ASI_LEON_MMUREGS) ! store it
0286 SUN_PI_(sta %twin_tmp1, [%g0] ASI_M_MMUREGS)    ! store it
0287 
0288     mov AC_M_SFAR, %twin_tmp2
0289 LEON_PI(lda [%twin_tmp2] ASI_LEON_MMUREGS, %g0) ! read fault address
0290 SUN_PI_(lda [%twin_tmp2] ASI_M_MMUREGS, %g0)    ! read fault address
0291 
0292     mov AC_M_SFSR, %twin_tmp2
0293 LEON_PI(lda [%twin_tmp2] ASI_LEON_MMUREGS, %twin_tmp2) ! read fault status
0294 SUN_PI_(lda [%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2)    ! read fault status
0295     andcc   %twin_tmp2, 0x2, %g0               ! did fault occur?
0296 
0297     bne 1f                     ! yep, cleanup
0298      nop
0299 
0300     wr  %t_psr, 0x0, %psr
0301     nop
0302     b   fwin_user_finish_up + 0x4
0303      nop
0304 
0305     /* Did I ever tell you about my window lobotomy?
0306      * anyways... fwin_user_stack_is_bolixed expects
0307      * to be in window 'W' so make it happy or else
0308      * we watchdog badly.
0309      */
0310 1:
0311     restore %g0, %g0, %g0
0312     b   fwin_user_stack_is_bolixed  ! oh well
0313      restore    %g0, %g0, %g0