root/arch/sparc/kernel/entry.S

/* [previous][next][first][last][top][bottom][index][help] */
   1 /* arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
   2  *
   3  * Sparc traps are so ugly, this code is going to go through a lot
   4  * of changes as I find out more interesting things. See head.S for
   5  * the trap table and how it works, this will show you how we get
   6  * to these routines.
   7  *
   8  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
   9  */
  10 
  11 #include <asm/head.h>
  12 
  13 /* Here are macros for routines we do often, this allows me to inline this
  14  * without making the code look real ugly. Well, the macro looks ugly too but
  15  * makes the trap entry code easier to understand.
  16  */
  17 
  18 /* I really don't like synthetic instructions. So I avoid them like the
  19  * plague.
  20  */
  21 
  22 /* Note that when I have to write a window out, and it is a user's window, I
  23  * have to check that the pages of memory that I am going to throw the window(s)
  24  * onto are valid and are writable by the user (this is %sp to %sp + 64) before
  25  * I start dumping stuff there. We always assume that kernels stack is ok.
  26  *
  27  * If we have to save a kernel window, only one branch is taken. This should
  28  * make trap handlers quicker in this scenario.
  29  *
  30  * Once 'current' is loaded into %g6, it stays there until we leave
  31  * this macro.
  32  *
  33  * XXX must do some checking on the assumption that kernel stack is always ok
  34  */
  35 
  36 /* I will document how this works real soon. TODO */
  37 
  38 #define TRAP_WIN_CLEAN \
  39         or      %g0, %g5, %l5;    /* we need the globals to do our work */ \
  40         or      %g0, %g6, %l6;    /* and %l0 to %l4 are loaded with important */ \
  41         or      %g0, %g7, %l7;    /* information like the psr and pc's to return to */ \
  42         sethi   %hi(_current), %g6; \
  43         ld      [%g6 + %lo(_current)], %g6; \
  44         ld      [%g6 + THREAD_UWINDOWS], %g7; /* how many user wins are active? */ \
  45         subcc   %g7, 0x0, %g0
  46         bne     2f;                            /* If there are any, branch. */ \
  47         save    %g0, %g0, %g0;                 /* Save into that window either way. */ \
  48         std     %l0, [%sp];                    /* If above shows only kernel windows */ \
  49 1:      std     %l2, [%sp + 0x8];              /* then we get here. */ \
  50         std     %l4, [%sp + 0x10]; \
  51         std     %l6, [%sp + 0x18]; \
  52         std     %i0, [%sp + 0x20]; \
  53         std     %i2, [%sp + 0x28]; \
  54         std     %i4, [%sp + 0x30]; \
  55         std     %i6, [%sp + 0x38]; \
  56         or      %g0, 0x1, %g5; \
  57         rd      %psr, %g7; \
  58         sll     %g5, %g7, %g5; \
  59         wr      %g5, 0x0, %wim;                 /* update %wim to 'now' invalid */ \
  60         and     %g7, 0x1f, %g7; \
  61         st      %g7, [%g6 + THREAD_WIM];        /* save 'this' threads mask */ \
  62         restore %g0, %g0, %g0; \
  63         or      %g0, %l5, %g5;                  /* restore the globals we used */ \
  64         or      %g0, %l6, %g6; \
  65         b       8f;                             /* we are done */ \
  66         or      %g0, %l7, %g7; \
  67 2:      sub     %g7, 0x1, %g7; \
  68         st      %g7, [%g6 + THREAD_UWINDOWS];   /* There are user windows if we */ \
  69         andcc   %sp, 0x7, %g0;                  /* get here. Check for stack alignment. */ \
  70         bne     5f;                             /* Stack is unaligned, yuck. */ \
  71         sra     %sp, 0x1e, %g7;                 /* This stuff checks to see if top 3-bits */ \
  72         subcc   %g7, 0x0, %g0;                  /* of stack pointer address are ok. */ \
  73         be,a    3f; \
  74         andn    %sp, 0xfff, %g7; \
  75         subcc   %g7, -1, %g0; \
  76         bne     5f;                             /* bad stack pointer, ugh */ \
  77         andn    %sp, 0xfff, %g7; \
  78 3:      lda     [%g7] ASI_PTE, %g7;             /* Ok, user stack is a valid address */ \
  79         srl     %g7, 0x1d, %g7; \
  80         subcc   %g7, 0x6, %g0;                  /* Can the user write to it? */ \
  81         bne     5f; \
  82         and     %sp, 0xfff, %g7; \
  83         subcc   %g7, 0xfc1, %g0;                /* Is our save area on one page? */ \
  84         bl,a    1b; \
  85         std     %l0, [%sp]; \
  86         add     %sp, 0x38, %g5;                 /* Nope, have to check both pages */ \
  87         sra     %g5, 0x1e, %g7; \
  88         subcc   %g7, 0x0, %g0; \
  89         be,a    4f; \
  90         andn    %g5, 0xfff, %g7; \
  91         subcc   %g7, -1, %g0; \
  92         bne     5f; \
  93         andn    %g5, 0xfff, %g7; \
  94 4:      lda     [%g7] ASI_PTE, %g7;             /* Stack space in 2nd page is valid */ \
  95         srl     %g7, 0x1d, %g7; \
  96         subcc   %g7, 0x6, %g0;                  /* Can user write here too? */ \
  97         be,a    1b; \
  98         std     %l0, [%sp]; \
  99 5:      ld      [%g6 + THREAD_UWINDOWS], %g7;   /* This is due to either bad page perms */ \
 100         add     %g6, THREAD_REG_WINDOW, %g5;    /* for the users stack area, or the stack */ \
 101 6:      std     %l0, [%g5];                     /* pointer is misaligned. See above. */ \
 102         std     %l2, [%g5 + 0x8]; \
 103         std     %l4, [%g5 + 0x10]; \
 104         std     %l6, [%g5 + 0x18]; \
 105         std     %i0, [%g5 + 0x20]; \
 106         std     %i2, [%g5 + 0x28]; \
 107         std     %i4, [%g5 + 0x30]; \
 108         std     %i6, [%g5 + 0x38]; \
 109         subcc   %g7, 0x1, %g7; \
 110         bge,a   6b;                             /* while(uwindows>=0) { write_win(); */ \
 111         save    %g5, 0x40, %g5;                 /*     uwindows--; } */ \
 112         st      %sp, [%g6 + THREAD_USP]; \
 113         or      %g0, 0x1, %g5; \
 114         rd      %psr, %g7; \
 115         sll     %g5, %g7, %g5; \
 116         wr      %g5, 0x0, %wim; \
 117         and     %g7, 0x1f, %g7; \
 118         st      %g7, [%g6 + THREAD_WIM];        /* Update thread_struct fields */ \
 119         ld      [%g6 + THREAD_UWINDOWS], %g7; \
 120         add     %g7, 0x1, %g5; \
 121         st      %g5, [%g6 + THREAD_W_SAVED]; \
 122         st      %g0, [%g6 + THREAD_UWINDOWS]; \
 123 7:      subcc   %g7, 0x1, %g7;                  /* Restore back to where we started. */ \
 124         bge     7b; \
 125         restore %g0, %g0, %g0; \
 126         or      %g0, %l5, %g5;                  /* Restore the globals. */ \
 127         or      %g0, %l6, %g6; \
 128         or      %g0, %l7, %g7; \
 129 8:                                              /* We are done when we get here. */ \
 130 
 131 
 132 /* As if the last macro wasn't enough, we have to go through a very similar routine
 133  * upon entry to most traps and interrupts. This is save away the current window
 134  * if it is the trap window, clean it, and adjust the stack for the handler c-code
 135  * to work.
 136  */
 137 
 138 #define ENTER_TRAP \
 139         rd      %wim, %l4; \
 140         or      %g0, 0x1, %l5; \
 141         sll     %l5, %l0, %l5; \
 142         andcc   %l0, 0x40, %g0; \
 143         bz      1f; \
 144         andcc   %l4, %l5, %g0; \
 145         bz,a    3f; \
 146         sub     %fp, 0xb0, %sp; \
 147         TRAP_WIN_CLEAN \
 148         b       3f; \
 149         sub     %fp, 0xb0, %sp; \
 150 1:      sethi   %hi(_current), %l6; \
 151         ld      [%l6 + %lo(_current)], %l6; \
 152         ld      [%l6 + THREAD_WIM], %l5; \
 153         and     %l0, 0x1f, %l4; \
 154         cmp     %l5, %l3; \
 155         ble,a   4f; \
 156         sethi   %hi(_nwindowsm1), %l4; \
 157         sub     %l5, %l3, %l3; \
 158         b       5f; \
 159         sub     %l3, 0x1, %l5; \
 160 4:      ld      [%l4 + %lo(_nwindowsm1)], %l4; \
 161         sub     %l4, %l3, %l4; \
 162         add     %l5, %l4, %l5; \
 163 5:      st      %l5, [%l6 + THREAD_UWINDOWS]; \
 164         bz,a    2f; \
 165         sethi   %hi(TASK_SIZE-176), %l5; \
 166         TRAP_WIN_CLEAN; \
 167         sethi   %hi(_current), %l6; \
 168         ld      [%l6 + %lo(_current)], %l6; \
 169         sethi   %hi(TASK_SIZE-176), %l5; \
 170 2:      or      %l5, %lo(TASK_SIZE-176), %l5; \
 171         add     %l6, %l5, %sp; \
 172 3: \
 173 
 174 #define ENTER_IRQ \
 175         rd      %wim, %l4; \
 176         or      %g0, 0x1, %l5; \
 177         sll     %l5, %l0, %l5; \
 178         andcc   %l0, 0x40, %g0; \
 179         bz      1f; \
 180         andcc   %l4, %l5, %g0; \
 181         bz,a    0f; \
 182         sethi   %hi(_eintstack), %l7; \
 183         TRAP_WIN_CLEAN \
 184         sethi   %hi(_eintstack), %l7; \
 185 0:      cmp     %fp, %l7; \
 186         bge,a   3f; \
 187         sub     %l7, 0xb0, %sp; \
 188         b       3f; \
 189         sub     %fp, 0xb0, %sp; \
 190 1:      sethi   %hi(_current), %l6; \
 191         ld      [%l6 + %lo(_current)], %l6; \
 192         ld      [%l6 + PCB_WIM], %l5; \
 193         and     %l0, 0x1f, %l7; \
 194         cmp     %l5, %l7; \
 195         ble,a   4f; \
 196         sethi   %hi(_nwindowsm1), %l4; \
 197         sub     %l5, %l7, %l7; \
 198         b       5f; \
 199         sub     %l7, 0x1, %l5; \
 200 4:      ld      [%l4 + %lo(_nwindowsm1)], %l4; \
 201         sub     %l4, %l7, %l4; \
 202         add     %l5, %l4, %l5; \
 203 5:      st      %l5, [%l6 + THREAD_UWINDOWS]; \
 204         bz,a    2f; \
 205         sethi   %hi(_eintstack), %l7; \
 206         TRAP_WIN_CLEAN; \
 207         sethi   %hi(_eintstack), %l7; \
 208 2: \
 209         sub     %l7, 0xb0, %sp; \
 210 3: \
 211 
 212         .text
 213         .align 4
 214 
 215 /* Default trap handler */
 216         .globl my_trap_handler
 217 my_trap_handler:
 218                 rd %wim, %l4
 219                 or %g0, 0x1, %l5
 220                 sll %l5, %l0, %l5
 221                 cmp %l4, %l5        ! are we in the invalid window?
 222         
 223                 TRAP_WIN_CLEAN
 224 
 225                 nop
 226                 or %%g0, %l3, %o0
 227                 call _do_hw_interrupt
 228                 or %%g0, %%g0, %o1
 229                 wr %l0, 0x20, %psr  ! re-enable traps and reset the condition codes
 230                 nop
 231                 nop
 232                 nop                 ! click our heels three times, "no place like home"
 233                 jmp %l1
 234                 rett %l2
 235         
 236 /* This routine is optimized for kernel window fills. User fills take about two
 237  * or three extra jumps on the average. We'll see how this works out.
 238  */
 239 
 240 /* Don't use local labels, or if you do be REAL CAREFUL. TRAP_WIN_CLEAN is
 241  * full of them! If you think this routine is hairy, window spills are worse,
 242  * see below.
 243  */
 244 
 245         .globl fill_window_entry
 246 fill_window_entry:
 247         andcc   %l0, 0x40, %g0          ! see if this is a user window fill
 248         bz,a    fill_from_user
 249         nop
 250 
 251         TRAP_WIN_CLEAN                  /* danger, danger... */
 252         wr      %l0, 0x0, %psr  
 253         nop
 254         jmp     %l1
 255         rett    %l2
 256 
 257 fill_from_user:
 258         sethi   %hi(_current), %l6
 259         ld      [%l6 + %lo(_current)], %l6
 260         ld      [%l6 + THREAD_WIM], %l5
 261         and     %l0, 0x1f, %l3
 262 
 263 /* I don't know whats worse, the extra comparison here, or an extra load
 264  * from a lookup table, we'll see.
 265  */
 266         cmp     %l5, %l3
 267         ble,a   1f
 268         sethi   %hi(_nwindowsm1), %l4
 269         sub     %l5, %l3, %l3
 270         b       2f
 271         sub     %l3, 0x1, %l5
 272 1:      ld      [%l4 + %lo(_nwindowsm1)], %l4
 273         sub     %l4, %l3, %l4
 274         add     %l5, %l4, %l5
 275 2:      st      %l5, [%l6 + THREAD_UWINDOWS]
 276 
 277         TRAP_WIN_CLEAN             /* danger, danger... */
 278         sethi   %hi(_current), %l6
 279         ld      [%l6 + %lo(_current)], %l6
 280         ld      [%l6 + THREAD_KSP], %sp
 281         and     %l0, 0x1f, %l3
 282         sethi   %hi(lnx_winmask), %l6
 283         or      %l6, %lo(lnx_winmask), %l6
 284         ldub    [%l6 + %l3], %l5
 285         b       back_to_userland_safety         ! may need a sched()
 286         rd      %wim, %l4
 287 
 288 /* A window spill has occurred.  This presents a weird situation, a restore
 289  * was attempted and a trap occurred. Therefore the restore attempt had no
 290  * effect on window movement and the trap saved, which means it went in the
 291  * other direction. :-( We are in a trap window which is two restores away
 292  * from the window we want to un-invalidate sorta speak and three away from
 293  * the one which will become invalid after this routine. There are probably
 294  * bugs already this routine. Bugs suck.
 295  */
 296 
 297 /* This is a very complicated and hairy routine, don't expect to understand
 298  * it the first time. :>
 299  */
 300 
 301         .globl spill_window_entry
 302 spill_window_entry:
 303         wr      %g0, 0, %wim            ! Can not enter invalid register without this.
 304         andcc   %l0, 0x40, %g0          ! From user?
 305         restore                         ! restore to where trap occurred
 306         bz      spill_from_user
 307         restore                         ! enter invalid register, whee...
 308         restore %g0, 0x1, %l1           ! enter one-past invalid register
 309         rd      %psr, %l0               ! this is the window we need to save
 310         and     %l0, 0x1f, %l0
 311         sll     %l1, %l0, %l1
 312         wr      %l1, 0x0, %wim
 313         sethi   %hi(_current), %l1
 314         ld      [%l1 + %lo(_current)], %l1
 315         st      %l0, [%l1 + THREAD_WIM]
 316         save    %g0, %g0, %g0           ! back to invalid register
 317         ldd     %l0, [%sp]              ! load the window from stack
 318         ldd     %l2, [%sp + 8]
 319         ldd     %l4, [%sp + 16]
 320         ldd     %l6, [%sp + 24]
 321         ldd     %i0, [%sp + 32]
 322         ldd     %i2, [%sp + 40]
 323         ldd     %i4, [%sp + 48]
 324         ldd     %i6, [%sp + 56]
 325         save    %g0, %g0, %g0           ! to window where trap happened
 326         save    %g0, %g0, %g0           ! back to trap window, so rett works
 327         wr      %l0, 0x0, %psr          ! load condition codes
 328         nop
 329         jmp     %l1
 330         rett    %l2                     ! are you as confused as I am?
 331 
 332 spill_from_user:
 333         andcc   %sp, 0x7, %g0           ! check for alignment of user stack
 334         bne     spill_bad_stack
 335         sra     %sp, 0x1e, %l7
 336         cmp     %l7, 0x0
 337         be,a    1f
 338         andn    %sp, 0xfff, %l7
 339         cmp     %l7, -1
 340         bne     spill_bad_stack
 341         andn    %sp, 0xfff, %l7
 342 1:      lda     [%l7] ASI_PTE, %l7
 343         srl     %l7, 0x1d, %l7
 344         andn    %l7, 0x2, %l7
 345         cmp     %l7, 0x4
 346         bne     spill_bad_stack
 347         and     %sp, 0xfff, %l7
 348         cmp     %l7, 0xfc1
 349         bl,a    spill_stack_ok
 350         restore %g0, 1, %l1
 351         add     %sp, 0x38, %l5
 352         sra     %sp, 0x1e, %l7
 353         cmp     %l7, 0x0
 354         be,a    1f
 355         andn    %sp, 0xfff, %l7
 356         cmp     %l7, -1
 357         bne     spill_bad_stack
 358         andn    %sp, 0xfff, %l7
 359 1:      lda     [%l7] ASI_PTE, %l7
 360         srl     %l7, 0x1d, %l7
 361         andn    %l7, 0x2, %l7
 362         cmp     %l7, 0x4
 363         be,a    spill_stack_ok
 364         restore %g0, 0x1, %l1
 365 
 366 spill_bad_stack:
 367         save    %g0, %g0, %g0                   ! save to where restore happened
 368         save    %g0, 0x1, %l4                   ! save is an add remember? to trap window
 369         sethi   %hi(_current), %l6
 370         ld      [%l6 + %lo(_current)], %l6
 371         st      %l4, [%l6 + THREAD_UWINDOWS]    ! update current->tss values
 372         ld      [%l6 + THREAD_WIN], %l5
 373         sll     %l4, %l5, %l4
 374         wr      %l4, 0x0, %wim
 375         ld      [%l6 + THREAD_KSP], %sp         ! set to kernel stack pointer
 376         wr      %l0, 0x20, %psr                 ! turn off traps
 377         std     %l0, [%sp + C_STACK]            ! set up thread_frame on stack
 378         rd      %y, %l3
 379         std     %l2, [%sp + C_STACK + 0x8]
 380         or      %g0, 0x6, %o0                   ! so _sparc_trap knows what to do
 381         st      %g1, [%sp + C_STACK + 0x14]     ! no need to save %g0, always zero
 382         or      %g0, %l0, %o1
 383         std     %g2, [%sp + C_STACK + 0x18]
 384         or      %g0, %l1, %o2
 385         std     %g4, [%sp + C_STACK + 0x20]
 386         add     %sp, C_STACK, %o3
 387         std     %g6, [%sp + C_STACK + 0x28]
 388         std     %i0, [%sp + C_STACK + 0x30]
 389         std     %i2, [%sp + C_STACK + 0x38]
 390         std     %i4, [%sp + C_STACK + 0x40]
 391         call    _sparc_trap
 392         std     %i6, [%sp + C_STACK + 0x48]
 393         
 394         ldd     [%sp + C_STACK], %l0
 395         ldd     [%sp + C_STACK + 0x8], %l2
 396         wr      %l3, 0, %y
 397         ld      [%sp + C_STACK + 0x14], %g1
 398         ldd     [%sp + C_STACK + 0x18], %g2
 399         ldd     [%sp + C_STACK + 0x20], %g4
 400         ldd     [%sp + C_STACK + 0x28], %g6
 401         ldd     [%sp + C_STACK + 0x30], %i0
 402         ldd     [%sp + C_STACK + 0x38], %i2
 403         ldd     [%sp + C_STACK + 0x40], %i4
 404         wr      %l0, 0, %psr                    ! disable traps again
 405         ldd     [%sp + C_STACK + 0x48], %i6
 406         sethi   %hi(_current), %l6
 407         ld      [%l6 + %lo(_current)], %l6
 408         ld      [%l6 + THREAD_W_SAVED], %l7
 409         cmp     %l7, 0x0
 410         bl,a    1f
 411         wr      %g0, 0x0, %wim
 412         b,a     leave_trap
 413 
 414 1:      or      %g0, %g6, %l3
 415         or      %g0, %l6, %g6
 416         st      %g0, [%g6 + THREAD_W_SAVED]
 417         restore %g0, %g0, %g0
 418         restore %g0, %g0, %g0
 419         restore %g0, 0x1, %l1
 420         rd      %psr, %l0
 421         sll     %l1, %l0, %l1
 422         wr      %l1, 0x0, %wim
 423         and     %l0, 0x1f, %l0
 424         st      %l0, [%g6 + THREAD_WIM]
 425         nop
 426         save    %g0, %g0, %g0
 427         ldd     [%sp], %l0                      ! load number one
 428         ldd     [%sp + 0x8], %l2
 429         ldd     [%sp + 0x10], %l4
 430         ldd     [%sp + 0x18], %l6
 431         ldd     [%sp + 0x20], %i0
 432         ldd     [%sp + 0x28], %i2
 433         ldd     [%sp + 0x30], %i4
 434         ldd     [%sp + 0x38], %i6
 435         save    %g0, %g0, %g0
 436         ldd     [%sp], %l0                      ! load number two
 437         ldd     [%sp + 0x8], %l2        
 438         ldd     [%sp + 0x10], %l4
 439         ldd     [%sp + 0x18], %l6
 440         ldd     [%sp + 0x20], %i0
 441         ldd     [%sp + 0x28], %i2
 442         ldd     [%sp + 0x30], %i4
 443         ldd     [%sp + 0x38], %i6
 444         save    %g0, %g0, %g0                   ! re-enter trap window
 445         wr      %l0, 0x0, %psr                  ! restore condition codes
 446         or      %g0, %l3, %g6                   ! restore scratch register
 447         jmp     %l1
 448         rett    %l2
 449 
 450 spill_stack_ok:
 451         rd      %psr, %l0
 452         sll     %l1, %l0, %l1
 453         wr      %l1, 0x0, %wim
 454         sethi   %hi(_current), %l2
 455         ld      [%l2 + %lo(_current)], %l2
 456         and     %l0, 0x1f, %l0
 457         st      %l0, [%l2 + THREAD_WIM]
 458         save    %g0, %g0, %g0
 459         ldd     [%sp], %l0                      ! only one load necessary
 460         ldd     [%sp + 0x8], %l2
 461         ldd     [%sp + 0x10], %l4
 462         ldd     [%sp + 0x18], %l6
 463         ldd     [%sp + 0x20], %i0
 464         ldd     [%sp + 0x28], %i2
 465         ldd     [%sp + 0x30], %i4
 466         ldd     [%sp + 0x38], %i6
 467         save    %g0, %g0, %g0
 468         save    %g0, %g0, %g0                   ! save into trap window
 469         wr      %l0, 0x0, %psr                  ! local number 0 here has cond codes
 470         nop
 471         jmp     %l1
 472         rett    %l2
 473 
 474 /* The following two things point to window management tables. The first
 475    one is used to quickly look up how many user windows there are from
 476    trap-land. The second is used in a trap handler to determine if a rett
 477    instruction will land us smack inside the invalid window that possibly
 478    the trap was called to fix-up.
 479 */
 480 
 481 /* For now these are static tables geared for a 7 window sparc. */
 482 
 483                 .data
 484                 .align 4
 485 lnx_winmask:    .byte   2, 4, 8, 16, 32, 64, 128,1  ! lnx_winmask[0..7]
 486 
 487         

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