linux/arch/sparc/kernel/wuf.S
<<
>>
Prefs
   1/* $Id: wuf.S,v 1.39 2000/01/08 16:38:18 anton Exp $
   2 * wuf.S: Window underflow trap handler for the Sparc.
   3 *
   4 * Copyright (C) 1995 David S. Miller
   5 */
   6
   7#include <asm/contregs.h>
   8#include <asm/page.h>
   9#include <asm/ptrace.h>
  10#include <asm/psr.h>
  11#include <asm/smp.h>
  12#include <asm/asi.h>
  13#include <asm/winmacro.h>
  14#include <asm/asmmacro.h>
  15#include <asm/thread_info.h>
  16
  17/* Just like the overflow handler we define macros for registers
  18 * with fixed meanings in this routine.
  19 */
  20#define t_psr       l0
  21#define t_pc        l1
  22#define t_npc       l2
  23#define t_wim       l3
  24/* Don't touch the above registers or else you die horribly... */
  25
  26/* Now macros for the available scratch registers in this routine. */
  27#define twin_tmp1    l4
  28#define twin_tmp2    l5
  29
  30#define curptr       g6
  31
  32        .text
  33        .align  4
  34
  35        /* The trap entry point has executed the following:
  36         *
  37         * rd    %psr, %l0
  38         * rd    %wim, %l3
  39         * b     fill_window_entry
  40         * andcc %l0, PSR_PS, %g0
  41         */
  42
  43        /* Datum current_thread_info->uwinmask contains at all times a bitmask
  44         * where if any user windows are active, at least one bit will
  45         * be set in to mask.  If no user windows are active, the bitmask
  46         * will be all zeroes.
  47         */
  48
  49        /* To get an idea of what has just happened to cause this
  50         * trap take a look at this diagram:
  51         *
  52         *      1  2  3  4     <--  Window number
  53         *      ----------
  54         *      T  O  W  I     <--  Symbolic name
  55         *
  56         *      O == the window that execution was in when
  57         *           the restore was attempted
  58         *
  59         *      T == the trap itself has save'd us into this
  60         *           window
  61         *
  62         *      W == this window is the one which is now invalid
  63         *           and must be made valid plus loaded from the
  64         *           stack
  65         *
  66         *      I == this window will be the invalid one when we
  67         *           are done and return from trap if successful
  68         */
  69
  70        /* BEGINNING OF PATCH INSTRUCTIONS */
  71
  72        /* On 7-window Sparc the boot code patches fnwin_patch1
  73         * with the following instruction.
  74         */
  75        .globl  fnwin_patch1_7win, fnwin_patch2_7win
  76fnwin_patch1_7win:      srl     %t_wim, 6, %twin_tmp2
  77fnwin_patch2_7win:      and     %twin_tmp1, 0x7f, %twin_tmp1
  78        /* END OF PATCH INSTRUCTIONS */
  79
  80        .globl  fill_window_entry, fnwin_patch1, fnwin_patch2
  81fill_window_entry:
  82        /* LOCATION: Window 'T' */
  83
  84        /* Compute what the new %wim is going to be if we retrieve
  85         * the proper window off of the stack.
  86         */
  87                sll     %t_wim, 1, %twin_tmp1
  88fnwin_patch1:   srl     %t_wim, 7, %twin_tmp2
  89                or      %twin_tmp1, %twin_tmp2, %twin_tmp1
  90fnwin_patch2:   and     %twin_tmp1, 0xff, %twin_tmp1
  91
  92        wr      %twin_tmp1, 0x0, %wim   /* Make window 'I' invalid */
  93
  94        andcc   %t_psr, PSR_PS, %g0
  95        be      fwin_from_user
  96         restore        %g0, %g0, %g0           /* Restore to window 'O' */
  97
  98        /* Trapped from kernel, we trust that the kernel does not
  99         * 'over restore' sorta speak and just grab the window
 100         * from the stack and return.  Easy enough.
 101         */
 102fwin_from_kernel:
 103        /* LOCATION: Window 'O' */
 104
 105        restore %g0, %g0, %g0
 106
 107        /* LOCATION: Window 'W' */
 108
 109        LOAD_WINDOW(sp)                 /* Load it up */
 110
 111        /* Spin the wheel... */
 112        save    %g0, %g0, %g0
 113        save    %g0, %g0, %g0
 114        /* I'd like to buy a vowel please... */
 115
 116        /* LOCATION: Window 'T' */
 117
 118        /* Now preserve the condition codes in %psr, pause, and
 119         * return from trap.  This is the simplest case of all.
 120         */
 121        wr      %t_psr, 0x0, %psr
 122        WRITE_PAUSE
 123
 124        jmp     %t_pc
 125        rett    %t_npc
 126
 127fwin_from_user:
 128        /* LOCATION: Window 'O' */
 129
 130        restore %g0, %g0, %g0           /* Restore to window 'W' */
 131
 132        /* LOCATION: Window 'W' */
 133
 134        /* Branch to the architecture specific stack validation
 135         * routine.  They can be found below...
 136         */
 137        .globl  fwin_mmu_patchme
 138fwin_mmu_patchme:       b       sun4c_fwin_stackchk
 139                                 andcc  %sp, 0x7, %g0
 140
 141#define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ)
 142
 143fwin_user_stack_is_bolixed:
 144        /* LOCATION: Window 'W' */
 145
 146        /* Place a pt_regs frame on the kernel stack, save back
 147         * to the trap window and call c-code to deal with this.
 148         */
 149        LOAD_CURRENT(l4, l5)
 150
 151        sethi   %hi(STACK_OFFSET), %l5
 152        or      %l5, %lo(STACK_OFFSET), %l5
 153        add     %l4, %l5, %l5
 154
 155        /* Store globals into pt_regs frame. */
 156        STORE_PT_GLOBALS(l5)
 157        STORE_PT_YREG(l5, g3)
 158
 159        /* Save current in a global while we change windows. */
 160        mov     %l4, %curptr
 161
 162        save    %g0, %g0, %g0
 163
 164        /* LOCATION: Window 'O' */
 165
 166        rd      %psr, %g3               /* Read %psr in live user window */
 167        mov     %fp, %g4                /* Save bogus frame pointer. */
 168
 169        save    %g0, %g0, %g0
 170
 171        /* LOCATION: Window 'T' */
 172
 173        sethi   %hi(STACK_OFFSET), %l5
 174        or      %l5, %lo(STACK_OFFSET), %l5
 175        add     %curptr, %l5, %sp
 176
 177        /* Build rest of pt_regs. */
 178        STORE_PT_INS(sp)
 179        STORE_PT_PRIV(sp, t_psr, t_pc, t_npc)
 180
 181        /* re-set trap time %wim value */
 182        wr      %t_wim, 0x0, %wim
 183
 184        /* Fix users window mask and buffer save count. */
 185        mov     0x1, %g5
 186        sll     %g5, %g3, %g5
 187        st      %g5, [%curptr + TI_UWINMASK]            ! one live user window still
 188        st      %g0, [%curptr + TI_W_SAVED]             ! no windows in the buffer
 189
 190        wr      %t_psr, PSR_ET, %psr                    ! enable traps
 191        nop
 192        call    window_underflow_fault
 193         mov    %g4, %o0
 194
 195        b       ret_trap_entry
 196         clr    %l6
 197
 198fwin_user_stack_is_ok:
 199        /* LOCATION: Window 'W' */
 200
 201        /* The users stack area is kosher and mapped, load the
 202         * window and fall through to the finish up routine.
 203         */
 204        LOAD_WINDOW(sp)
 205
 206        /* Round and round she goes... */
 207        save    %g0, %g0, %g0           /* Save to window 'O' */
 208        save    %g0, %g0, %g0           /* Save to window 'T' */
 209        /* Where she'll trap nobody knows... */
 210
 211        /* LOCATION: Window 'T' */
 212
 213fwin_user_finish_up:
 214        /* LOCATION: Window 'T' */
 215
 216        wr      %t_psr, 0x0, %psr
 217        WRITE_PAUSE     
 218
 219        jmp     %t_pc
 220        rett    %t_npc
 221
 222        /* Here come the architecture specific checks for stack.
 223         * mappings.  Note that unlike the window overflow handler
 224         * we only need to check whether the user can read from
 225         * the appropriate addresses.  Also note that we are in
 226         * an invalid window which will be loaded, and this means
 227         * that until we actually load the window up we are free
 228         * to use any of the local registers contained within.
 229         *
 230         * On success these routine branch to fwin_user_stack_is_ok
 231         * if the area at %sp is user readable and the window still
 232         * needs to be loaded, else fwin_user_finish_up if the
 233         * routine has done the loading itself.  On failure (bogus
 234         * user stack) the routine shall branch to the label called
 235         * fwin_user_stack_is_bolixed.
 236         *
 237         * Contrary to the arch-specific window overflow stack
 238         * check routines in wof.S, these routines are free to use
 239         * any of the local registers they want to as this window
 240         * does not belong to anyone at this point, however the
 241         * outs and ins are still verboten as they are part of
 242         * 'someone elses' window possibly.
 243         */
 244
 245        .align  4
 246        .globl  sun4c_fwin_stackchk
 247sun4c_fwin_stackchk:
 248        /* LOCATION: Window 'W' */
 249
 250        /* Caller did 'andcc %sp, 0x7, %g0' */
 251        be      1f
 252         and    %sp, 0xfff, %l0         ! delay slot
 253
 254        b,a     fwin_user_stack_is_bolixed
 255
 256        /* See if we have to check the sanity of one page or two */
 2571:
 258        add     %l0, 0x38, %l0
 259        sra     %sp, 29, %l5
 260        add     %l5, 0x1, %l5
 261        andncc  %l5, 0x1, %g0
 262        be      1f
 263         andncc %l0, 0xff8, %g0
 264
 265        b,a     fwin_user_stack_is_bolixed      /* %sp is in vma hole, yuck */
 266
 2671:
 268        be      sun4c_fwin_onepage      /* Only one page to check */
 269         lda    [%sp] ASI_PTE, %l1
 270sun4c_fwin_twopages:
 271        add     %sp, 0x38, %l0
 272        sra     %l0, 29, %l5
 273        add     %l5, 0x1, %l5
 274        andncc  %l5, 0x1, %g0
 275        be      1f
 276         lda    [%l0] ASI_PTE, %l1
 277
 278        b,a     fwin_user_stack_is_bolixed      /* Second page in vma hole */
 279
 2801:
 281        srl     %l1, 29, %l1
 282        andcc   %l1, 0x4, %g0
 283        bne     sun4c_fwin_onepage
 284         lda    [%sp] ASI_PTE, %l1      
 285
 286        b,a     fwin_user_stack_is_bolixed      /* Second page has bad perms */
 287
 288sun4c_fwin_onepage:
 289        srl     %l1, 29, %l1
 290        andcc   %l1, 0x4, %g0
 291        bne     fwin_user_stack_is_ok
 292         nop
 293
 294        /* A page had bad page permissions, losing... */
 295        b,a     fwin_user_stack_is_bolixed
 296
 297        .globl  srmmu_fwin_stackchk
 298srmmu_fwin_stackchk:
 299        /* LOCATION: Window 'W' */
 300
 301        /* Caller did 'andcc %sp, 0x7, %g0' */
 302        bne     fwin_user_stack_is_bolixed
 303         sethi   %hi(PAGE_OFFSET), %l5
 304
 305        /* Check if the users stack is in kernel vma, then our
 306         * trial and error technique below would succeed for
 307         * the 'wrong' reason.
 308         */
 309        mov     AC_M_SFSR, %l4
 310        cmp     %l5, %sp
 311        bleu    fwin_user_stack_is_bolixed
 312         lda    [%l4] ASI_M_MMUREGS, %g0        ! clear fault status
 313
 314        /* The technique is, turn off faults on this processor,
 315         * just let the load rip, then check the sfsr to see if
 316         * a fault did occur.  Then we turn on fault traps again
 317         * and branch conditionally based upon what happened.
 318         */
 319        lda     [%g0] ASI_M_MMUREGS, %l5        ! read mmu-ctrl reg
 320        or      %l5, 0x2, %l5                   ! turn on no-fault bit
 321        sta     %l5, [%g0] ASI_M_MMUREGS        ! store it
 322
 323        /* Cross fingers and go for it. */
 324        LOAD_WINDOW(sp)
 325
 326        /* A penny 'saved'... */
 327        save    %g0, %g0, %g0
 328        save    %g0, %g0, %g0
 329        /* Is a BADTRAP earned... */
 330
 331        /* LOCATION: Window 'T' */
 332
 333        lda     [%g0] ASI_M_MMUREGS, %twin_tmp1 ! load mmu-ctrl again
 334        andn    %twin_tmp1, 0x2, %twin_tmp1     ! clear no-fault bit
 335        sta     %twin_tmp1, [%g0] ASI_M_MMUREGS ! store it
 336
 337        mov     AC_M_SFAR, %twin_tmp2
 338        lda     [%twin_tmp2] ASI_M_MMUREGS, %g0 ! read fault address
 339
 340        mov     AC_M_SFSR, %twin_tmp2
 341        lda     [%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2  ! read fault status
 342        andcc   %twin_tmp2, 0x2, %g0                    ! did fault occur?
 343
 344        bne     1f                                      ! yep, cleanup
 345         nop
 346
 347        wr      %t_psr, 0x0, %psr
 348        nop
 349        b       fwin_user_finish_up + 0x4
 350         nop
 351
 352        /* Did I ever tell you about my window lobotomy?
 353         * anyways... fwin_user_stack_is_bolixed expects
 354         * to be in window 'W' so make it happy or else
 355         * we watchdog badly.
 356         */
 3571:
 358        restore %g0, %g0, %g0
 359        b       fwin_user_stack_is_bolixed      ! oh well
 360         restore        %g0, %g0, %g0
 361