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) 1995 David S. Miller (davem@caip.rutgers.edu)
   9  */
  10 
  11 
  12 #include <asm/head.h>
  13 #include <asm/asi.h>
  14 #include <asm/contregs.h>
  15 #include <asm/psr.h>
  16 #include <asm/cprefix.h>
  17 #include <asm/vaddrs.h>
  18 #include <asm/memreg.h>
  19 #include <asm/page.h>
  20 
  21 #define NR_SYSCALLS 255      /* Each OS is different... */
  22 
  23 /* A debugging macro, it just prints a dot on the screen.  For now
  24  * it is only used in the context switch code since it is so delicate
  25  * I need to use the prom putchar() routines and reload the pointers
  26  * every time.  This clobbers %l7 and %o0.
  27  */
  28 #define DO_SPARC_DOT \
  29         sethi   %hi(C_LABEL(romvec)), %l7; \
  30         ld      [%l7 + %lo(C_LABEL(romvec))], %l7; \
  31         ld      [%l7 + 0x54], %l7; \
  32         or      %g0, '.', %o0; \
  33         call    %l7; \
  34         nop; \
  35         nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; \
  36 
  37 /* Another macro, the name speaks for itself. */
  38 #define DROP_THE_BOMB \
  39         sethi   %hi(C_LABEL(romvec)), %l7;  \
  40         ld      [%l7 + %lo(C_LABEL(romvec))], %l7;  \
  41         ld      [%l7 + 0x74], %l7;  \
  42         call    %l7;  \
  43         nop;  \
  44 
  45 /* Turn off interrupts while we change contexts. Clobbers %l7 */
  46 #define TRAPS_OFF \
  47         rd      %psr, %l7; \
  48         andn    %l7, (PSR_ET), %l7; \
  49         wr      %l7, 0x0, %psr; \
  50 
  51 /* Here are macros for routines we do often, this allows me to inline this
  52  * without making the code look real ugly.  Well, the macro looks ugly too
  53  * but makes the trap entry code easier to understand.
  54  */
  55 
  56 /* I really don't like synthetic instructions. So I avoid them like the
  57  * plague.
  58  */
  59 
  60 /* Note that when I have to write a window out, and it is a user's window, I
  61  * have to check that the pages of memory that I am going to throw the window(s)
  62  * onto are valid and are writable by the user (this is %sp to %sp + 64) before
  63  * I start dumping stuff there. We always assume that kernels stack is ok.
  64  * XXX Will change on MP's XXX
  65  *
  66  * If we have to save a kernel window, only one branch is taken. This should
  67  * make trap handlers quicker in this scenario.
  68  *
  69  * Once 'current' is loaded into %g6, it stays there until we leave
  70  * this macro.
  71  */
  72 
  73 /* I will document how this works real soon. TODO */
  74 
  75 #define TRAP_WIN_CLEAN \
  76         or      %g0, %g5, %l5;    /* we need the globals to do our work */ \
  77         or      %g0, %g6, %l6;    /* and %l0 to %l4 are loaded with important */ \
  78         or      %g0, %g7, %l7;    /* information like the psr and pc's to return to */ \
  79         sethi   %hi( C_LABEL(current) ), %g6; \
  80         ld      [%g6 + %lo( C_LABEL(current) )], %g6; \
  81         ld      [%g6 + THREAD_UWINDOWS], %g7; /* how many user wins are active? */ \
  82         subcc   %g7, 0x0, %g0; \
  83         bne     2f;                            /* If there are any, branch. */ \
  84         save    %g0, %g0, %g0;                 /* Save into that window either way. */ \
  85         std     %l0, [%sp];                    /* If above shows only kernel windows */ \
  86 1:      std     %l2, [%sp + 0x8];              /* then we get here. */ \
  87         std     %l4, [%sp + 0x10]; \
  88         std     %l6, [%sp + 0x18]; \
  89         std     %i0, [%sp + 0x20]; \
  90         std     %i2, [%sp + 0x28]; \
  91         std     %i4, [%sp + 0x30]; \
  92         std     %i6, [%sp + 0x38]; \
  93         or      %g0, 0x1, %g5; \
  94         rd      %psr, %g7; \
  95         sll     %g5, %g7, %g5; \
  96         wr      %g5, 0x0, %wim;                 /* update %wim to 'now' invalid */ \
  97         and     %g7, 0x1f, %g7; \
  98         sethi   %hi( C_LABEL(current) ), %g6; \
  99         ld      [%g6 + %lo( C_LABEL(current) )], %g6; \
 100         st      %g7, [%g6 + THREAD_WIM];        /* save 'this' threads mask */ \
 101         restore %g0, %g0, %g0; \
 102         or      %g0, %l5, %g5;                  /* restore the globals we used */ \
 103         or      %g0, %l6, %g6; \
 104         b       8f;                             /* we are done */ \
 105         or      %g0, %l7, %g7; \
 106 2:      sub     %g7, 0x1, %g7; \
 107         sethi   %hi( C_LABEL(current) ), %g6; \
 108         ld      [%g6 + %lo( C_LABEL(current) )], %g6; \
 109         st      %g7, [%g6 + THREAD_UWINDOWS];   /* There are user windows if we */ \
 110         andcc   %sp, 0x7, %g0;                  /* get here. Check for stack alignment. */ \
 111         bne     5f;                             /* Stack is unaligned, yuck. */ \
 112         sra     %sp, 0x1e, %g7;                 /* This stuff checks to see if top 3-bits */ \
 113         subcc   %g7, 0x0, %g0;                  /* of stack pointer address are ok. */ \
 114         be,a    3f; \
 115         andn    %sp, 0xfff, %g7; \
 116         subcc   %g7, -1, %g0; \
 117         bne     5f;                             /* bad stack pointer, ugh */ \
 118         andn    %sp, 0xfff, %g7; \
 119 3:      lda     [%g7] ASI_PTE, %g7;             /* Ok, user stack is a valid address */ \
 120         srl     %g7, 0x1d, %g7; \
 121         subcc   %g7, 0x6, %g0;                  /* Can the user write to it? */ \
 122         bne     5f; \
 123         and     %sp, 0xfff, %g7; \
 124         subcc   %g7, 0xfc1, %g0;                /* Is our save area on one page? */ \
 125         bl,a    1b; \
 126         std     %l0, [%sp]; \
 127         add     %sp, 0x38, %g5;                 /* Nope, have to check both pages */ \
 128         sra     %g5, 0x1e, %g7; \
 129         subcc   %g7, 0x0, %g0; \
 130         be,a    4f; \
 131         andn    %g5, 0xfff, %g7; \
 132         subcc   %g7, -1, %g0; \
 133         bne     5f; \
 134         andn    %g5, 0xfff, %g7; \
 135 4:      lda     [%g7] ASI_PTE, %g7;             /* Stack space in 2nd page is valid */ \
 136         srl     %g7, 0x1d, %g7; \
 137         subcc   %g7, 0x6, %g0;                  /* Can user write here too? */ \
 138         be,a    1b; \
 139         std     %l0, [%sp]; \
 140 5:      ld      [%g6 + THREAD_UWINDOWS], %g7;   /* This is due to either bad page perms */ \
 141         add     %g6, THREAD_REG_WINDOW, %g5;    /* for the users stack area, or the stack */ \
 142 6:      std     %l0, [%g5];                     /* pointer is misaligned. See above. */ \
 143         std     %l2, [%g5 + 0x8]; \
 144         std     %l4, [%g5 + 0x10]; \
 145         std     %l6, [%g5 + 0x18]; \
 146         std     %i0, [%g5 + 0x20]; \
 147         std     %i2, [%g5 + 0x28]; \
 148         std     %i4, [%g5 + 0x30]; \
 149         std     %i6, [%g5 + 0x38]; \
 150         subcc   %g7, 0x1, %g7; \
 151         bge,a   6b;                             /* while(uwindows>=0) { write_win(); */ \
 152         save    %g5, 0x40, %g5;                 /*     uwindows--; } */ \
 153         st      %sp, [%g6 + THREAD_USP]; \
 154         or      %g0, 0x1, %g5; \
 155         rd      %psr, %g7; \
 156         sll     %g5, %g7, %g5; \
 157         wr      %g5, 0x0, %wim; \
 158         and     %g7, 0x1f, %g7; \
 159         st      %g7, [%g6 + THREAD_WIM];        /* Update thread_struct fields */ \
 160         ld      [%g6 + THREAD_UWINDOWS], %g7; \
 161         add     %g7, 0x1, %g5; \
 162         st      %g5, [%g6 + THREAD_W_SAVED]; \
 163         st      %g0, [%g6 + THREAD_UWINDOWS]; \
 164 7:      subcc   %g7, 0x1, %g7;                  /* Restore back to where we started. */ \
 165         bge     7b; \
 166         restore %g0, %g0, %g0; \
 167         or      %g0, %l5, %g5;                  /* Restore the globals. */ \
 168         or      %g0, %l6, %g6; \
 169         or      %g0, %l7, %g7; \
 170 8:      nop;                                     /* We are done when we get here. */ \
 171 
 172 /* As if the last macro wasn't enough, we have to go through a very similar routine
 173  * upon entry to most traps and interrupts. This is save away the current window
 174  * if it is the trap window, clean it, and adjust the stack for the handler c-code
 175  * to work.
 176  *
 177  * See asm-sparc/cprefix.h to see how the CONCAT macros work.
 178  */
 179 /* NOTE: The system call entry code ASSUMES that the ENTER_TRAP macro
 180  *       does NOT touch register %l7 and leaves the same contents after
 181  *       the macro is done. Keep in mind if you change this code.
 182  */
 183 
 184 #define ENTER_TRAP(label) \
 185         rd      %wim, %l4; \
 186         or      %g0, 0x1, %l5; \
 187         sll     %l5, %l0, %l5; \
 188         andcc   %l0, PSR_PS, %g0; \
 189         bz      CONCAT1(label, 1); \
 190         andcc   %l4, %l5, %g0; \
 191         bz,a    CONCAT1(label, 3); \
 192         sub     %fp, 0xb0, %sp; \
 193         TRAP_WIN_CLEAN \
 194         b       CONCAT1(label, 3); \
 195         sub     %fp, 0xb0, %sp; \
 196 CONCAT1(label, 1): \
 197         sethi   %hi( C_LABEL(current) ), %l6; \
 198         ld      [%l6 + %lo( C_LABEL(current) )], %l6; \
 199         ld      [%l6 + THREAD_WIM], %l5; \
 200         and     %l0, 0x1f, %l4; \
 201         cmp     %l5, %l3; \
 202         ble,a   CONCAT1(label, 4); \
 203         sethi   %hi( C_LABEL(nwindowsm1) ), %l4; \
 204         sub     %l5, %l3, %l3; \
 205         b       CONCAT1(label, 5); \
 206         sub     %l3, 0x1, %l5; \
 207 CONCAT1(label, 4): \
 208         ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
 209         sub     %l4, %l3, %l4; \
 210         add     %l5, %l4, %l5; \
 211 CONCAT1(label, 5): \
 212         st      %l5, [%l6 + THREAD_UWINDOWS]; \
 213         bz,a    CONCAT1(label, 2); \
 214         sethi   %hi(C_LABEL(current)), %l6; \
 215         TRAP_WIN_CLEAN \
 216         sethi   %hi(C_LABEL(current)), %l6; \
 217 CONCAT1(label, 2): \
 218         ld      [%l6 + %lo(C_LABEL(current))], %l6; \
 219         ld      [%l6 + TASK_KSTACK_PG], %l6; \
 220         add     %l6, (PAGE_SIZE - 96 - 80), %l6; \
 221         andn    %l6, 0x7, %l6; \
 222         or      %g0, %l6, %sp; \
 223 CONCAT1(label, 3):
 224 
 225 /* What needs to be executed upon entry to an interrupt.
 226  *
 227  * See asm-sparc/cprefix.h to see how the CONCAT macros work.
 228  */
 229 
 230 #define ENTER_IRQ(label) \
 231         rd      %wim, %l4; \
 232         or      %g0, 0x1, %l5; \
 233         sll     %l5, %l0, %l5; \
 234         andcc   %l0, PSR_PS, %g0; \
 235         bz      CONCAT1(label, 1); \
 236         andcc   %l4, %l5, %g0; \
 237         bz,a    CONCAT1(label, 0); \
 238         sethi   %hi( C_LABEL(eintstack) ), %l7; \
 239         TRAP_WIN_CLEAN \
 240         sethi   %hi( C_LABEL(eintstack) ), %l7; \
 241 CONCAT1(label, 0): \
 242         subcc   %fp, %l7, %g0; \
 243         bge,a   CONCAT1(label, 3); \
 244         sub     %l7, 0xb0, %sp; \
 245         b       CONCAT1(label, 3); \
 246         sub     %fp, 0xb0, %sp; \
 247 CONCAT1(label, 1): \
 248         sethi   %hi( C_LABEL(current) ), %l6; \
 249         ld      [%l6 + %lo( C_LABEL(current) )], %l6; \
 250         ld      [%l6 + THREAD_WIM], %l5; \
 251         and     %l0, 0x1f, %l7; \
 252         cmp     %l5, %l7; \
 253         ble,a   CONCAT1(label, 4); \
 254         sethi   %hi( C_LABEL(nwindowsm1) ), %l4; \
 255         sub     %l5, %l7, %l7; \
 256         b       CONCAT1(label, 5); \
 257         sub     %l7, 0x1, %l5; \
 258 CONCAT1(label, 4): \
 259         ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
 260         sub     %l4, %l7, %l4; \
 261         add     %l5, %l4, %l5; \
 262 CONCAT1(label, 5): \
 263         st      %l5, [%l6 + THREAD_UWINDOWS]; \
 264         bz,a    CONCAT1(label, 2); \
 265         sethi   %hi( C_LABEL(eintstack) ), %l7; \
 266         TRAP_WIN_CLEAN \
 267         sethi   %hi( C_LABEL(eintstack) ), %l7; \
 268 CONCAT1(label, 2): \
 269         sub     %l7, 0xb0, %sp; \
 270 CONCAT1(label, 3):
 271 
 272 
 273         .text
 274         .align 4
 275 
 276 /* Bad trap handler */
 277         .globl bad_trap_handler
 278 bad_trap_handler:
 279         ENTER_TRAP(bad_trap_handler)
 280 
 281         or      %g0, %l3, %o0
 282         or      %g0, %l0, %o1
 283         call    C_LABEL(do_hw_interrupt)
 284         or      %g0, %l1, %o2
 285 
 286         jmp     %l1
 287         rett %  l2
 288         
 289         .align 4
 290         .globl sparc_timer
 291 sparc_timer:
 292         ENTER_IRQ(sparc_timer)
 293 
 294         sethi   %hi(C_LABEL(master_l10_limit)), %l4
 295         ld      [%l4 + %lo(C_LABEL(master_l10_limit))], %l4
 296         ld      [%l4], %g0                      ! read the limit register
 297 
 298         std     %g2, [%sp + C_STACK + PT_G2]
 299         or      %g0, %g1, %l7
 300         rd      %y, %l6
 301         std     %g4, [%sp + C_STACK + PT_G4]
 302         andn    %l0, PSR_PIL, %l4
 303 /*      sll     %l3, 0x8, %l5 */
 304         std     %g6, [%sp + C_STACK + PT_G6]
 305 /*      or      %l5, %l4, %l4 */
 306 
 307         /* Magic, we can't increase PIL and set ET at the same
 308          * time or the chip calls prom_panic().
 309          */
 310 /*      wr      %l4, 0x0, %psr */
 311         wr      %l4, PSR_ET, %psr
 312 
 313         or      %g0, 10, %o0
 314         add     %sp, C_STACK, %o1
 315         call    C_LABEL(do_IRQ)
 316         nop
 317 
 318         or      %g0, %l7, %g1
 319         wr      %l6, 0x0, %y
 320         ldd     [%sp + C_STACK + PT_G2], %g2
 321         ldd     [%sp + C_STACK + PT_G4], %g4
 322         ldd     [%sp + C_STACK + PT_G6], %g6
 323 
 324         b       ret_trap_entry
 325         wr      %l0, 0x0, %psr
 326 
 327 /* For now all IRQ's not registered get sent here. handler_irq() will
 328  * see if a routine is registered to handle this interrupt and if not
 329  * it will say so on the console.
 330  */
 331 
 332         .align 4
 333         .globl real_irq_entry
 334 real_irq_entry:
 335         ENTER_IRQ(real_irq_entry)
 336         std     %g2, [%sp + C_STACK + PT_G2]
 337         or      %g0, %g1, %l7
 338         rd      %y, %l6
 339         std     %g4, [%sp + C_STACK + PT_G4]
 340         andn    %l0, PSR_PIL, %l4
 341         sll     %l3, 0x8, %l5
 342         std     %g6, [%sp + C_STACK + PT_G6]
 343         or      %l5, %l4, %l4
 344 
 345         wr      %l4, 0x0, %psr
 346         wr      %l4, PSR_ET, %psr
 347 
 348         std     %l0, [%sp + C_STACK + PT_PSR]
 349         std     %l2, [%sp + C_STACK + PT_NPC]
 350         
 351         or      %g0, %l3, %o0   
 352         add     %sp, C_STACK, %o1
 353         call    C_LABEL(handler_irq)
 354         nop
 355 
 356         or      %g0, %l7, %g1
 357         wr      %l6, 0x0, %y
 358         ldd     [%sp + C_STACK + PT_G2], %g2
 359         ldd     [%sp + C_STACK + PT_G4], %g4
 360         ldd     [%sp + C_STACK + PT_G6], %g6
 361         b       ret_trap_entry
 362         wr      %l0, 0x0, %psr
 363 
 364 
 365 /* This routine is optimized for kernel window fills. User fills take about two
 366  * or three extra jumps on the average. We'll see how this works out.
 367  */
 368 
 369 /* Don't use local labels, or if you do be REAL CAREFUL. TRAP_WIN_CLEAN is
 370  * full of them! If you think this routine is hairy, window fills are worse,
 371  * see below.
 372  */
 373 
 374         .align 4
 375         .globl spill_window_entry
 376 spill_window_entry:
 377         andcc   %l0, PSR_PS, %g0        ! see if this is a user window fill
 378         bz,a    spill_from_user
 379         nop
 380 
 381         TRAP_WIN_CLEAN                  /* danger, danger... */
 382         wr      %l0, 0x0, %psr  
 383         nop
 384         jmp     %l1
 385         rett    %l2
 386 
 387 spill_from_user:
 388         sethi   %hi( C_LABEL(current) ), %l6
 389         ld      [%l6 + %lo( C_LABEL(current) )], %l6
 390         ld      [%l6 + THREAD_WIM], %l5
 391         and     %l0, 0x1f, %l3
 392 
 393 /* I don't know what's worse, the extra comparison here, or an extra load
 394  * from a lookup table, we'll see.
 395  */
 396         cmp     %l5, %l3
 397         ble,a   1f
 398         sethi   %hi( C_LABEL(nwindowsm1) ), %l4
 399         sub     %l5, %l3, %l3
 400         b       2f
 401         sub     %l3, 0x1, %l5
 402 1:
 403         ld      [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
 404         sub     %l4, %l3, %l4
 405         add     %l5, %l4, %l5
 406 2:
 407         st      %l5, [%l6 + THREAD_UWINDOWS]
 408 
 409         TRAP_WIN_CLEAN             /* danger, danger... */
 410         sethi   %hi( C_LABEL(current) ), %l6
 411         ld      [%l6 + %lo( C_LABEL(current) )], %l6
 412         ld      [%l6 + THREAD_KSP], %sp
 413         and     %l0, 0x1f, %l3
 414         sethi   %hi(lnx_winmask), %l6
 415         or      %l6, %lo(lnx_winmask), %l6
 416         ldub    [%l6 + %l3], %l5
 417         rd      %wim, %l4
 418         jmp     %l1
 419         rett    %l2
 420 
 421 /* A window spill has occurred.  This presents a weird situation, a restore
 422  * was attempted and a trap occurred. Therefore the restore attempt had no
 423  * effect on window movement and the trap saved, which means it went in the
 424  * other direction. :-( We are in a trap window which is two restores away
 425  * from the window we want to un-invalidate so to speak and three away from
 426  * the one which will become invalid after this routine. There are probably
 427  * bugs already this routine. Bugs suck.
 428  */
 429 
 430 /* This is a very complicated and hairy routine, don't expect to understand
 431  * it the first time. :>
 432  */
 433 
 434         .align 4
 435         .globl fill_window_entry
 436 fill_window_entry:
 437         wr      %g0, 0, %wim            ! Can not enter invalid register without this.
 438         andcc   %l0, 0x40, %g0          ! From user?
 439         restore                         ! restore to where trap occurred
 440         bz      fill_from_user
 441         restore                         ! enter invalid register, whee...
 442         restore %g0, 0x1, %l1           ! enter one-past invalid register
 443         rd      %psr, %l0               ! this is the window we need to save
 444         and     %l0, 0x1f, %l0
 445         sll     %l1, %l0, %l1
 446         wr      %l1, 0x0, %wim
 447         sethi   %hi( C_LABEL(current) ), %l1
 448         ld      [%l1 + %lo( C_LABEL(current) )], %l1
 449         st      %l0, [%l1 + THREAD_WIM]
 450         save    %g0, %g0, %g0           ! back to invalid register
 451         ldd     [%sp], %l0              ! load the window from stack
 452         ldd     [%sp + 8], %l2
 453         ldd     [%sp + 16], %l4
 454         ldd     [%sp + 24], %l6
 455         ldd     [%sp + 32], %i0
 456         ldd     [%sp + 40], %i2
 457         ldd     [%sp + 48], %i4
 458         ldd     [%sp + 56], %i6
 459         save    %g0, %g0, %g0           ! to window where trap happened
 460         save    %g0, %g0, %g0           ! back to trap window, so rett works
 461         wr      %l0, 0x0, %psr          ! load condition codes
 462         nop
 463         jmp     %l1
 464         rett    %l2                     ! are you as confused as I am?
 465 
 466 fill_from_user:
 467         andcc   %sp, 0x7, %g0           ! check for alignment of user stack
 468         bne     fill_bad_stack
 469         sra     %sp, 0x1e, %l7
 470         cmp     %l7, 0x0
 471         be,a    1f
 472         andn    %sp, 0xfff, %l7
 473         cmp     %l7, -1
 474         bne     fill_bad_stack
 475         andn    %sp, 0xfff, %l7
 476 1:
 477         lda     [%l7] ASI_PTE, %l7
 478         srl     %l7, 0x1d, %l7
 479         andn    %l7, 0x2, %l7
 480         cmp     %l7, 0x4
 481         bne     fill_bad_stack
 482         and     %sp, 0xfff, %l7
 483         cmp     %l7, 0xfc1
 484         bl,a    fill_stack_ok
 485         restore %g0, 1, %l1
 486         add     %sp, 0x38, %l5
 487         sra     %sp, 0x1e, %l7
 488         cmp     %l7, 0x0
 489         be,a    1f
 490         andn    %sp, 0xfff, %l7
 491         cmp     %l7, -1
 492         bne     fill_bad_stack
 493         andn    %sp, 0xfff, %l7
 494 1:
 495         lda     [%l7] ASI_PTE, %l7
 496         srl     %l7, 0x1d, %l7
 497         andn    %l7, 0x2, %l7
 498         cmp     %l7, 0x4
 499         be,a    fill_stack_ok
 500         restore %g0, 0x1, %l1
 501 
 502 fill_bad_stack:
 503         save    %g0, %g0, %g0                   ! save to where restore happened
 504         save    %g0, 0x1, %l4                   ! save is an add remember? to trap window
 505         sethi   %hi( C_LABEL(current) ), %l6
 506         ld      [%l6 + %lo( C_LABEL(current) )], %l6
 507         st      %l4, [%l6 + THREAD_UWINDOWS]    ! update current->tss values
 508         ld      [%l6 + THREAD_WIM], %l5
 509         sll     %l4, %l5, %l4
 510         wr      %l4, 0x0, %wim
 511         ld      [%l6 + THREAD_KSP], %sp         ! set to kernel stack pointer
 512         wr      %l0, PSR_ET, %psr               ! turn off traps
 513         std     %l0, [%sp + C_STACK]            ! set up thread_frame XXX
 514         rd      %y, %l3
 515         std     %l2, [%sp + C_STACK + 0x8]
 516         or      %g0, 0x6, %o0                   ! so _sparc_trap knows what to do
 517         st      %g1, [%sp + C_STACK + 0x14]     ! no need to save %g0, always zero
 518         or      %g0, %l0, %o1
 519         std     %g2, [%sp + C_STACK + 0x18]
 520         or      %g0, %l1, %o2
 521         std     %g4, [%sp + C_STACK + 0x20]
 522         add     %sp, C_STACK, %o3
 523         std     %g6, [%sp + C_STACK + 0x28]
 524         std     %i0, [%sp + C_STACK + 0x30]
 525         std     %i2, [%sp + C_STACK + 0x38]
 526         std     %i4, [%sp + C_STACK + 0x40]
 527         nop                                     /* SHould trap here */
 528         std     %i6, [%sp + C_STACK + 0x48]
 529         
 530         ldd     [%sp + C_STACK], %l0
 531         ldd     [%sp + C_STACK + 0x8], %l2
 532         wr      %l3, 0, %y
 533         ld      [%sp + C_STACK + 0x14], %g1
 534         ldd     [%sp + C_STACK + 0x18], %g2
 535         ldd     [%sp + C_STACK + 0x20], %g4
 536         ldd     [%sp + C_STACK + 0x28], %g6
 537         ldd     [%sp + C_STACK + 0x30], %i0
 538         ldd     [%sp + C_STACK + 0x38], %i2
 539         ldd     [%sp + C_STACK + 0x40], %i4
 540         wr      %l0, 0, %psr                    ! disable traps again
 541         ldd     [%sp + C_STACK + 0x48], %i6
 542         sethi   %hi( C_LABEL(current) ), %l6
 543         ld      [%l6 + %lo( C_LABEL(current) )], %l6
 544         ld      [%l6 + THREAD_W_SAVED], %l7
 545         cmp     %l7, 0x0
 546         bl,a    1f
 547         wr      %g0, 0x0, %wim
 548         /* Should trap here */
 549 
 550 1:
 551         or      %g0, %g6, %l3
 552         or      %g0, %l6, %g6
 553         st      %g0, [%g6 + THREAD_W_SAVED]
 554         restore %g0, %g0, %g0
 555         restore %g0, %g0, %g0
 556         restore %g0, 0x1, %l1
 557         rd      %psr, %l0
 558         sll     %l1, %l0, %l1
 559         wr      %l1, 0x0, %wim
 560         and     %l0, 0x1f, %l0
 561         st      %l0, [%g6 + THREAD_WIM]
 562         nop
 563         save    %g0, %g0, %g0
 564         ldd     [%sp], %l0                      ! load number one
 565         ldd     [%sp + 0x8], %l2
 566         ldd     [%sp + 0x10], %l4
 567         ldd     [%sp + 0x18], %l6
 568         ldd     [%sp + 0x20], %i0
 569         ldd     [%sp + 0x28], %i2
 570         ldd     [%sp + 0x30], %i4
 571         ldd     [%sp + 0x38], %i6
 572         save    %g0, %g0, %g0
 573         ldd     [%sp], %l0                      ! load number two
 574         ldd     [%sp + 0x8], %l2        
 575         ldd     [%sp + 0x10], %l4
 576         ldd     [%sp + 0x18], %l6
 577         ldd     [%sp + 0x20], %i0
 578         ldd     [%sp + 0x28], %i2
 579         ldd     [%sp + 0x30], %i4
 580         ldd     [%sp + 0x38], %i6
 581         save    %g0, %g0, %g0                   ! re-enter trap window
 582         wr      %l0, 0x0, %psr                  ! restore condition codes
 583         or      %g0, %l3, %g6                   ! restore scratch register
 584         jmp     %l1
 585         rett    %l2
 586 
 587 fill_stack_ok:
 588         rd      %psr, %l0
 589         sll     %l1, %l0, %l1
 590         wr      %l1, 0x0, %wim
 591         sethi   %hi( C_LABEL(current) ), %l2
 592         ld      [%l2 + %lo( C_LABEL(current) )], %l2
 593         and     %l0, 0x1f, %l0
 594         st      %l0, [%l2 + THREAD_WIM]
 595         save    %g0, %g0, %g0
 596         ldd     [%sp], %l0                      ! only one load necessary
 597         ldd     [%sp + 0x8], %l2
 598         ldd     [%sp + 0x10], %l4
 599         ldd     [%sp + 0x18], %l6
 600         ldd     [%sp + 0x20], %i0
 601         ldd     [%sp + 0x28], %i2
 602         ldd     [%sp + 0x30], %i4
 603         ldd     [%sp + 0x38], %i6
 604         save    %g0, %g0, %g0
 605         save    %g0, %g0, %g0                   ! save into trap window
 606         wr      %l0, 0x0, %psr                  ! local number 0 here has cond codes
 607         nop
 608         jmp     %l1
 609         rett    %l2
 610 
 611         /* This routine handles illegal isntructions and privileged
 612          * instruction attempts from user code.
 613          */
 614         .align 4
 615         .globl bad_instruction
 616 bad_instruction:
 617         ENTER_TRAP(bad_instruction)
 618         st      %g1, [%sp + C_STACK + PT_G1]
 619         rd      %y, %l4
 620         std     %g2, [%sp + C_STACK + PT_G2]
 621         std     %g4, [%sp + C_STACK + PT_G4]
 622         std     %g6, [%sp + C_STACK + PT_G6]
 623         wr      %l0, PSR_ET, %psr               ! re-enable traps
 624         add     %sp, C_STACK, %o0
 625         mov     %l1, %o1
 626         mov     %l2, %o2
 627         cmp     %l3, 0x2
 628         bne     1f
 629         call    C_LABEL(do_illegal_instruction)
 630         mov     %l0, %o3
 631         b       2f
 632         ld      [%sp + C_STACK + PT_G1], %g1
 633 
 634 1:
 635         call    C_LABEL(do_priv_instruction)
 636         mov     %l0, %o3
 637         ld      [%sp + C_STACK + PT_G1], %g1
 638 2:
 639         wr      %l0, 0x0, %psr
 640         ldd     [%sp + C_STACK + PT_G2], %g2
 641         ldd     [%sp + C_STACK + PT_G4], %g4
 642         ldd     [%sp + C_STACK + PT_G6], %g6
 643         b       ret_trap_entry
 644         wr      %l4, 0, %y
 645 
 646         /* This routine handles unaligned data accesses.
 647          */
 648         .align 4
 649         .globl mna_handler
 650 mna_handler:
 651         ENTER_TRAP(mna_handler)
 652         st      %g1, [%sp + C_STACK + PT_G1]
 653         rd      %y, %l4
 654         std     %g2, [%sp + C_STACK + PT_G2]
 655         std     %g4, [%sp + C_STACK + PT_G4]
 656         std     %g6, [%sp + C_STACK + PT_G6]
 657         wr      %l0, PSR_ET, %psr               ! re-enable traps
 658         add     %sp, C_STACK, %o0
 659         mov     %l1, %o1
 660         mov     %l2, %o2
 661         call    C_LABEL(do_memaccess_unaligned)
 662         mov     %l0, %o3
 663 
 664         ld      [%sp + C_STACK + PT_G1], %g1
 665         wr      %l0, 0x0, %psr
 666         ldd     [%sp + C_STACK + PT_G2], %g2
 667         ldd     [%sp + C_STACK + PT_G4], %g4
 668         ldd     [%sp + C_STACK + PT_G6], %g6
 669         b       ret_trap_entry
 670         wr      %l4, 0, %y
 671 
 672         /* This routine handles floating point disabled traps.
 673          */
 674         .align 4
 675         .globl fpd_trap_handler
 676 fpd_trap_handler:
 677         ENTER_TRAP(fpd_trap_handler)
 678         st      %g1, [%sp + C_STACK + PT_G1]
 679         rd      %y, %l4
 680         std     %g2, [%sp + C_STACK + PT_G2]
 681         std     %g4, [%sp + C_STACK + PT_G4]
 682         std     %g6, [%sp + C_STACK + PT_G6]
 683         wr      %l0, PSR_ET, %psr               ! re-enable traps
 684         add     %sp, C_STACK, %o0
 685         mov     %l1, %o1
 686         mov     %l2, %o2
 687         call    C_LABEL(do_fpd_trap)
 688         mov     %l0, %o3
 689 
 690         ld      [%sp + C_STACK + PT_G1], %g1
 691         wr      %l0, 0x0, %psr
 692         ldd     [%sp + C_STACK + PT_G2], %g2
 693         ldd     [%sp + C_STACK + PT_G4], %g4
 694         ldd     [%sp + C_STACK + PT_G6], %g6
 695         b       ret_trap_entry
 696         wr      %l4, 0, %y
 697 
 698         /* This routine handles Floating Point Exceptions.
 699          */
 700         .align 4
 701         .globl fpe_trap_handler
 702 fpe_trap_handler:
 703         ENTER_TRAP(fpe_trap_handler)
 704         st      %g1, [%sp + C_STACK + PT_G1]
 705         rd      %y, %l4
 706         std     %g2, [%sp + C_STACK + PT_G2]
 707         std     %g4, [%sp + C_STACK + PT_G4]
 708         std     %g6, [%sp + C_STACK + PT_G6]
 709         wr      %l0, PSR_ET, %psr               ! re-enable traps
 710         add     %sp, C_STACK, %o0
 711         mov     %l1, %o1
 712         mov     %l2, %o2
 713         call    C_LABEL(do_fpe_trap)
 714         mov     %l0, %o3
 715 
 716         ld      [%sp + C_STACK + PT_G1], %g1
 717         wr      %l0, 0x0, %psr
 718         ldd     [%sp + C_STACK + PT_G2], %g2
 719         ldd     [%sp + C_STACK + PT_G4], %g4
 720         ldd     [%sp + C_STACK + PT_G6], %g6
 721         b       ret_trap_entry
 722         wr      %l4, 0, %y
 723 
 724         /* This routine handles Tag Overflow Exceptions.
 725          */
 726         .align 4
 727         .globl do_tag_overflow
 728 do_tag_overflow:
 729         ENTER_TRAP(do_tag_overflow)
 730         st      %g1, [%sp + C_STACK + PT_G1]
 731         rd      %y, %l4
 732         std     %g2, [%sp + C_STACK + PT_G2]
 733         std     %g4, [%sp + C_STACK + PT_G4]
 734         std     %g6, [%sp + C_STACK + PT_G6]
 735         wr      %l0, PSR_ET, %psr               ! re-enable traps
 736         add     %sp, C_STACK, %o0
 737         mov     %l1, %o1
 738         mov     %l2, %o2
 739         call    C_LABEL(handle_tag_overflow)
 740         mov     %l0, %o3
 741 
 742         ld      [%sp + C_STACK + PT_G1], %g1
 743         wr      %l0, 0x0, %psr
 744         ldd     [%sp + C_STACK + PT_G2], %g2
 745         ldd     [%sp + C_STACK + PT_G4], %g4
 746         ldd     [%sp + C_STACK + PT_G6], %g6
 747         b       ret_trap_entry
 748         wr      %l4, 0, %y
 749 
 750         /* This routine handles Watchpoint Exceptions.
 751          */
 752         .align 4
 753         .globl do_watchpoint
 754 do_watchpoint:
 755         ENTER_TRAP(do_watchpoint)
 756         st      %g1, [%sp + C_STACK + PT_G1]
 757         rd      %y, %l4
 758         std     %g2, [%sp + C_STACK + PT_G2]
 759         std     %g4, [%sp + C_STACK + PT_G4]
 760         std     %g6, [%sp + C_STACK + PT_G6]
 761         wr      %l0, PSR_ET, %psr               ! re-enable traps
 762         add     %sp, C_STACK, %o0
 763         mov     %l1, %o1
 764         mov     %l2, %o2
 765         call    C_LABEL(handle_watchpoint)
 766         mov     %l0, %o3
 767 
 768         ld      [%sp + C_STACK + PT_G1], %g1
 769         wr      %l0, 0x0, %psr
 770         ldd     [%sp + C_STACK + PT_G2], %g2
 771         ldd     [%sp + C_STACK + PT_G4], %g4
 772         ldd     [%sp + C_STACK + PT_G6], %g6
 773         b       ret_trap_entry
 774         wr      %l4, 0, %y
 775 
 776         /* This routine handles Register Access Exceptions.
 777          */
 778         .align 4
 779         .globl do_reg_access
 780 do_reg_access:
 781         ENTER_TRAP(do_reg_access)
 782         st      %g1, [%sp + C_STACK + PT_G1]
 783         rd      %y, %l4
 784         std     %g2, [%sp + C_STACK + PT_G2]
 785         std     %g4, [%sp + C_STACK + PT_G4]
 786         std     %g6, [%sp + C_STACK + PT_G6]
 787         wr      %l0, PSR_ET, %psr               ! re-enable traps
 788         add     %sp, C_STACK, %o0
 789         mov     %l1, %o1
 790         mov     %l2, %o2
 791         call    C_LABEL(handle_reg_access)
 792         mov     %l0, %o3
 793 
 794         ld      [%sp + C_STACK + PT_G1], %g1
 795         wr      %l0, 0x0, %psr
 796         ldd     [%sp + C_STACK + PT_G2], %g2
 797         ldd     [%sp + C_STACK + PT_G4], %g4
 798         ldd     [%sp + C_STACK + PT_G6], %g6
 799         b       ret_trap_entry
 800         wr      %l4, 0, %y
 801 
 802         /* This routine handles Instruction Access Errors.
 803          */
 804         .align 4
 805         .globl do_iacc_error
 806 do_iacc_error:
 807         ENTER_TRAP(do_iacc_error)
 808         st      %g1, [%sp + C_STACK + PT_G1]
 809         rd      %y, %l4
 810         std     %g2, [%sp + C_STACK + PT_G2]
 811         std     %g4, [%sp + C_STACK + PT_G4]
 812         std     %g6, [%sp + C_STACK + PT_G6]
 813         wr      %l0, PSR_ET, %psr               ! re-enable traps
 814         add     %sp, C_STACK, %o0
 815         mov     %l1, %o1
 816         mov     %l2, %o2
 817         call    C_LABEL(handle_iacc_error)
 818         mov     %l0, %o3
 819 
 820         ld      [%sp + C_STACK + PT_G1], %g1
 821         wr      %l0, 0x0, %psr
 822         ldd     [%sp + C_STACK + PT_G2], %g2
 823         ldd     [%sp + C_STACK + PT_G4], %g4
 824         ldd     [%sp + C_STACK + PT_G6], %g6
 825         b       ret_trap_entry
 826         wr      %l4, 0, %y
 827 
 828         /* This routine handles Co-Processor Disabled Exceptions.
 829          */
 830         .align 4
 831         .globl do_cp_disabled
 832 do_cp_disabled:
 833         ENTER_TRAP(do_cp_disabled)
 834         st      %g1, [%sp + C_STACK + PT_G1]
 835         rd      %y, %l4
 836         std     %g2, [%sp + C_STACK + PT_G2]
 837         std     %g4, [%sp + C_STACK + PT_G4]
 838         std     %g6, [%sp + C_STACK + PT_G6]
 839         wr      %l0, PSR_ET, %psr               ! re-enable traps
 840         add     %sp, C_STACK, %o0
 841         mov     %l1, %o1
 842         mov     %l2, %o2
 843         call    C_LABEL(handle_cp_disabled)
 844         mov     %l0, %o3
 845 
 846         ld      [%sp + C_STACK + PT_G1], %g1
 847         wr      %l0, 0x0, %psr
 848         ldd     [%sp + C_STACK + PT_G2], %g2
 849         ldd     [%sp + C_STACK + PT_G4], %g4
 850         ldd     [%sp + C_STACK + PT_G6], %g6
 851         b       ret_trap_entry
 852         wr      %l4, 0, %y
 853 
 854         /* This routine handles Unimplemented FLUSH Exceptions.
 855          */
 856         .align 4
 857         .globl do_bad_flush
 858 do_bad_flush:
 859         ENTER_TRAP(do_bad_flush)
 860         st      %g1, [%sp + C_STACK + PT_G1]
 861         rd      %y, %l4
 862         std     %g2, [%sp + C_STACK + PT_G2]
 863         std     %g4, [%sp + C_STACK + PT_G4]
 864         std     %g6, [%sp + C_STACK + PT_G6]
 865         wr      %l0, PSR_ET, %psr               ! re-enable traps
 866         add     %sp, C_STACK, %o0
 867         mov     %l1, %o1
 868         mov     %l2, %o2
 869         call    C_LABEL(handle_bad_flush)
 870         mov     %l0, %o3
 871 
 872         ld      [%sp + C_STACK + PT_G1], %g1
 873         wr      %l0, 0x0, %psr
 874         ldd     [%sp + C_STACK + PT_G2], %g2
 875         ldd     [%sp + C_STACK + PT_G4], %g4
 876         ldd     [%sp + C_STACK + PT_G6], %g6
 877         b       ret_trap_entry
 878         wr      %l4, 0, %y
 879 
 880         /* This routine handles Co-Processor Exceptions.
 881          */
 882         .align 4
 883         .globl do_cp_exception
 884 do_cp_exception:
 885         ENTER_TRAP(do_cp_exception)
 886         st      %g1, [%sp + C_STACK + PT_G1]
 887         rd      %y, %l4
 888         std     %g2, [%sp + C_STACK + PT_G2]
 889         std     %g4, [%sp + C_STACK + PT_G4]
 890         std     %g6, [%sp + C_STACK + PT_G6]
 891         wr      %l0, PSR_ET, %psr               ! re-enable traps
 892         add     %sp, C_STACK, %o0
 893         mov     %l1, %o1
 894         mov     %l2, %o2
 895         call    C_LABEL(handle_cp_exception)
 896         mov     %l0, %o3
 897 
 898         ld      [%sp + C_STACK + PT_G1], %g1
 899         wr      %l0, 0x0, %psr
 900         ldd     [%sp + C_STACK + PT_G2], %g2
 901         ldd     [%sp + C_STACK + PT_G4], %g4
 902         ldd     [%sp + C_STACK + PT_G6], %g6
 903         b       ret_trap_entry
 904         wr      %l4, 0, %y
 905 
 906         /* This routine handles Data Access Errors.
 907          */
 908         .align 4
 909         .globl do_dacc_error
 910 do_dacc_error:
 911         ENTER_TRAP(do_dacc_error)
 912         st      %g1, [%sp + C_STACK + PT_G1]
 913         rd      %y, %l4
 914         std     %g2, [%sp + C_STACK + PT_G2]
 915         std     %g4, [%sp + C_STACK + PT_G4]
 916         std     %g6, [%sp + C_STACK + PT_G6]
 917         wr      %l0, PSR_ET, %psr               ! re-enable traps
 918         add     %sp, C_STACK, %o0
 919         mov     %l1, %o1
 920         mov     %l2, %o2
 921         call    C_LABEL(handle_dacc_error)
 922         mov     %l0, %o3
 923 
 924         ld      [%sp + C_STACK + PT_G1], %g1
 925         wr      %l0, 0x0, %psr
 926         ldd     [%sp + C_STACK + PT_G2], %g2
 927         ldd     [%sp + C_STACK + PT_G4], %g4
 928         ldd     [%sp + C_STACK + PT_G6], %g6
 929         b       ret_trap_entry
 930         wr      %l4, 0, %y
 931 
 932         /* This routine handles Hardware Divide By Zero Exceptions.
 933          */
 934         .align 4
 935         .globl do_hw_divzero
 936 do_hw_divzero:
 937         ENTER_TRAP(do_hw_divzero)
 938         st      %g1, [%sp + C_STACK + PT_G1]
 939         rd      %y, %l4
 940         std     %g2, [%sp + C_STACK + PT_G2]
 941         std     %g4, [%sp + C_STACK + PT_G4]
 942         std     %g6, [%sp + C_STACK + PT_G6]
 943         wr      %l0, PSR_ET, %psr               ! re-enable traps
 944         add     %sp, C_STACK, %o0
 945         mov     %l1, %o1
 946         mov     %l2, %o2
 947         call    C_LABEL(handle_hw_divzero)
 948         mov     %l0, %o3
 949 
 950         ld      [%sp + C_STACK + PT_G1], %g1
 951         wr      %l0, 0x0, %psr
 952         ldd     [%sp + C_STACK + PT_G2], %g2
 953         ldd     [%sp + C_STACK + PT_G4], %g4
 954         ldd     [%sp + C_STACK + PT_G6], %g6
 955         b       ret_trap_entry
 956         wr      %l4, 0, %y
 957 
 958         /* This routine handles Data Store Errors.
 959          */
 960         .align 4
 961         .globl do_dstore_err
 962 do_dstore_err:
 963         ENTER_TRAP(do_dstore_err)
 964         st      %g1, [%sp + C_STACK + PT_G1]
 965         rd      %y, %l4
 966         std     %g2, [%sp + C_STACK + PT_G2]
 967         std     %g4, [%sp + C_STACK + PT_G4]
 968         std     %g6, [%sp + C_STACK + PT_G6]
 969         wr      %l0, PSR_ET, %psr               ! re-enable traps
 970         add     %sp, C_STACK, %o0
 971         mov     %l1, %o1
 972         mov     %l2, %o2
 973         call    C_LABEL(handle_dstore_error)
 974         mov     %l0, %o3
 975 
 976         ld      [%sp + C_STACK + PT_G1], %g1
 977         wr      %l0, 0x0, %psr
 978         ldd     [%sp + C_STACK + PT_G2], %g2
 979         ldd     [%sp + C_STACK + PT_G4], %g4
 980         ldd     [%sp + C_STACK + PT_G6], %g6
 981         b       ret_trap_entry
 982         wr      %l4, 0, %y
 983 
 984         /* This routine handles Data Access MMU-Miss Exceptions.
 985          */
 986         .align 4
 987         .globl do_dacc_mmu_miss
 988 do_dacc_mmu_miss:
 989         ENTER_TRAP(do_dacc_mmu_miss)
 990         st      %g1, [%sp + C_STACK + PT_G1]
 991         rd      %y, %l4
 992         std     %g2, [%sp + C_STACK + PT_G2]
 993         std     %g4, [%sp + C_STACK + PT_G4]
 994         std     %g6, [%sp + C_STACK + PT_G6]
 995         wr      %l0, PSR_ET, %psr               ! re-enable traps
 996         add     %sp, C_STACK, %o0
 997         mov     %l1, %o1
 998         mov     %l2, %o2
 999         call    C_LABEL(handle_dacc_mmu_miss)
1000         mov     %l0, %o3
1001 
1002         ld      [%sp + C_STACK + PT_G1], %g1
1003         wr      %l0, 0x0, %psr
1004         ldd     [%sp + C_STACK + PT_G2], %g2
1005         ldd     [%sp + C_STACK + PT_G4], %g4
1006         ldd     [%sp + C_STACK + PT_G6], %g6
1007         b       ret_trap_entry
1008         wr      %l4, 0, %y
1009 
1010         /* This routine handles Instruction Access MMU-Miss Exceptions.
1011          */
1012         .align 4
1013         .globl do_iacc_mmu_miss
1014 do_iacc_mmu_miss:
1015         ENTER_TRAP(do_iacc_mmu_miss)
1016         st      %g1, [%sp + C_STACK + PT_G1]
1017         rd      %y, %l4
1018         std     %g2, [%sp + C_STACK + PT_G2]
1019         std     %g4, [%sp + C_STACK + PT_G4]
1020         std     %g6, [%sp + C_STACK + PT_G6]
1021         wr      %l0, PSR_ET, %psr               ! re-enable traps
1022         add     %sp, C_STACK, %o0
1023         mov     %l1, %o1
1024         mov     %l2, %o2
1025         call    C_LABEL(handle_iacc_mmu_miss)
1026         mov     %l0, %o3
1027 
1028         ld      [%sp + C_STACK + PT_G1], %g1
1029         wr      %l0, 0x0, %psr
1030         ldd     [%sp + C_STACK + PT_G2], %g2
1031         ldd     [%sp + C_STACK + PT_G4], %g4
1032         ldd     [%sp + C_STACK + PT_G6], %g6
1033         b       ret_trap_entry
1034         wr      %l4, 0, %y
1035 
1036         /* The getcc software trap.  The user wants the condition codes from
1037          * the %psr in register %g1.
1038          */
1039 
1040         .align 4
1041         .globl getcc_trap_handler
1042 getcc_trap_handler:
1043         /* Shit, one more instruction and I could do this inline. */
1044         sll     %l0, 0x8, %g1
1045         srl     %g1, 28, %g1
1046         jmp     %l2
1047         rett    %l2+0x4
1048 
1049         /* The setcc software trap.  The user has condition codes in %g1
1050          * that it would like placed in the %psr.  Be careful not to flip
1051          * any unintention bits!
1052          */
1053 
1054         .align 4
1055         .globl setcc_trap_handler
1056 setcc_trap_handler:
1057         sll     %g1, 0x14, %l4
1058         set     PSR_ICC, %l5
1059         andn    %l0, %l5, %l0
1060         or      %l4, %l0, %l4
1061         wr      %l4, 0x0, %psr
1062         WRITE_PAUSE
1063         jmp     %l2
1064         rett    %l2+0x4
1065 
1066         .align 4
1067 NMI_STRING:     .asciz  "NMI received, dazed and confused, halting...\n"
1068 
1069         .align 4
1070         .globl linux_trap_nmi
1071         .globl C_LABEL(interrupt_enable)
1072 linux_trap_nmi:
1073         sethi   %hi(C_LABEL(prom_vector_p)), %o0
1074         ld      [%o0 + %lo(C_LABEL(prom_vector_p))], %o0
1075         ld      [%o0 + 0x74], %o0
1076         /* Ugh, until I figure out how to clear the IRQ line ;( */
1077         call    %o0
1078         nop
1079 
1080         .align 4
1081         .globl sparc_text_fault
1082 sparc_text_fault:
1083         ENTER_TRAP(sparc_text_fault)
1084         st      %g1, [%sp + C_STACK + PT_G1]
1085         std     %g2, [%sp + C_STACK + PT_G2]
1086         std     %g4, [%sp + C_STACK + PT_G4]
1087         std     %g6, [%sp + C_STACK + PT_G6]
1088         rd      %y, %l4
1089         sethi   %hi(AC_SYNC_ERR), %o0
1090         lda     [%o0] ASI_CONTROL, %o1
1091         add     %o0, 0x4, %o0           ! go to sync vaddr
1092         lda     [%o0] ASI_CONTROL, %o2
1093         andcc   %o1, SUN4C_SYNC_NOMEM, %g0
1094         bz,a    normal_page_fault
1095         wr      %l0, PSR_ET, %psr       ! re-enable traps
1096 
1097         add     %o0, 0x4, %o0           ! go to async error register
1098         lda     [%o0] ASI_CONTROL, %o3
1099         add     %o0, 0x4, %o0           ! go to async vaddr
1100         subcc   %o4, %o2, %g0
1101         be,a    is_sync_fault           ! not an async fault
1102         wr      %l0, PSR_ET, %psr
1103 
1104         /* crap, an asynchronous error has occurred */
1105         sethi   %hi(C_LABEL(interrupt_enable)), %l5
1106         ldub    [%l5 + %lo(C_LABEL(interrupt_enable))], %o0
1107         andn    %o0, INTS_ENAB, %o0
1108         stb     %o0, [%l5 + %lo(C_LABEL(interrupt_enable))]
1109         wr      %l0, PSR_ET, %psr               ! enable traps
1110         call    C_LABEL(sparc_txtmem_error)     ! call high level c-code
1111         or      %g0, FAULT_ASYNC, %o0
1112 
1113         ld      [%sp + C_STACK + PT_G1], %g1
1114         wr      %l0, 0x0, %psr
1115         ldd     [%sp + C_STACK + PT_G2], %g2
1116         ldd     [%sp + C_STACK + PT_G4], %g4
1117         ldd     [%sp + C_STACK + PT_G6], %g6
1118         ldub    [%l5 + %lo(C_LABEL(interrupt_enable))], %o1
1119         or      %o1, INTS_ENAB, %o1
1120         stb     %o1, [%l5 + %lo(C_LABEL(interrupt_enable))]
1121         b       ret_trap_entry
1122         wr      %l4, 0, %y
1123 
1124 is_sync_fault:
1125         call    C_LABEL(sparc_txtmem_error)     ! call high level c-code
1126         or      %g0, FAULT_SYNC, %o0
1127 
1128         ld      [%sp + C_STACK + PT_G1], %g1
1129         ld      [%sp + C_STACK + PT_G2], %g2
1130         ld      [%sp + C_STACK + PT_G4], %g4
1131         ld      [%sp + C_STACK + PT_G6], %g6
1132         wr      %l4, 0x0, %y
1133         b       ret_trap_entry
1134         wr      %l0, 0x0, %psr
1135 
1136 normal_page_fault:
1137         std     %l0, [%sp + C_STACK + PT_PSR]
1138         or      %g0, %l3, %o0
1139         st      %l2, [%sp + C_STACK + PT_NPC]
1140         st      %l4, [%sp + C_STACK + PT_Y]
1141         or      %g0, %l1, %o3
1142         std     %i0, [%sp + C_STACK + PT_I0]
1143         std     %i2, [%sp + C_STACK + PT_I2]
1144         or      %g0, %l0, %o4
1145         std     %i4, [%sp + C_STACK + PT_I4]
1146         std     %i6, [%sp + C_STACK + PT_I6]
1147         call    C_LABEL(sparc_text_access_fault)
1148         add     %sp, C_STACK, %o5
1149 
1150         ldd     [%sp + C_STACK + PT_PSR], %l0
1151         ldd     [%sp + C_STACK + PT_NPC], %l2
1152         wr      %l3, 0x0, %y
1153         ld      [%sp + C_STACK + PT_G1], %g1
1154         ldd     [%sp + C_STACK + PT_G2], %g2
1155         ldd     [%sp + C_STACK + PT_G4], %g4
1156         ldd     [%sp + C_STACK + PT_G6], %g6
1157         ldd     [%sp + C_STACK + PT_I0], %i0
1158         ldd     [%sp + C_STACK + PT_I2], %i2
1159         ldd     [%sp + C_STACK + PT_I4], %i4
1160         ldd     [%sp + C_STACK + PT_I6], %i6
1161 
1162         b       ret_trap_entry
1163         wr      %l0, 0x0, %psr
1164 
1165         .align 4
1166         .globl sparc_data_fault
1167 sparc_data_fault:
1168         ENTER_TRAP(sparc_data_fault)
1169         st      %g1, [%sp + C_STACK + PT_G1]
1170         std     %g2, [%sp + C_STACK + PT_G2]
1171         std     %g4, [%sp + C_STACK + PT_G4]
1172         std     %g6, [%sp + C_STACK + PT_G6]
1173         rd      %y, %l4
1174         sethi   %hi(AC_SYNC_ERR), %o0
1175         lda     [%o0] ASI_CONTROL, %o1
1176         add     %o0, 0x4, %o0           ! go to sync vaddr
1177         lda     [%o0] ASI_CONTROL, %o2
1178         andcc   %o1, SUN4C_SYNC_NOMEM, %g0
1179         bz,a    normal_data_page_fault
1180         wr      %l0, PSR_ET, %psr
1181 
1182         add     %o0, 0x4, %o0           ! go to async error register
1183         lda     [%o0] ASI_CONTROL, %o3
1184         add     %o0, 0x4, %o0           ! go to async vaddr
1185         subcc   %o4, %o2, %g0
1186         be,a    is_data_sync_fault      ! not an async fault
1187         wr      %l0, PSR_ET, %psr
1188 
1189         /* crap, an asynchronous error has occurred */
1190         sethi   %hi(C_LABEL(interrupt_enable)), %l5
1191         ldub    [%l5 + %lo(C_LABEL(interrupt_enable))], %o0
1192         andn    %o0, INTS_ENAB, %o0
1193         stb     %o0, [%l5 + %lo(C_LABEL(interrupt_enable))]
1194         wr      %l0, PSR_ET, %psr
1195         call    C_LABEL(sparc_datamem_error)    ! call high level c-code
1196         or      %g0, FAULT_ASYNC, %o0
1197 
1198         ld      [%sp + C_STACK + PT_G1], %g1
1199         wr      %l0, 0x0, %psr
1200         ldd     [%sp + C_STACK + PT_G2], %g2
1201         ldd     [%sp + C_STACK + PT_G4], %g4
1202         ldd     [%sp + C_STACK + PT_G6], %g6
1203         ldub    [%l5 + %lo(C_LABEL(interrupt_enable))], %o1
1204         or      %o1, INTS_ENAB, %o1
1205         stb     %o1, [%l5 + %lo(C_LABEL(interrupt_enable))]
1206         b       ret_trap_entry
1207         wr      %l4, 0, %y
1208 
1209 is_data_sync_fault:
1210         call    C_LABEL(sparc_datamem_error)    ! call high level c-code
1211         or      %g0, FAULT_SYNC, %o0
1212 
1213         ld      [%sp + C_STACK + PT_G1], %g1
1214         ldd     [%sp + C_STACK + PT_G2], %g2
1215         ldd     [%sp + C_STACK + PT_G4], %g4
1216         ldd     [%sp + C_STACK + PT_G6], %g6
1217         wr      %l4, 0x0, %y
1218         b       ret_trap_entry
1219         wr      %l0, 0x0, %psr
1220 
1221 normal_data_page_fault:
1222         std     %l0, [%sp + C_STACK + PT_PSR]   ! store %psr and pc
1223         or      %g0, %l3, %o0
1224         st      %l2, [%sp + C_STACK + PT_NPC]   ! store npc
1225         st      %l4, [%sp + C_STACK + PT_Y]     ! store %y
1226         or      %g0, %l1, %o3
1227 
1228         /* The globals have already been placed on the stack */
1229         std     %i0, [%sp + C_STACK + PT_I0]    ! store ins
1230         std     %i2, [%sp + C_STACK + PT_I2]
1231         or      %g0, %l0, %o4
1232         std     %i4, [%sp + C_STACK + PT_I4]
1233         std     %i6, [%sp + C_STACK + PT_I6]
1234         call    C_LABEL(sparc_data_access_fault)
1235         add     %sp, C_STACK, %o5
1236 
1237         ldd     [%sp + C_STACK + PT_PSR], %l0
1238         ldd     [%sp + C_STACK + PT_NPC], %l2
1239         wr      %l3, 0x0, %y
1240         ld      [%sp + C_STACK + PT_G1], %g1
1241         ldd     [%sp + C_STACK + PT_G2], %g2
1242         ldd     [%sp + C_STACK + PT_G4], %g4
1243         ldd     [%sp + C_STACK + PT_G6], %g6
1244         ldd     [%sp + C_STACK + PT_I0], %i0
1245         ldd     [%sp + C_STACK + PT_I2], %i2
1246         ldd     [%sp + C_STACK + PT_I4], %i4
1247         ldd     [%sp + C_STACK + PT_I6], %i6
1248 
1249         b       ret_trap_entry
1250         wr      %l0, 0x0, %psr
1251 
1252 
1253         .align 4
1254         .globl C_LABEL(srmmu_text_fault)
1255 C_LABEL(srmmu_text_fault):
1256         ENTER_TRAP(srmmu_text_fault)
1257         st      %g1, [%sp + C_STACK + PT_G1]
1258         std     %g2, [%sp + C_STACK + PT_G2]
1259         std     %g4, [%sp + C_STACK + PT_G4]
1260         std     %g6, [%sp + C_STACK + PT_G6]
1261         rd      %y, %l4
1262         set     0x300, %o0
1263         lda     [%o0] ASI_M_MMUREGS, %o1        ! fault status
1264         set     0x400, %o0
1265         lda     [%o0] ASI_M_MMUREGS, %o2        ! fault address
1266         wr      %l0, PSR_ET, %psr               ! traps back on
1267         WRITE_PAUSE
1268         std     %l0, [%sp + C_STACK + PT_PSR]
1269         or      %g0, %l3, %o0
1270         st      %l2, [%sp + C_STACK + PT_NPC]
1271         st      %l4, [%sp + C_STACK + PT_Y]
1272         or      %g0, %l1, %o3
1273         std     %i0, [%sp + C_STACK + PT_I0]
1274         std     %i2, [%sp + C_STACK + PT_I2]
1275         or      %g0, %l0, %o4
1276         std     %i4, [%sp + C_STACK + PT_I4]
1277         std     %i6, [%sp + C_STACK + PT_I6]
1278         call    C_LABEL(srmmu_text_access_fault)
1279         add     %sp, C_STACK, %o5
1280 
1281         ldd     [%sp + C_STACK + PT_PSR], %l0
1282         ldd     [%sp + C_STACK + PT_NPC], %l2
1283         wr      %l3, 0x0, %y
1284         ld      [%sp + C_STACK + PT_G1], %g1
1285         ldd     [%sp + C_STACK + PT_G2], %g2
1286         ldd     [%sp + C_STACK + PT_G4], %g4
1287         ldd     [%sp + C_STACK + PT_G6], %g6
1288         ldd     [%sp + C_STACK + PT_I0], %i0
1289         ldd     [%sp + C_STACK + PT_I2], %i2
1290         ldd     [%sp + C_STACK + PT_I4], %i4
1291         ldd     [%sp + C_STACK + PT_I6], %i6
1292 
1293         b       ret_trap_entry
1294         wr      %l0, 0x0, %psr
1295 
1296         .align 4
1297         .globl C_LABEL(srmmu_data_fault)
1298 C_LABEL(srmmu_data_fault):
1299         ENTER_TRAP(srmmu_data_fault)
1300         st      %g1, [%sp + C_STACK + PT_G1]
1301         std     %g2, [%sp + C_STACK + PT_G2]
1302         std     %g4, [%sp + C_STACK + PT_G4]
1303         std     %g6, [%sp + C_STACK + PT_G6]
1304         rd      %y, %l4
1305 
1306         set     AC_M_SFSR, %o0
1307         lda     [%o0] ASI_M_MMUREGS, %o1        ! fault status
1308         set     AC_M_SFAR, %o0
1309         lda     [%o0] ASI_M_MMUREGS, %o2        ! fault address
1310         set     AC_M_AFSR, %o0
1311         lda     [%o0] ASI_M_MMUREGS, %o3
1312         set     AC_M_AFAR, %o0
1313         lda     [%o0] ASI_M_MMUREGS, %o4
1314         wr      %l0, PSR_ET, %psr               ! traps back on
1315         WRITE_PAUSE
1316         std     %l0, [%sp + C_STACK + PT_PSR]
1317         or      %g0, %l3, %o0
1318         st      %l2, [%sp + C_STACK + PT_NPC]
1319         st      %l4, [%sp + C_STACK + PT_Y]
1320         std     %i0, [%sp + C_STACK + PT_I0]
1321         std     %i2, [%sp + C_STACK + PT_I2]
1322         std     %i4, [%sp + C_STACK + PT_I4]
1323         std     %i6, [%sp + C_STACK + PT_I6]
1324         call    C_LABEL(srmmu_data_access_fault)
1325         add     %sp, C_STACK, %o5
1326 
1327         ldd     [%sp + C_STACK + PT_PSR], %l0
1328         ldd     [%sp + C_STACK + PT_NPC], %l2
1329         wr      %l3, 0x0, %y
1330         ld      [%sp + C_STACK + PT_G1], %g1
1331         ldd     [%sp + C_STACK + PT_G2], %g2
1332         ldd     [%sp + C_STACK + PT_G4], %g4
1333         ldd     [%sp + C_STACK + PT_G6], %g6
1334         ldd     [%sp + C_STACK + PT_I0], %i0
1335         ldd     [%sp + C_STACK + PT_I2], %i2
1336         ldd     [%sp + C_STACK + PT_I4], %i4
1337         ldd     [%sp + C_STACK + PT_I6], %i6
1338 
1339         b       ret_trap_entry
1340         wr      %l0, 0x0, %psr
1341 
1342 /* Normal Linux system calls enter here... */
1343 /* Trying to make this as generic and simple as possible. */
1344 
1345         .align 4
1346         .globl linux_sparc_syscall
1347 linux_sparc_syscall:
1348         /* Don't dork with %l7, it holds the pointer to the
1349          * system call vector table.  ENTER_TRAP does not
1350          * modify its value.
1351          */
1352         ENTER_TRAP(linux_sparc_syscall)
1353 
1354         /* setup pt_regs stack frame, leave ints off...
1355          * First save all but the current window onto the stack.
1356          * This means nwindows-2 saves and nwindows-2 restores.
1357          */
1358         andn    %l0, PSR_PIL, %l5
1359         wr      %l5, 0xf00, %psr
1360         wr      %l5, 0xf20, %psr        ! no ints, traps on
1361         WRITE_PAUSE
1362         
1363         .globl nop7
1364         /* Flush windows */
1365         save    %sp, -C_STACK, %sp
1366         save    %sp, -C_STACK, %sp
1367         save    %sp, -C_STACK, %sp
1368         save    %sp, -C_STACK, %sp
1369         save    %sp, -C_STACK, %sp
1370 nop7:   save    %sp, -C_STACK, %sp
1371         restore
1372         restore
1373         restore
1374         restore
1375         restore
1376         restore
1377 
1378         rd      %psr, %l6
1379         and     %l6, PSR_CWP, %l6               ! only care about CWP
1380         andn    %l0, PSR_CWP, %l0
1381         or      %l0, %l6, %l0                   ! %l0 is now the new %psr
1382         
1383         std     %l0, [%sp + C_STACK + PT_PSR]   ! save it away
1384         rd      %y, %l3
1385         std     %l2, [%sp + C_STACK + PT_NPC]
1386 
1387         /* Put %wim in %g0 slot, a hack.  This way we ensure that %wim
1388          * sits right behind the current window in %psr, which is what
1389          * we want.
1390          */
1391         rd      %wim, %l4
1392         st      %l4, [%sp + C_STACK + PT_G0]
1393         st      %g1, [%sp + C_STACK + PT_G1]
1394         std     %g2, [%sp + C_STACK + PT_G2]
1395         std     %g4, [%sp + C_STACK + PT_G4]
1396         std     %g6, [%sp + C_STACK + PT_G6]
1397         std     %i0, [%sp + C_STACK + PT_I0]
1398         std     %i2, [%sp + C_STACK + PT_I2]
1399         std     %i4, [%sp + C_STACK + PT_I4]
1400         std     %i6, [%sp + C_STACK + PT_I6]
1401 
1402         wr      %l0, PSR_ET, %psr /* Turn on traps + interrupts */
1403         WRITE_PAUSE
1404 
1405         cmp     %i0, NR_SYSCALLS
1406         bgu,a   C_LABEL(ret_sys_call)
1407         or      %g0, -1, %i0
1408 
1409         cmp     %i0, 0x2                ! fork? Same number for all OSs
1410         bne     not_fork
1411         nop
1412         call    C_LABEL(sys_fork)       ! yep, load pt_regs into first arg
1413         add     %sp, C_STACK, %o0
1414         b       C_LABEL(ret_sys_call)
1415         nop
1416 not_fork:
1417         /* Remember, trap table entry loaded syscall table ptr in %l7 */
1418         sll     %i0, 0x2, %o0
1419         add     %l7, %o0, %l7
1420         ld      [%l7], %o5              ! load up ptr to syscall handler
1421 
1422         mov     %i1, %o0                ! load up arguments
1423         mov     %i2, %o1
1424         mov     %i3, %o2
1425         mov     %i4, %o3
1426         jmpl    %o5, %o7                ! Make syscall
1427         mov     %i5, %o4
1428 
1429         .globl C_LABEL(ret_sys_call)  /* exported for copy_process() */
1430 C_LABEL(ret_sys_call):   /* Child of a fork returns here */
1431         /* dump the pt_regs back into their rightful places */
1432         ldd     [%sp + C_STACK + PT_PSR], %l0
1433         ldd     [%sp + C_STACK + PT_NPC], %l2
1434         wr      %l3, 0x0, %y
1435 
1436         ld      [%sp + C_STACK + PT_G1], %g1
1437         ldd     [%sp + C_STACK + PT_G2], %g2
1438         ldd     [%sp + C_STACK + PT_G4], %g4
1439         ldd     [%sp + C_STACK + PT_G6], %g6
1440         ldd     [%sp + C_STACK + PT_I0], %i0
1441         ldd     [%sp + C_STACK + PT_I2], %i2
1442         ldd     [%sp + C_STACK + PT_I4], %i4
1443         ldd     [%sp + C_STACK + PT_I6], %i6
1444 
1445         /* %i6 is our frame pointer, the restore done by the rett
1446          * instruction will automatically put us back on the users
1447          * stack.
1448          * Advance the pc and npc past the trap instruction, the copy_process()
1449          * code for fork() depends on this being done right before trap return.
1450          */
1451         or      %l2, 0x0, %l5
1452 
1453         or      %l5, 0x0, %l1    /* pc = npc */
1454         add     %l5, 0x4, %l2    /* npc= npc+4 */
1455 
1456         wr      %l0, 0x0, %psr
1457         WRITE_PAUSE     
1458 
1459         /* Fall through to ret_trap_entry */
1460 
1461 /* Return from trap code.  I realized that I was duplicating a lot
1462  * of logic in the various trap handlers. Traps are off upon entry.
1463  */
1464 
1465 ret_trap_entry:
1466         and     %l0, 0x1f, %l5
1467         sethi   %hi(lnx_winmask), %l6
1468         or      %l6, %lo(lnx_winmask), %l6
1469         ldub    [%l6 + %l5], %l5
1470         andcc   %l0, PSR_PS, %g0
1471         bnz     ret_trap_kernel
1472         rd      %wim, %l4
1473 
1474         sethi   %hi(C_LABEL(current)), %l6
1475         ld      [%l6 + %lo(C_LABEL(current))], %l6
1476         ld      [%l6 + THREAD_W_SAVED], %l7
1477         subcc   %g0, %l7, %g0
1478         bz,a    ret_trap_user
1479         nop
1480 
1481         wr      %g0, 0, %wim
1482         or      %g0, %g6, %l3
1483         or      %g0, %l6, %g6
1484         st      %g0, [%g6 + THREAD_W_SAVED]
1485         restore
1486         restore %g0, 1, %l1
1487         rd      %psr, %l0
1488         sll     %l1, %l0, %l1
1489         wr      %l1, 0x0, %wim
1490         and     %l0, 0x1f, %l0
1491         st      %l0, [%g6 + THREAD_WIM]
1492         nop
1493         save    %g0, %g0, %g0
1494         add     %g6, THREAD_REG_WINDOW, %g6
1495         ldd     [%g6], %l0
1496         ldd     [%g6 + 0x8], %l2
1497         ldd     [%g6 + 0x10], %l4
1498         ldd     [%g6 + 0x18], %l6
1499         ldd     [%g6 + 0x20], %i0
1500         ldd     [%g6 + 0x28], %i2
1501         ldd     [%g6 + 0x30], %i4
1502         ldd     [%g6 + 0x38], %i6
1503 
1504         save    %g0, %g0, %g0
1505         wr      %l0, 0x0, %psr
1506         or      %g0, %l3, %g6
1507         jmp     %l1
1508         rett    %l2
1509 
1510 ret_trap_kernel:
1511         andcc   %l4, %l5, %g0
1512         bnz     1f
1513         wr      %l0, 0x0, %psr       ! reset condition codes
1514         nop
1515         jmp     %l1
1516         rett    %l2
1517 
1518 1:
1519         wr      %g0, 0x0, %wim
1520         WRITE_PAUSE
1521         restore
1522         restore %g0, 0x1, %l1
1523         rd      %psr, %l0
1524         and     %l0, 0x1f, %l0
1525         sll     %l1, %l0, %l1
1526         wr      %l1, 0x0, %wim
1527         sethi   %hi(C_LABEL(current)), %l1
1528         ld      [%l1 + %lo(C_LABEL(current))], %l1
1529         st      %l0, [%l1 + THREAD_WIM]
1530         save    %g0, %g0, %g0
1531         ldd     [%sp], %l0
1532         ldd     [%sp + 0x8], %l2
1533         ldd     [%sp + 0x10], %l4
1534         ldd     [%sp + 0x18], %l6
1535         ldd     [%sp + 0x20], %i0
1536         ldd     [%sp + 0x28], %i2
1537         ldd     [%sp + 0x30], %i4
1538         ldd     [%sp + 0x38], %i6
1539 
1540         save    %g0, %g0, %g0
1541         jmp     %l1
1542         rett    %l2
1543 
1544 ret_trap_user:
1545         andcc   %l4, %l5, %g0
1546         bnz     1f
1547         wr      %l0, 0x0, %psr
1548         nop
1549         jmp     %l1
1550         rett    %l2
1551 
1552 1:
1553         wr      %g0, 0x0, %wim
1554         wr      %l0, 0x0, %psr
1555         WRITE_PAUSE
1556         restore
1557         restore %g0, 0x1, %l1
1558         rd      %psr, %l0
1559         sll     %l1, %l0, %l1
1560         wr      %l1, 0x0, %wim
1561         sethi   %hi(C_LABEL(current)), %l1
1562         ld      [%l1 + %lo(C_LABEL(current))], %l1
1563         and     %l0, 0x1f, %l0
1564         st      %l0, [%l1 + THREAD_WIM]
1565         save    %g0, %g0, %g0
1566         ldd     [%sp], %l0
1567         ldd     [%sp + 0x8], %l2
1568         ldd     [%sp + 0x10], %l4
1569         ldd     [%sp + 0x18], %l6
1570         ldd     [%sp + 0x20], %i0
1571         ldd     [%sp + 0x28], %i2
1572         ldd     [%sp + 0x30], %i4
1573         ldd     [%sp + 0x38], %i6
1574         save    %g0, %g0, %g0
1575         jmp     %l1
1576         rett    %l2
1577 
1578 /* Context switch code.  I don't feel like playing around with
1579  * inline gcc-assembly to do this right, so here it is.  The new
1580  * process's task_struct ptr is passed in %o0.
1581  *
1582  * This is still work in progress.
1583  * ONLY MAKE PROM CALLS FOR DIAGNOSTICS WHEN TRAPS ARE ON!!!!!
1584  *
1585  * First successful task switch 05/13/95 21:52:37
1586  *
1587  */
1588         .align 4
1589         .globl C_LABEL(sparc_switch_to)
1590 C_LABEL(sparc_switch_to):
1591         or      %g0, %o0, %l5
1592         sethi   %hi(C_LABEL(current)), %l6
1593         ld      [%l6 + %lo(C_LABEL(current))], %l6
1594         rd      %psr, %l0
1595 
1596         or      %g0, %l0, %l4
1597         andn    %l0, PSR_PIL, %l0   /* turn off IRQ level bits leave PSR_ET on */
1598 
1599         wr      %l0, 0xf00, %psr    /* NO interrupts */
1600         WRITE_PAUSE
1601 
1602         /* Save state of old process */
1603         .globl rnop7
1604         save    %sp, -C_STACK, %sp
1605         save    %sp, -C_STACK, %sp
1606         save    %sp, -C_STACK, %sp
1607         save    %sp, -C_STACK, %sp
1608         save    %sp, -C_STACK, %sp
1609 rnop7:  save    %sp, -C_STACK, %sp
1610         restore
1611         restore
1612         restore
1613         restore
1614         restore
1615         restore
1616 
1617         rd      %psr, %l3
1618         and     %l3, PSR_CWP, %l3               ! only care about CWP bits now
1619         andn    %l0, PSR_CWP, %l0               ! integrate with old %psr
1620         or      %l3, %l0, %l0
1621         
1622         st      %l0, [%sp + C_STACK + PT_PSR]   ! save new %psr
1623         /* ??? We backtrack the PC two instructions due to retl's semantics ??? */
1624         /*sub   %o7, 0x8, %o7 */
1625         st      %o7, [%sp + C_STACK + PT_PC]    ! save return PC
1626         add     %o7, 0x4, %l3
1627         st      %l3, [%sp + C_STACK + PT_NPC]   ! and NPC
1628 
1629         rd      %y, %l3
1630         st      %l3, [%sp + C_STACK + PT_Y]     ! save %y
1631 
1632         /* Save the %wim into %g0 slot, ensures that it sits behind CWP */
1633         rd      %wim, %l3
1634         st      %l3, [%sp + C_STACK + PT_G0]    ! save new %wim
1635         st      %g1, [%sp + C_STACK + PT_G1]
1636         std     %g2, [%sp + C_STACK + PT_G2]
1637         std     %g4, [%sp + C_STACK + PT_G4]
1638         std     %g6, [%sp + C_STACK + PT_G6]
1639         std     %i0, [%sp + C_STACK + PT_I0]
1640         std     %i2, [%sp + C_STACK + PT_I2]
1641         std     %i4, [%sp + C_STACK + PT_I4]
1642         std     %i6, [%sp + C_STACK + PT_I6]
1643 
1644         wr      %l0, (0xf20), %psr              ! no traps, no intrs
1645         WRITE_PAUSE
1646 
1647         /* TRAPS ARE OFF, NO PROM CALLS WHATSOEVER FOR DEBUGGING!!! */
1648         /* SO what we do is we put an imperical constant in %g2 and
1649          * a 'counter' in %g1 which we increment after every instruction
1650          * so we can figure out where the thing prom panics.  Then at the
1651          * prom prompt we print out the saved registers.  To drop into the
1652          * prom and look at the registers just execute 7 saves since that
1653          * will induce a window trap before the last one and traps are off,
1654          * thus a watchdog reset will occur.
1655          */
1656 
1657         /* Grrr, this is hairy... be careful, again NO PROM CALLS YET! */
1658         /* Load up the new 'current' */
1659         sethi   %hi(C_LABEL(current)), %g1
1660         st      %l5, [%g1 + %lo(C_LABEL(current))]
1661         
1662         /* Load up new processes stack, we always switch onto the kernel stack */
1663         /* Be CAREFUL, use globals for temporaries, because after we change the
1664          * %psr the window could change and you will most likely be accessing
1665          * different outs, ins, and locals than you origionally were.
1666          */
1667         or      %g0, %l5, %g6
1668         ld      [%l5 + THREAD_KSP], %g3
1669 
1670         /* New procs %psr */
1671         ld      [%g3 + C_STACK + PT_PSR], %g4
1672         wr      %g4, 0xf00, %psr         /* No ints, no traps */
1673         WRITE_PAUSE
1674 
1675         /* We could be in a different window NOW. Assume nothing about the
1676          * current set of in, out and local registers.
1677          */
1678 
1679         /* New procs %wim */
1680         ld      [%g3 + C_STACK + PT_G0], %l4 /* %wim is here */
1681         st      %l4, [%g6 + THREAD_WIM]      /* Update tss */
1682         wr      %l4, 0x0, %wim               /* Use it */
1683         WRITE_PAUSE
1684 
1685         /* Finally, load the stack */
1686         or      %g0, %g3, %sp
1687 
1688         /* We are now sane, we have a good stack and our state is reflected
1689          * properly in 'current'.  Let it rip.
1690          */
1691         /* Remember, you can't increase PIL and turn on traps at the
1692          * same time.
1693          */
1694         wr      %g4, 0xf00, %psr  /* Traps on, no interrupts. */
1695         wr      %g4, 0xf20, %psr
1696         WRITE_PAUSE
1697         
1698         sethi   %hi(C_LABEL(current)), %o0
1699         ld      [%o0 + %lo(C_LABEL(current))], %o0
1700         ld      [%o0 + THREAD_PC], %o7 /* Setup return address */
1701 
1702         /* cross fingers */
1703         retl
1704         nop
1705 
1706 /* The following two things point to window management tables. The first
1707  * one is used to quickly look up how many user windows there are from
1708  * trap-land. The second is used in a trap handler to determine if a rett
1709  * instruction will land us smack inside the invalid window that possibly
1710  * the trap was called to fix-up.
1711  */
1712 
1713 /* For now these are static tables geared for a 7 window sparc.
1714  * But in head.S after we calculate this table based upon the
1715  * nwindows value.  This table is big enough for a 16 window sparc.
1716  */
1717 
1718 
1719                 .data
1720                 .align 4
1721                 .globl lnx_winmask
1722 lnx_winmask:
1723                 .byte   2, 4, 8, 16, 32, 64, 1, 0
1724                 .byte   0, 0, 0, 0, 0, 0, 0, 0
1725         
1726                 .align 4
1727                 .globl C_LABEL(sys_call_table)
1728 C_LABEL(sys_call_table):
1729         .long C_LABEL(sys_setup)                /* 0 */
1730         .long C_LABEL(sys_exit)
1731         .long C_LABEL(sys_fork)
1732         .long C_LABEL(sys_read)
1733         .long C_LABEL(sys_write)
1734         .long C_LABEL(sys_open)                 /* 5 */
1735         .long C_LABEL(sys_close)
1736         .long C_LABEL(sys_waitpid)
1737         .long C_LABEL(sys_creat)
1738         .long C_LABEL(sys_link)
1739         .long C_LABEL(sys_unlink)               /* 10 */
1740         .long C_LABEL(sys_execve)
1741         .long C_LABEL(sys_chdir)
1742         .long C_LABEL(sys_time)
1743         .long C_LABEL(sys_mknod)
1744         .long C_LABEL(sys_chmod)                /* 15 */
1745         .long C_LABEL(sys_chown)
1746         .long C_LABEL(sys_break)
1747         .long C_LABEL(sys_stat)
1748         .long C_LABEL(sys_lseek)
1749         .long C_LABEL(sys_getpid)               /* 20 */
1750         .long C_LABEL(sys_mount)
1751         .long C_LABEL(sys_umount)
1752         .long C_LABEL(sys_setuid)
1753         .long C_LABEL(sys_getuid)
1754         .long C_LABEL(sys_stime)                /* 25 */
1755         .long C_LABEL(sys_ni_syscall)           /* this will be sys_ptrace() */
1756         .long C_LABEL(sys_alarm)
1757         .long C_LABEL(sys_fstat)
1758         .long C_LABEL(sys_pause)
1759         .long C_LABEL(sys_utime)                /* 30 */
1760         .long C_LABEL(sys_stty)
1761         .long C_LABEL(sys_gtty)
1762         .long C_LABEL(sys_access)
1763         .long C_LABEL(sys_nice)
1764         .long C_LABEL(sys_ftime)                /* 35 */
1765         .long C_LABEL(sys_sync)
1766         .long C_LABEL(sys_kill)
1767         .long C_LABEL(sys_rename)
1768         .long C_LABEL(sys_mkdir)
1769         .long C_LABEL(sys_rmdir)                /* 40 */
1770         .long C_LABEL(sys_dup)
1771         .long C_LABEL(sys_pipe)
1772         .long C_LABEL(sys_times)
1773         .long C_LABEL(sys_prof)
1774         .long C_LABEL(sys_brk)                  /* 45 */
1775         .long C_LABEL(sys_setgid)
1776         .long C_LABEL(sys_getgid)
1777         .long C_LABEL(sys_signal)
1778         .long C_LABEL(sys_geteuid)
1779         .long C_LABEL(sys_getegid)              /* 50 */
1780         .long C_LABEL(sys_acct)
1781         .long C_LABEL(sys_phys)
1782         .long C_LABEL(sys_lock)
1783         .long C_LABEL(sys_ioctl)
1784         .long C_LABEL(sys_fcntl)                /* 55 */
1785         .long C_LABEL(sys_mpx)
1786         .long C_LABEL(sys_setpgid)
1787         .long C_LABEL(sys_ulimit)
1788         .long C_LABEL(sys_olduname)
1789         .long C_LABEL(sys_umask)        /* 60 */
1790         .long C_LABEL(sys_chroot)
1791         .long C_LABEL(sys_ustat)
1792         .long C_LABEL(sys_dup2)
1793         .long C_LABEL(sys_getppid)
1794         .long C_LABEL(sys_getpgrp)              /* 65 */
1795         .long C_LABEL(sys_setsid)
1796         .long C_LABEL(sys_sigaction)
1797         .long C_LABEL(sys_sgetmask)
1798         .long C_LABEL(sys_ssetmask)
1799         .long C_LABEL(sys_setreuid)             /* 70 */
1800         .long C_LABEL(sys_setregid)
1801         .long C_LABEL(sys_sigsuspend)
1802         .long C_LABEL(sys_sigpending)
1803         .long C_LABEL(sys_sethostname)
1804         .long C_LABEL(sys_setrlimit)            /* 75 */
1805         .long C_LABEL(sys_getrlimit)
1806         .long C_LABEL(sys_getrusage)
1807         .long C_LABEL(sys_gettimeofday)
1808         .long C_LABEL(sys_settimeofday)
1809         .long C_LABEL(sys_getgroups)            /* 80 */
1810         .long C_LABEL(sys_setgroups)
1811         .long C_LABEL(sys_select)
1812         .long C_LABEL(sys_symlink)
1813         .long C_LABEL(sys_lstat)
1814         .long C_LABEL(sys_readlink)             /* 85 */
1815         .long C_LABEL(sys_uselib)
1816         .long C_LABEL(sys_swapon)
1817         .long C_LABEL(sys_reboot)
1818         .long C_LABEL(sys_readdir)
1819         .long C_LABEL(sys_mmap)                 /* 90 */
1820         .long C_LABEL(sys_munmap)
1821         .long C_LABEL(sys_truncate)
1822         .long C_LABEL(sys_ftruncate)
1823         .long C_LABEL(sys_fchmod)
1824         .long C_LABEL(sys_fchown)               /* 95 */
1825         .long C_LABEL(sys_getpriority)
1826         .long C_LABEL(sys_setpriority)
1827         .long C_LABEL(sys_profil)
1828         .long C_LABEL(sys_statfs)
1829         .long C_LABEL(sys_fstatfs)              /* 100 */
1830         .long C_LABEL(sys_ni_syscall)
1831         .long C_LABEL(sys_socketcall)
1832         .long C_LABEL(sys_syslog)
1833         .long C_LABEL(sys_setitimer)
1834         .long C_LABEL(sys_getitimer)            /* 105 */
1835         .long C_LABEL(sys_newstat)
1836         .long C_LABEL(sys_newlstat)
1837         .long C_LABEL(sys_newfstat)
1838         .long C_LABEL(sys_uname)
1839         .long C_LABEL(sys_ni_syscall)           /* 110 */
1840         .long C_LABEL(sys_vhangup)
1841         .long C_LABEL(sys_idle)
1842         .long C_LABEL(sys_ni_syscall)           /* was vm86, meaningless on Sparc */
1843         .long C_LABEL(sys_wait4)
1844         .long C_LABEL(sys_swapoff)              /* 115 */
1845         .long C_LABEL(sys_sysinfo)
1846         .long C_LABEL(sys_ipc)
1847         .long C_LABEL(sys_fsync)
1848         .long C_LABEL(sys_sigreturn)
1849         .long C_LABEL(sys_ni_syscall)           /* 120 */
1850         .long C_LABEL(sys_setdomainname)
1851         .long C_LABEL(sys_newuname)
1852         .long C_LABEL(sys_ni_syscall)
1853         .long C_LABEL(sys_adjtimex)
1854         .long C_LABEL(sys_mprotect)             /* 125 */
1855         .long C_LABEL(sys_sigprocmask)
1856         .long C_LABEL(sys_create_module)
1857         .long C_LABEL(sys_init_module)
1858         .long C_LABEL(sys_delete_module)
1859         .long C_LABEL(sys_get_kernel_syms)      /* 130 */
1860         .long C_LABEL(sys_ni_syscall)
1861         .long C_LABEL(sys_getpgid)
1862         .long C_LABEL(sys_fchdir)
1863         .long C_LABEL(sys_bdflush)
1864         .long C_LABEL(sys_sysfs)                /* 135 */
1865         .long C_LABEL(sys_personality)
1866         .long C_LABEL(sys_ni_syscall)           /* for afs_syscall */
1867         .long C_LABEL(sys_setfsuid)
1868         .long C_LABEL(sys_setfsgid)
1869         .long C_LABEL(sys_llseek)               /* 140 */
1870         .long C_LABEL(sys_ni_syscall)
1871         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1872         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1873         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1874         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1875 
1876         /* 150 */
1877         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1878         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1879         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1880         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1881         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1882 
1883         /* 160 */
1884         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1885         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1886         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1887         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1888         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1889 
1890         /* 170 */
1891         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1892         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1893         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1894         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1895         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1896 
1897         /* 180 */
1898         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1899         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1900         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1901         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1902         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1903 
1904         /* 190 */
1905         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1906         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1907         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1908         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1909         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1910 
1911         /* 200 */
1912         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1913         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1914         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1915         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1916         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1917 
1918         /* 210 */
1919         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1920         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1921         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1922         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1923         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1924 
1925         /* 220 */
1926         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1927         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1928         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1929         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1930         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1931 
1932         /* 230 */
1933         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1934         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1935         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1936         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1937         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1938 
1939         /* 240 */
1940         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1941         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1942         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1943         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1944         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1945 
1946         /* 250 */
1947         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1948         .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall)
1949         .long C_LABEL(sys_ni_syscall)           /* 255 */
1950         .align 4

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