Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * etrap.S: Sparc trap window preparation for entry into the
0004  *          Linux kernel.
0005  *
0006  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
0007  */
0008 
0009 #include <asm/head.h>
0010 #include <asm/asi.h>
0011 #include <asm/contregs.h>
0012 #include <asm/page.h>
0013 #include <asm/psr.h>
0014 #include <asm/ptrace.h>
0015 #include <asm/winmacro.h>
0016 #include <asm/asmmacro.h>
0017 #include <asm/thread_info.h>
0018 
0019 /* Registers to not touch at all. */
0020 #define t_psr        l0 /* Set by caller */
0021 #define t_pc         l1 /* Set by caller */
0022 #define t_npc        l2 /* Set by caller */
0023 #define t_wim        l3 /* Set by caller */
0024 #define t_twinmask   l4 /* Set at beginning of this entry routine. */
0025 #define t_kstack     l5 /* Set right before pt_regs frame is built */
0026 #define t_retpc      l6 /* If you change this, change winmacro.h header file */
0027 #define t_systable   l7 /* Never touch this, could be the syscall table ptr. */
0028 #define curptr       g6 /* Set after pt_regs frame is built */
0029 
0030     .text
0031     .align 4
0032 
0033     /* SEVEN WINDOW PATCH INSTRUCTIONS */
0034     .globl  tsetup_7win_patch1, tsetup_7win_patch2
0035     .globl  tsetup_7win_patch3, tsetup_7win_patch4
0036     .globl  tsetup_7win_patch5, tsetup_7win_patch6
0037 tsetup_7win_patch1: sll %t_wim, 0x6, %t_wim
0038 tsetup_7win_patch2: and %g2, 0x7f, %g2
0039 tsetup_7win_patch3: and %g2, 0x7f, %g2
0040 tsetup_7win_patch4: and %g1, 0x7f, %g1
0041 tsetup_7win_patch5: sll %t_wim, 0x6, %t_wim
0042 tsetup_7win_patch6: and %g2, 0x7f, %g2
0043     /* END OF PATCH INSTRUCTIONS */
0044 
0045     /* At trap time, interrupts and all generic traps do the
0046      * following:
0047      *
0048      * rd   %psr, %l0
0049      * b    some_handler
0050      * rd   %wim, %l3
0051      * nop
0052      *
0053      * Then 'some_handler' if it needs a trap frame (ie. it has
0054      * to call c-code and the trap cannot be handled in-window)
0055      * then it does the SAVE_ALL macro in entry.S which does
0056      *
0057      * sethi    %hi(trap_setup), %l4
0058      * jmpl     %l4 + %lo(trap_setup), %l6
0059      * nop
0060      */
0061 
0062     /* 2 3 4  window number
0063      * -----
0064      * O T S  mnemonic
0065      *
0066      * O == Current window before trap
0067      * T == Window entered when trap occurred
0068      * S == Window we will need to save if (1<<T) == %wim
0069      *
0070      * Before execution gets here, it must be guaranteed that
0071      * %l0 contains trap time %psr, %l1 and %l2 contain the
0072      * trap pc and npc, and %l3 contains the trap time %wim.
0073      */
0074 
0075     .globl  trap_setup, tsetup_patch1, tsetup_patch2
0076     .globl  tsetup_patch3, tsetup_patch4
0077     .globl  tsetup_patch5, tsetup_patch6
0078 trap_setup:
0079     /* Calculate mask of trap window.  See if from user
0080      * or kernel and branch conditionally.
0081      */
0082     mov 1, %t_twinmask
0083     andcc   %t_psr, PSR_PS, %g0      ! fromsupv_p = (psr & PSR_PS)
0084     be  trap_setup_from_user         ! nope, from user mode
0085      sll    %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
0086 
0087     /* From kernel, allocate more kernel stack and
0088      * build a pt_regs trap frame.
0089      */
0090     sub %fp, (STACKFRAME_SZ + TRACEREG_SZ), %t_kstack
0091     STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
0092 
0093     /* See if we are in the trap window. */
0094     andcc   %t_twinmask, %t_wim, %g0
0095     bne trap_setup_kernel_spill     ! in trap window, clean up
0096      nop
0097 
0098     /* Trap from kernel with a window available.
0099      * Just do it...
0100      */
0101     jmpl    %t_retpc + 0x8, %g0 ! return to caller
0102      mov    %t_kstack, %sp      ! jump onto new stack
0103 
0104 trap_setup_kernel_spill:
0105     ld  [%curptr + TI_UWINMASK], %g1
0106     orcc    %g0, %g1, %g0
0107     bne trap_setup_user_spill   ! there are some user windows, yuck
0108     /* Spill from kernel, but only kernel windows, adjust
0109      * %wim and go.
0110      */
0111      srl    %t_wim, 0x1, %g2    ! begin computation of new %wim
0112 tsetup_patch1:
0113     sll %t_wim, 0x7, %t_wim ! patched on 7 window Sparcs
0114     or  %t_wim, %g2, %g2
0115 tsetup_patch2:
0116     and %g2, 0xff, %g2      ! patched on 7 window Sparcs
0117 
0118     save    %g0, %g0, %g0
0119 
0120     /* Set new %wim value */
0121     wr  %g2, 0x0, %wim
0122 
0123     /* Save the kernel window onto the corresponding stack. */
0124     STORE_WINDOW(sp)
0125 
0126     restore %g0, %g0, %g0
0127 
0128     jmpl    %t_retpc + 0x8, %g0 ! return to caller
0129      mov    %t_kstack, %sp      ! and onto new kernel stack
0130 
0131 #define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)
0132 
0133 trap_setup_from_user:
0134     /* We can't use %curptr yet. */
0135     LOAD_CURRENT(t_kstack, t_twinmask)
0136 
0137     sethi   %hi(STACK_OFFSET), %t_twinmask
0138     or  %t_twinmask, %lo(STACK_OFFSET), %t_twinmask
0139     add %t_kstack, %t_twinmask, %t_kstack
0140 
0141     mov 1, %t_twinmask
0142     sll %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
0143 
0144     /* Build pt_regs frame. */
0145     STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, g2)
0146 
0147 #if 0
0148     /* If we're sure every task_struct is THREAD_SIZE aligned,
0149        we can speed this up. */
0150     sethi   %hi(STACK_OFFSET), %curptr
0151     or  %curptr, %lo(STACK_OFFSET), %curptr
0152     sub %t_kstack, %curptr, %curptr
0153 #else
0154     sethi   %hi(~(THREAD_SIZE - 1)), %curptr
0155     and %t_kstack, %curptr, %curptr
0156 #endif
0157 
0158     /* Clear current_thread_info->w_saved */
0159     st  %g0, [%curptr + TI_W_SAVED]
0160 
0161     /* See if we are in the trap window. */
0162     andcc   %t_twinmask, %t_wim, %g0
0163     bne trap_setup_user_spill       ! yep we are
0164      orn    %g0, %t_twinmask, %g1       ! negate trap win mask into %g1
0165 
0166     /* Trap from user, but not into the invalid window.
0167      * Calculate new umask.  The way this works is,
0168      * any window from the %wim at trap time until
0169      * the window right before the one we are in now,
0170      * is a user window.  A diagram:
0171      *
0172      *      7 6 5 4 3 2 1 0    window number
0173      *      ---------------
0174      *        I     L T        mnemonic
0175      *
0176      * Window 'I' is the invalid window in our example,
0177      * window 'L' is the window the user was in when
0178      * the trap occurred, window T is the trap window
0179      * we are in now.  So therefore, windows 5, 4 and
0180      * 3 are user windows.  The following sequence
0181      * computes the user winmask to represent this.
0182      */
0183     subcc   %t_wim, %t_twinmask, %g2
0184     bneg,a  1f
0185      sub    %g2, 0x1, %g2
0186 1:
0187     andn    %g2, %t_twinmask, %g2
0188 tsetup_patch3:
0189     and %g2, 0xff, %g2          ! patched on 7win Sparcs
0190     st  %g2, [%curptr + TI_UWINMASK]    ! store new umask
0191 
0192     jmpl    %t_retpc + 0x8, %g0     ! return to caller
0193      mov    %t_kstack, %sp          ! and onto kernel stack
0194 
0195 trap_setup_user_spill:
0196     /* A spill occurred from either kernel or user mode
0197      * and there exist some user windows to deal with.
0198      * A mask of the currently valid user windows
0199      * is in %g1 upon entry to here.
0200      */
0201 
0202 tsetup_patch4:
0203     and %g1, 0xff, %g1      ! patched on 7win Sparcs, mask
0204     srl %t_wim, 0x1, %g2    ! compute new %wim
0205 tsetup_patch5:
0206     sll %t_wim, 0x7, %t_wim ! patched on 7win Sparcs
0207     or  %t_wim, %g2, %g2    ! %g2 is new %wim
0208 tsetup_patch6:
0209     and %g2, 0xff, %g2      ! patched on 7win Sparcs
0210     andn    %g1, %g2, %g1       ! clear this bit in %g1
0211     st  %g1, [%curptr + TI_UWINMASK]
0212 
0213     save    %g0, %g0, %g0
0214 
0215     wr  %g2, 0x0, %wim
0216 
0217     /* Call MMU-architecture dependent stack checking
0218      * routine.
0219      */
0220     b   tsetup_srmmu_stackchk
0221      andcc  %sp, 0x7, %g0
0222 
0223     /* Architecture specific stack checking routines.  When either
0224      * of these routines are called, the globals are free to use
0225      * as they have been safely stashed on the new kernel stack
0226      * pointer.  Thus the definition below for simplicity.
0227      */
0228 #define glob_tmp     g1
0229 
0230     .globl  tsetup_srmmu_stackchk
0231 tsetup_srmmu_stackchk:
0232     /* Check results of callers andcc %sp, 0x7, %g0 */
0233     bne trap_setup_user_stack_is_bolixed
0234      sethi   %hi(PAGE_OFFSET), %glob_tmp
0235 
0236     cmp %glob_tmp, %sp
0237     bleu,a  1f
0238 LEON_PI( lda    [%g0] ASI_LEON_MMUREGS, %glob_tmp)  ! read MMU control
0239 SUN_PI_( lda    [%g0] ASI_M_MMUREGS, %glob_tmp)     ! read MMU control
0240 
0241 trap_setup_user_stack_is_bolixed:
0242     /* From user/kernel into invalid window w/bad user
0243      * stack. Save bad user stack, and return to caller.
0244      */
0245     SAVE_BOLIXED_USER_STACK(curptr, g3)
0246     restore %g0, %g0, %g0
0247 
0248     jmpl    %t_retpc + 0x8, %g0
0249      mov    %t_kstack, %sp
0250 
0251 1:
0252     /* Clear the fault status and turn on the no_fault bit. */
0253     or  %glob_tmp, 0x2, %glob_tmp       ! or in no_fault bit
0254 LEON_PI(sta %glob_tmp, [%g0] ASI_LEON_MMUREGS)      ! set it
0255 SUN_PI_(sta %glob_tmp, [%g0] ASI_M_MMUREGS)     ! set it
0256 
0257     /* Dump the registers and cross fingers. */
0258     STORE_WINDOW(sp)
0259 
0260     /* Clear the no_fault bit and check the status. */
0261     andn    %glob_tmp, 0x2, %glob_tmp
0262 LEON_PI(sta %glob_tmp, [%g0] ASI_LEON_MMUREGS)
0263 SUN_PI_(sta %glob_tmp, [%g0] ASI_M_MMUREGS)
0264 
0265     mov AC_M_SFAR, %glob_tmp
0266 LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %g0)
0267 SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %g0)
0268 
0269     mov AC_M_SFSR, %glob_tmp
0270 LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %glob_tmp)! save away status of winstore
0271 SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp)   ! save away status of winstore
0272 
0273     andcc   %glob_tmp, 0x2, %g0         ! did we fault?
0274     bne trap_setup_user_stack_is_bolixed    ! failure
0275      nop
0276 
0277     restore %g0, %g0, %g0
0278 
0279     jmpl    %t_retpc + 0x8, %g0
0280      mov    %t_kstack, %sp
0281