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

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