root/arch/sparc/kernel/etrap.S

/* [previous][next][first][last][top][bottom][index][help] */
   1 /* $Id: etrap.S,v 1.10 1995/11/25 00:57:58 davem Exp $
   2  * etrap.S: Sparc trap window preparation for entry into the
   3  *          Linux kernel.
   4  *
   5  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   6  */
   7 
   8 #include <asm/cprefix.h>
   9 #include <asm/head.h>
  10 #include <asm/page.h>
  11 #include <asm/psr.h>
  12 #include <asm/ptrace.h>
  13 #include <asm/winmacro.h>
  14 
  15 /* Registers to not touch at all. */
  16 #define t_psr        l0 /* Set by caller */
  17 #define t_pc         l1 /* Set by caller */
  18 #define t_npc        l2 /* Set by caller */
  19 #define t_wim        l3 /* Set by caller */
  20 #define t_twinmask   l4 /* Set at beginning of this entry routine. */
  21 #define t_kstack     l5 /* Set right before pt_regs frame is built */
  22 #define t_retpc      l6 /* If you change this, change winmacro.h header file */
  23 #define t_systable   l7 /* Never touch this, could be the syscall table ptr. */
  24 #define curptr       g4 /* Set after pt_regs frame is built */
  25 
  26         .text
  27         .align 4
  28 
  29         /* SEVEN WINDOW PATCH INSTRUCTIONS */
  30         .globl  tsetup_7win_patch1, tsetup_7win_patch2
  31         .globl  tsetup_7win_patch3, tsetup_7win_patch4
  32         .globl  tsetup_7win_patch5, tsetup_7win_patch6
  33 tsetup_7win_patch1:     sll     %t_wim, 0x6, %t_wim
  34 tsetup_7win_patch2:     and     %g2, 0x7f, %g2
  35 tsetup_7win_patch3:     and     %g2, 0x7f, %g2
  36 tsetup_7win_patch4:     and     %g1, 0x7f, %g1
  37 tsetup_7win_patch5:     sll     %t_wim, 0x6, %t_wim
  38 tsetup_7win_patch6:     and     %g2, 0x7f, %g2
  39         /* END OF PATCH INSTRUCTIONS */
  40 
  41         /* At trap time, interrupts and all generic traps do the
  42          * following:
  43          *
  44          * rd   %psr, %l0
  45          * b    some_handler
  46          * rd   %wim, %l3
  47          * nop
  48          *
  49          * Then 'some_handler' if it needs a trap frame (ie. it has
  50          * to call c-code and the trap cannot be handled in-window)
  51          * then it does the SAVE_ALL macro in entry.S which does
  52          *
  53          * sethi        %hi(trap_setup), %l4
  54          * jmpl         %l4 + %lo(trap_setup), %l6
  55          * mov          1, %l4
  56          */
  57 
  58         /* 2 3 4  window number
  59          * -----
  60          * O T S  mnemonic
  61          *
  62          * O == Current window before trap
  63          * T == Window entered when trap occurred
  64          * S == Window we will need to save if (1<<T) == %wim
  65          *
  66          * Before execution gets here, it must be guarenteed that
  67          * %l0 contains trap time %psr, %l1 and %l2 contain the
  68          * trap pc and npc, and %l3 contains the trap time %wim.
  69          */
  70 
  71         .globl  trap_setup, tsetup_patch1, tsetup_patch2
  72         .globl  tsetup_patch3, tsetup_patch4
  73         .globl  tsetup_patch5, tsetup_patch6
  74 trap_setup:
  75         /* Calculate mask of trap window.  See if from user
  76          * or kernel and branch conditionally.
  77          */
  78         mov     1, %t_twinmask
  79         sll     %t_twinmask, %t_psr, %t_twinmask ! t_twinmask = (1 << psr)
  80         andcc   %t_psr, PSR_PS, %g0              ! fromsupv_p = (psr & PSR_PS)
  81         be      trap_setup_from_user             ! nope, from user mode
  82          nop
  83 
  84         /* From kernel, allocate more kernel stack and
  85          * build a pt_regs trap frame.
  86          */
  87         sub     %fp, (STACKFRAME_SZ + TRACEREG_SZ), %t_kstack
  88         STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, t_wim, g2)
  89 
  90         /* See if we are in the trap window. */
  91         andcc   %t_twinmask, %t_wim, %g0
  92         be      1f
  93          nop
  94 
  95         b       trap_setup_kernel_spill         ! in trap window, clean up
  96          nop
  97 
  98         /* Trap from kernel with a window available.
  99          * Just do it...
 100          */
 101 1:
 102         mov     %t_kstack, %sp          ! jump onto new stack
 103         jmpl    %t_retpc + 0x8, %g0     ! return to caller
 104          nop
 105 
 106 trap_setup_kernel_spill:
 107         LOAD_CURRENT(curptr)
 108         ld      [%curptr + THREAD_UMASK], %g1
 109         orcc    %g0, %g1, %g0
 110         bne     trap_setup_user_spill   ! there are some user windows, yuck
 111          nop
 112 
 113                 /* Spill from kernel, but only kernel windows, adjust
 114                  * %wim and go.
 115                  */
 116                 srl     %t_wim, 0x1, %g2        ! begin computation of new %wim
 117 tsetup_patch1:  sll     %t_wim, 0x7, %t_wim     ! patched on 7 window Sparcs
 118                 or      %t_wim, %g2, %g2
 119 tsetup_patch2:  and     %g2, 0xff, %g2          ! patched on 7 window Sparcs
 120 
 121         save    %g0, %g0, %g0
 122 
 123         /* Set new %wim value */
 124         wr      %g2, 0x0, %wim
 125         WRITE_PAUSE
 126 
 127         /* Save the kernel window onto the corresponding stack. */
 128         STORE_WINDOW(sp)
 129 
 130         restore %g0, %g0, %g0
 131 
 132         mov     %t_kstack, %sp          ! and onto new kernel stack
 133         jmpl    %t_retpc + 0x8, %g0     ! return to caller
 134          nop
 135 
 136 trap_setup_from_user:
 137         /* We can't use %curptr yet. */
 138         LOAD_CURRENT(t_kstack)
 139         ld      [%t_kstack + TASK_KSTACK_PG], %t_kstack
 140 
 141         /* Build pt_regs frame. */
 142         add     %t_kstack, (PAGE_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %t_kstack
 143         STORE_PT_ALL(t_kstack, t_psr, t_pc, t_npc, t_wim, g2)
 144 
 145         /* Clear current->tss.w_saved */
 146         LOAD_CURRENT(curptr)
 147         st      %g0, [%curptr + THREAD_W_SAVED]
 148 
 149         /* See if we are in the trap window. */
 150         andcc   %t_twinmask, %t_wim, %g0
 151         bne     trap_setup_user_spill           ! yep we are
 152          orn    %g0, %t_twinmask, %g1           ! negate trap win mask into %g1
 153 
 154                 /* Trap from user, but not into the invalid window.
 155                  * Calculate new umask.  The way this works is,
 156                  * any window from the %wim at trap time until
 157                  * the window right before the one we are in now,
 158                  * is a user window.  A diagram:
 159                  *
 160                  *      7 6 5 4 3 2 1 0    window number
 161                  *      ---------------
 162                  *        I     L T        mnemonic
 163                  *
 164                  * Window 'I' is the invalid window in our example,
 165                  * window 'L' is the window the user was in when
 166                  * the trap occurred, window T is the trap window
 167                  * we are in now.  So therefore, windows 5, 4 and
 168                  * 3 are user windows.  The following sequence
 169                  * computes the user winmask to represent this.
 170                  */
 171                 subcc   %t_wim, %t_twinmask, %g2
 172                 bneg,a  1f
 173                  sub    %g2, 0x1, %g2
 174 1:
 175                 andn    %g2, %t_twinmask, %g2
 176 tsetup_patch3:  and     %g2, 0xff, %g2                  ! patched on 7win Sparcs
 177                 st      %g2, [%curptr + THREAD_UMASK]   ! store new umask
 178 
 179                 mov     %t_kstack, %sp                  ! and onto kernel stack
 180                 jmpl    %t_retpc + 0x8, %g0             ! return to caller
 181                  nop
 182 
 183 trap_setup_user_spill:
 184                 /* A spill occured from either kernel or user mode
 185                  * and there exist some user windows to deal with.
 186                  * A mask of the currently valid user windows
 187                  * is in %g1 upon entry to here.
 188                  */
 189 
 190 tsetup_patch4:  and     %g1, 0xff, %g1          ! patched on 7win Sparcs, mask
 191                 srl     %t_wim, 0x1, %g2        ! compute new %wim
 192 tsetup_patch5:  sll     %t_wim, 0x7, %t_wim     ! patched on 7win Sparcs
 193                 or      %t_wim, %g2, %g2        ! %g2 is new %wim
 194 tsetup_patch6:  and     %g2, 0xff, %g2          ! patched on 7win Sparcs
 195                 andn    %g1, %g2, %g1           ! clear this bit in %g1
 196                 st      %g1, [%curptr + THREAD_UMASK]
 197 
 198         save    %g0, %g0, %g0
 199 
 200         wr      %g2, 0x0, %wim
 201         WRITE_PAUSE
 202 
 203         /* Call MMU-architecture dependant stack checking
 204          * routine.
 205          */
 206         .globl  C_LABEL(tsetup_mmu_patchme)
 207 C_LABEL(tsetup_mmu_patchme):    b       C_LABEL(tsetup_sun4c_stackchk)
 208                                  andcc  %sp, 0x7, %g0
 209 
 210 trap_setup_user_stack_is_bolixed:
 211         /* From user/kernel into invalid window w/bad user
 212          * stack. Save bad user stack, and return to caller.
 213          */
 214         SAVE_BOLIXED_USER_STACK(curptr, g3)
 215         restore %g0, %g0, %g0
 216         mov     %t_kstack, %sp
 217         jmpl    %t_retpc + 0x8, %g0
 218          nop
 219 
 220 trap_setup_good_ustack:
 221         STORE_WINDOW(sp)
 222 
 223 trap_setup_finish_up:
 224         restore %g0, %g0, %g0
 225         mov     %t_kstack, %sp
 226         jmpl    %t_retpc + 0x8, %g0
 227          nop
 228 
 229         /* Architecture specific stack checking routines.  When either
 230          * of these routines are called, the globals are free to use
 231          * as they have been safely stashed on the new kernel stack
 232          * pointer.  Thus the definition below for simplicity.
 233          */
 234 #define glob_tmp     g1
 235 
 236         .globl  C_LABEL(tsetup_sun4c_stackchk)
 237         .globl  C_LABEL(tsetup_srmmu_stackchk)
 238 C_LABEL(tsetup_sun4c_stackchk):
 239         /* Done by caller: andcc %sp, 0x7, %g0 */
 240         be      1f
 241          sra    %sp, 29, %glob_tmp
 242 
 243         b       trap_setup_user_stack_is_bolixed
 244          nop
 245 
 246 1:
 247         add     %glob_tmp, 0x1, %glob_tmp
 248         andncc  %glob_tmp, 0x1, %g0
 249         be      1f
 250          and    %sp, 0xfff, %glob_tmp           ! delay slot
 251 
 252         b       trap_setup_user_stack_is_bolixed
 253          nop
 254 
 255         /* See if our dump area will be on more than one
 256          * page.
 257          */
 258 1:
 259         add     %glob_tmp, 0x38, %glob_tmp
 260         andncc  %glob_tmp, 0xff8, %g0
 261         be      tsetup_sun4c_onepage            ! only one page to check
 262          lda    [%sp] ASI_PTE, %glob_tmp        ! have to check first page anyways
 263 
 264 tsetup_sun4c_twopages:
 265         /* Is first page ok permission wise? */
 266         srl     %glob_tmp, 29, %glob_tmp
 267         cmp     %glob_tmp, 0x6
 268         be      1f
 269          add    %sp, 0x38, %glob_tmp            /* Is second page in vma hole? */
 270 
 271         b       trap_setup_user_stack_is_bolixed
 272          nop
 273 
 274 1:
 275         sra     %glob_tmp, 29, %glob_tmp
 276         add     %glob_tmp, 0x1, %glob_tmp
 277         andncc  %glob_tmp, 0x1, %g0
 278         be      1f
 279          add    %sp, 0x38, %glob_tmp
 280 
 281         b       trap_setup_user_stack_is_bolixed
 282          nop
 283 
 284 1:
 285         lda     [%glob_tmp] ASI_PTE, %glob_tmp
 286 
 287 tsetup_sun4c_onepage:
 288         srl     %glob_tmp, 29, %glob_tmp
 289         cmp     %glob_tmp, 0x6                          ! can user write to it?
 290         be      trap_setup_good_ustack                  ! success
 291          nop
 292 
 293         b       trap_setup_user_stack_is_bolixed
 294          nop
 295 
 296 C_LABEL(tsetup_srmmu_stackchk):
 297         /* Check results of callers andcc %sp, 0x7, %g0 */
 298         bne     trap_setup_user_stack_is_bolixed
 299          sethi  %hi(KERNBASE), %glob_tmp
 300         cmp     %glob_tmp, %sp
 301         bleu    trap_setup_user_stack_is_bolixed
 302          nop
 303 
 304         /* Clear the fault status and turn on the no_fault bit. */
 305         mov     AC_M_SFSR, %glob_tmp                    ! delay from above...
 306         lda     [%glob_tmp] ASI_M_MMUREGS, %g0          ! eat SFSR
 307         lda     [%g0] ASI_M_MMUREGS, %glob_tmp          ! read MMU control
 308         or      %glob_tmp, 0x2, %glob_tmp               ! or in no_fault bit
 309         sta     %glob_tmp, [%g0] ASI_M_MMUREGS          ! set it
 310 
 311         /* Dump the registers and cross fingers. */
 312         STORE_WINDOW(sp)
 313 
 314         /* Clear the no_fault bit and check the status. */
 315         andn    %glob_tmp, 0x2, %glob_tmp
 316         sta     %glob_tmp, [%g0] ASI_M_MMUREGS
 317         mov     AC_M_SFAR, %glob_tmp
 318         lda     [%glob_tmp] ASI_M_MMUREGS, %g0
 319         mov     AC_M_SFSR, %glob_tmp
 320         lda     [%glob_tmp] ASI_M_MMUREGS, %glob_tmp
 321         andcc   %glob_tmp, 0x2, %g0                     ! did we fault?
 322         be      trap_setup_finish_up                    ! cool beans, success
 323          nop
 324 
 325         b       trap_setup_user_stack_is_bolixed        ! we faulted, ugh
 326          nop

/* [previous][next][first][last][top][bottom][index][help] */