linux/arch/sparc/kernel/entry.S
<<
>>
Prefs
   1/* arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
   2 *
   3 * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
   4 * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
   5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
   6 * Copyright (C) 1996-1999 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
   7 * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
   8 */
   9
  10#include <linux/errno.h>
  11
  12#include <asm/head.h>
  13#include <asm/asi.h>
  14#include <asm/smp.h>
  15#include <asm/contregs.h>
  16#include <asm/ptrace.h>
  17#include <asm/asm-offsets.h>
  18#include <asm/psr.h>
  19#include <asm/vaddrs.h>
  20#include <asm/memreg.h>
  21#include <asm/page.h>
  22#include <asm/pgtable.h>
  23#include <asm/pgtsun4c.h>
  24#include <asm/winmacro.h>
  25#include <asm/signal.h>
  26#include <asm/obio.h>
  27#include <asm/mxcc.h>
  28#include <asm/thread_info.h>
  29#include <asm/param.h>
  30#include <asm/unistd.h>
  31
  32#include <asm/asmmacro.h>
  33
  34#define curptr      g6
  35
  36/* These are just handy. */
  37#define _SV     save    %sp, -STACKFRAME_SZ, %sp
  38#define _RS     restore 
  39
  40#define FLUSH_ALL_KERNEL_WINDOWS \
  41        _SV; _SV; _SV; _SV; _SV; _SV; _SV; \
  42        _RS; _RS; _RS; _RS; _RS; _RS; _RS;
  43
  44        .text
  45
  46#ifdef CONFIG_KGDB
  47        .align  4
  48        .globl          arch_kgdb_breakpoint
  49        .type           arch_kgdb_breakpoint,#function
  50arch_kgdb_breakpoint:
  51        ta              0x7d
  52        retl
  53         nop
  54        .size           arch_kgdb_breakpoint,.-arch_kgdb_breakpoint
  55#endif
  56
  57#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
  58        .align  4
  59        .globl  floppy_hardint
  60floppy_hardint:
  61        /*
  62         * This code cannot touch registers %l0 %l1 and %l2
  63         * because SAVE_ALL depends on their values. It depends
  64         * on %l3 also, but we regenerate it before a call.
  65         * Other registers are:
  66         * %l3 -- base address of fdc registers
  67         * %l4 -- pdma_vaddr
  68         * %l5 -- scratch for ld/st address
  69         * %l6 -- pdma_size
  70         * %l7 -- scratch [floppy byte, ld/st address, aux. data]
  71         */
  72
  73        /* Do we have work to do? */
  74        sethi   %hi(doing_pdma), %l7
  75        ld      [%l7 + %lo(doing_pdma)], %l7
  76        cmp     %l7, 0
  77        be      floppy_dosoftint
  78         nop
  79
  80        /* Load fdc register base */
  81        sethi   %hi(fdc_status), %l3
  82        ld      [%l3 + %lo(fdc_status)], %l3
  83
  84        /* Setup register addresses */
  85        sethi   %hi(pdma_vaddr), %l5    ! transfer buffer
  86        ld      [%l5 + %lo(pdma_vaddr)], %l4
  87        sethi   %hi(pdma_size), %l5     ! bytes to go
  88        ld      [%l5 + %lo(pdma_size)], %l6
  89next_byte:
  90        ldub    [%l3], %l7
  91
  92        andcc   %l7, 0x80, %g0          ! Does fifo still have data
  93        bz      floppy_fifo_emptied     ! fifo has been emptied...
  94         andcc  %l7, 0x20, %g0          ! in non-dma mode still?
  95        bz      floppy_overrun          ! nope, overrun
  96         andcc  %l7, 0x40, %g0          ! 0=write 1=read
  97        bz      floppy_write
  98         sub    %l6, 0x1, %l6
  99
 100        /* Ok, actually read this byte */
 101        ldub    [%l3 + 1], %l7
 102        orcc    %g0, %l6, %g0
 103        stb     %l7, [%l4]
 104        bne     next_byte
 105         add    %l4, 0x1, %l4
 106
 107        b       floppy_tdone
 108         nop
 109
 110floppy_write:
 111        /* Ok, actually write this byte */
 112        ldub    [%l4], %l7
 113        orcc    %g0, %l6, %g0
 114        stb     %l7, [%l3 + 1]
 115        bne     next_byte
 116         add    %l4, 0x1, %l4
 117
 118        /* fall through... */
 119floppy_tdone:
 120        sethi   %hi(pdma_vaddr), %l5
 121        st      %l4, [%l5 + %lo(pdma_vaddr)]
 122        sethi   %hi(pdma_size), %l5
 123        st      %l6, [%l5 + %lo(pdma_size)]
 124        /* Flip terminal count pin */
 125        set     auxio_register, %l7
 126        ld      [%l7], %l7
 127
 128        set     sparc_cpu_model, %l5
 129        ld      [%l5], %l5
 130        subcc   %l5, 1, %g0             /* enum { sun4c = 1 }; */
 131        be      1f
 132         ldub   [%l7], %l5
 133
 134        or      %l5, 0xc2, %l5
 135        stb     %l5, [%l7]
 136        andn    %l5, 0x02, %l5
 137        b       2f
 138         nop
 139
 1401:
 141        or      %l5, 0xf4, %l5
 142        stb     %l5, [%l7]
 143        andn    %l5, 0x04, %l5
 144
 1452:
 146        /* Kill some time so the bits set */
 147        WRITE_PAUSE
 148        WRITE_PAUSE
 149
 150        stb     %l5, [%l7]
 151
 152        /* Prevent recursion */
 153        sethi   %hi(doing_pdma), %l7
 154        b       floppy_dosoftint
 155         st     %g0, [%l7 + %lo(doing_pdma)]
 156
 157        /* We emptied the FIFO, but we haven't read everything
 158         * as of yet.  Store the current transfer address and
 159         * bytes left to read so we can continue when the next
 160         * fast IRQ comes in.
 161         */
 162floppy_fifo_emptied:
 163        sethi   %hi(pdma_vaddr), %l5
 164        st      %l4, [%l5 + %lo(pdma_vaddr)]
 165        sethi   %hi(pdma_size), %l7
 166        st      %l6, [%l7 + %lo(pdma_size)]
 167
 168        /* Restore condition codes */
 169        wr      %l0, 0x0, %psr
 170        WRITE_PAUSE
 171
 172        jmp     %l1
 173        rett    %l2
 174
 175floppy_overrun:
 176        sethi   %hi(pdma_vaddr), %l5
 177        st      %l4, [%l5 + %lo(pdma_vaddr)]
 178        sethi   %hi(pdma_size), %l5
 179        st      %l6, [%l5 + %lo(pdma_size)]
 180        /* Prevent recursion */
 181        sethi   %hi(doing_pdma), %l7
 182        st      %g0, [%l7 + %lo(doing_pdma)]
 183
 184        /* fall through... */
 185floppy_dosoftint:
 186        rd      %wim, %l3
 187        SAVE_ALL
 188
 189        /* Set all IRQs off. */
 190        or      %l0, PSR_PIL, %l4
 191        wr      %l4, 0x0, %psr
 192        WRITE_PAUSE
 193        wr      %l4, PSR_ET, %psr
 194        WRITE_PAUSE
 195
 196        mov     11, %o0                 ! floppy irq level (unused anyway)
 197        mov     %g0, %o1                ! devid is not used in fast interrupts
 198        call    sparc_floppy_irq
 199         add    %sp, STACKFRAME_SZ, %o2 ! struct pt_regs *regs
 200
 201        RESTORE_ALL
 202        
 203#endif /* (CONFIG_BLK_DEV_FD) */
 204
 205        /* Bad trap handler */
 206        .globl  bad_trap_handler
 207bad_trap_handler:
 208        SAVE_ALL
 209
 210        wr      %l0, PSR_ET, %psr
 211        WRITE_PAUSE
 212
 213        add     %sp, STACKFRAME_SZ, %o0 ! pt_regs
 214        call    do_hw_interrupt
 215         mov    %l7, %o1                ! trap number
 216
 217        RESTORE_ALL
 218        
 219/* For now all IRQ's not registered get sent here. handler_irq() will
 220 * see if a routine is registered to handle this interrupt and if not
 221 * it will say so on the console.
 222 */
 223
 224        .align  4
 225        .globl  real_irq_entry, patch_handler_irq
 226real_irq_entry:
 227        SAVE_ALL
 228
 229#ifdef CONFIG_SMP
 230        .globl  patchme_maybe_smp_msg
 231
 232        cmp     %l7, 12
 233patchme_maybe_smp_msg:
 234        bgu     maybe_smp4m_msg
 235         nop
 236#endif
 237
 238real_irq_continue:
 239        or      %l0, PSR_PIL, %g2
 240        wr      %g2, 0x0, %psr
 241        WRITE_PAUSE
 242        wr      %g2, PSR_ET, %psr
 243        WRITE_PAUSE
 244        mov     %l7, %o0                ! irq level
 245patch_handler_irq:
 246        call    handler_irq
 247         add    %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr
 248        or      %l0, PSR_PIL, %g2       ! restore PIL after handler_irq
 249        wr      %g2, PSR_ET, %psr       ! keep ET up
 250        WRITE_PAUSE
 251
 252        RESTORE_ALL
 253
 254#ifdef CONFIG_SMP
 255        /* SMP per-cpu ticker interrupts are handled specially. */
 256smp4m_ticker:
 257        bne     real_irq_continue+4
 258         or     %l0, PSR_PIL, %g2
 259        wr      %g2, 0x0, %psr
 260        WRITE_PAUSE
 261        wr      %g2, PSR_ET, %psr
 262        WRITE_PAUSE
 263        call    smp4m_percpu_timer_interrupt
 264         add    %sp, STACKFRAME_SZ, %o0
 265        wr      %l0, PSR_ET, %psr
 266        WRITE_PAUSE
 267        RESTORE_ALL
 268
 269        /* Here is where we check for possible SMP IPI passed to us
 270         * on some level other than 15 which is the NMI and only used
 271         * for cross calls.  That has a separate entry point below.
 272         */
 273maybe_smp4m_msg:
 274        GET_PROCESSOR4M_ID(o3)
 275        sethi   %hi(sun4m_irq_percpu), %l5
 276        sll     %o3, 2, %o3
 277        or      %l5, %lo(sun4m_irq_percpu), %o5
 278        sethi   %hi(0x40000000), %o2
 279        ld      [%o5 + %o3], %o1
 280        ld      [%o1 + 0x00], %o3       ! sun4m_irq_percpu[cpu]->pending
 281        andcc   %o3, %o2, %g0
 282        be,a    smp4m_ticker
 283         cmp    %l7, 14
 284        st      %o2, [%o1 + 0x04]       ! sun4m_irq_percpu[cpu]->clear=0x40000000
 285        WRITE_PAUSE
 286        ld      [%o1 + 0x00], %g0       ! sun4m_irq_percpu[cpu]->pending
 287        WRITE_PAUSE
 288        or      %l0, PSR_PIL, %l4
 289        wr      %l4, 0x0, %psr
 290        WRITE_PAUSE
 291        wr      %l4, PSR_ET, %psr
 292        WRITE_PAUSE
 293        call    smp_reschedule_irq
 294         nop
 295
 296        RESTORE_ALL
 297
 298        .align  4
 299        .globl  linux_trap_ipi15_sun4m
 300linux_trap_ipi15_sun4m:
 301        SAVE_ALL
 302        sethi   %hi(0x80000000), %o2
 303        GET_PROCESSOR4M_ID(o0)
 304        sethi   %hi(sun4m_irq_percpu), %l5
 305        or      %l5, %lo(sun4m_irq_percpu), %o5
 306        sll     %o0, 2, %o0
 307        ld      [%o5 + %o0], %o5
 308        ld      [%o5 + 0x00], %o3       ! sun4m_irq_percpu[cpu]->pending
 309        andcc   %o3, %o2, %g0
 310        be      1f                      ! Must be an NMI async memory error
 311         st     %o2, [%o5 + 0x04]       ! sun4m_irq_percpu[cpu]->clear=0x80000000
 312        WRITE_PAUSE
 313        ld      [%o5 + 0x00], %g0       ! sun4m_irq_percpu[cpu]->pending
 314        WRITE_PAUSE
 315        or      %l0, PSR_PIL, %l4
 316        wr      %l4, 0x0, %psr
 317        WRITE_PAUSE
 318        wr      %l4, PSR_ET, %psr
 319        WRITE_PAUSE
 320        call    smp4m_cross_call_irq
 321         nop
 322        b       ret_trap_lockless_ipi
 323         clr    %l6
 3241:
 325        /* NMI async memory error handling. */
 326        sethi   %hi(0x80000000), %l4
 327        sethi   %hi(sun4m_irq_global), %o5
 328        ld      [%o5 + %lo(sun4m_irq_global)], %l5
 329        st      %l4, [%l5 + 0x0c]       ! sun4m_irq_global->mask_set=0x80000000
 330        WRITE_PAUSE
 331        ld      [%l5 + 0x00], %g0       ! sun4m_irq_global->pending
 332        WRITE_PAUSE
 333        or      %l0, PSR_PIL, %l4
 334        wr      %l4, 0x0, %psr
 335        WRITE_PAUSE
 336        wr      %l4, PSR_ET, %psr
 337        WRITE_PAUSE
 338        call    sun4m_nmi
 339         nop
 340        st      %l4, [%l5 + 0x08]       ! sun4m_irq_global->mask_clear=0x80000000
 341        WRITE_PAUSE
 342        ld      [%l5 + 0x00], %g0       ! sun4m_irq_global->pending
 343        WRITE_PAUSE
 344        RESTORE_ALL
 345
 346        .globl  smp4d_ticker
 347        /* SMP per-cpu ticker interrupts are handled specially. */
 348smp4d_ticker:
 349        SAVE_ALL
 350        or      %l0, PSR_PIL, %g2
 351        sethi   %hi(CC_ICLR), %o0
 352        sethi   %hi(1 << 14), %o1
 353        or      %o0, %lo(CC_ICLR), %o0
 354        stha    %o1, [%o0] ASI_M_MXCC   /* Clear PIL 14 in MXCC's ICLR */
 355        wr      %g2, 0x0, %psr
 356        WRITE_PAUSE
 357        wr      %g2, PSR_ET, %psr
 358        WRITE_PAUSE
 359        call    smp4d_percpu_timer_interrupt
 360         add    %sp, STACKFRAME_SZ, %o0
 361        wr      %l0, PSR_ET, %psr
 362        WRITE_PAUSE
 363        RESTORE_ALL
 364
 365        .align  4
 366        .globl  linux_trap_ipi15_sun4d
 367linux_trap_ipi15_sun4d:
 368        SAVE_ALL
 369        sethi   %hi(CC_BASE), %o4
 370        sethi   %hi(MXCC_ERR_ME|MXCC_ERR_PEW|MXCC_ERR_ASE|MXCC_ERR_PEE), %o2
 371        or      %o4, (CC_EREG - CC_BASE), %o0
 372        ldda    [%o0] ASI_M_MXCC, %o0
 373        andcc   %o0, %o2, %g0
 374        bne     1f
 375         sethi  %hi(BB_STAT2), %o2
 376        lduba   [%o2] ASI_M_CTL, %o2
 377        andcc   %o2, BB_STAT2_MASK, %g0
 378        bne     2f
 379         or     %o4, (CC_ICLR - CC_BASE), %o0
 380        sethi   %hi(1 << 15), %o1
 381        stha    %o1, [%o0] ASI_M_MXCC   /* Clear PIL 15 in MXCC's ICLR */
 382        or      %l0, PSR_PIL, %l4
 383        wr      %l4, 0x0, %psr
 384        WRITE_PAUSE
 385        wr      %l4, PSR_ET, %psr
 386        WRITE_PAUSE
 387        call    smp4d_cross_call_irq
 388         nop
 389        b       ret_trap_lockless_ipi
 390         clr    %l6
 391
 3921:      /* MXCC error */
 3932:      /* BB error */
 394        /* Disable PIL 15 */
 395        set     CC_IMSK, %l4
 396        lduha   [%l4] ASI_M_MXCC, %l5
 397        sethi   %hi(1 << 15), %l7
 398        or      %l5, %l7, %l5
 399        stha    %l5, [%l4] ASI_M_MXCC
 400        /* FIXME */
 4011:      b,a     1b
 402
 403#endif /* CONFIG_SMP */
 404
 405        /* This routine handles illegal instructions and privileged
 406         * instruction attempts from user code.
 407         */
 408        .align  4
 409        .globl  bad_instruction
 410bad_instruction:
 411        sethi   %hi(0xc1f80000), %l4
 412        ld      [%l1], %l5
 413        sethi   %hi(0x81d80000), %l7
 414        and     %l5, %l4, %l5
 415        cmp     %l5, %l7
 416        be      1f
 417        SAVE_ALL
 418
 419        wr      %l0, PSR_ET, %psr               ! re-enable traps
 420        WRITE_PAUSE
 421
 422        add     %sp, STACKFRAME_SZ, %o0
 423        mov     %l1, %o1
 424        mov     %l2, %o2
 425        call    do_illegal_instruction
 426         mov    %l0, %o3
 427
 428        RESTORE_ALL
 429
 4301:      /* unimplemented flush - just skip */
 431        jmpl    %l2, %g0
 432         rett   %l2 + 4
 433
 434        .align  4
 435        .globl  priv_instruction
 436priv_instruction:
 437        SAVE_ALL
 438
 439        wr      %l0, PSR_ET, %psr
 440        WRITE_PAUSE
 441
 442        add     %sp, STACKFRAME_SZ, %o0
 443        mov     %l1, %o1
 444        mov     %l2, %o2
 445        call    do_priv_instruction
 446         mov    %l0, %o3
 447
 448        RESTORE_ALL
 449
 450        /* This routine handles unaligned data accesses. */
 451        .align  4
 452        .globl  mna_handler
 453mna_handler:
 454        andcc   %l0, PSR_PS, %g0
 455        be      mna_fromuser
 456         nop
 457
 458        SAVE_ALL
 459
 460        wr      %l0, PSR_ET, %psr
 461        WRITE_PAUSE
 462
 463        ld      [%l1], %o1
 464        call    kernel_unaligned_trap
 465         add    %sp, STACKFRAME_SZ, %o0
 466
 467        RESTORE_ALL
 468
 469mna_fromuser:
 470        SAVE_ALL
 471
 472        wr      %l0, PSR_ET, %psr               ! re-enable traps
 473        WRITE_PAUSE
 474
 475        ld      [%l1], %o1
 476        call    user_unaligned_trap
 477         add    %sp, STACKFRAME_SZ, %o0
 478
 479        RESTORE_ALL
 480
 481        /* This routine handles floating point disabled traps. */
 482        .align  4
 483        .globl  fpd_trap_handler
 484fpd_trap_handler:
 485        SAVE_ALL
 486
 487        wr      %l0, PSR_ET, %psr               ! re-enable traps
 488        WRITE_PAUSE
 489
 490        add     %sp, STACKFRAME_SZ, %o0
 491        mov     %l1, %o1
 492        mov     %l2, %o2
 493        call    do_fpd_trap
 494         mov    %l0, %o3
 495
 496        RESTORE_ALL
 497
 498        /* This routine handles Floating Point Exceptions. */
 499        .align  4
 500        .globl  fpe_trap_handler
 501fpe_trap_handler:
 502        set     fpsave_magic, %l5
 503        cmp     %l1, %l5
 504        be      1f
 505         sethi  %hi(fpsave), %l5
 506        or      %l5, %lo(fpsave), %l5
 507        cmp     %l1, %l5
 508        bne     2f
 509         sethi  %hi(fpsave_catch2), %l5
 510        or      %l5, %lo(fpsave_catch2), %l5
 511        wr      %l0, 0x0, %psr
 512        WRITE_PAUSE
 513        jmp     %l5
 514         rett   %l5 + 4
 5151:      
 516        sethi   %hi(fpsave_catch), %l5
 517        or      %l5, %lo(fpsave_catch), %l5
 518        wr      %l0, 0x0, %psr
 519        WRITE_PAUSE
 520        jmp     %l5
 521         rett   %l5 + 4
 522
 5232:
 524        SAVE_ALL
 525
 526        wr      %l0, PSR_ET, %psr               ! re-enable traps
 527        WRITE_PAUSE
 528
 529        add     %sp, STACKFRAME_SZ, %o0
 530        mov     %l1, %o1
 531        mov     %l2, %o2
 532        call    do_fpe_trap
 533         mov    %l0, %o3
 534
 535        RESTORE_ALL
 536
 537        /* This routine handles Tag Overflow Exceptions. */
 538        .align  4
 539        .globl  do_tag_overflow
 540do_tag_overflow:
 541        SAVE_ALL
 542
 543        wr      %l0, PSR_ET, %psr               ! re-enable traps
 544        WRITE_PAUSE
 545
 546        add     %sp, STACKFRAME_SZ, %o0
 547        mov     %l1, %o1
 548        mov     %l2, %o2
 549        call    handle_tag_overflow
 550         mov    %l0, %o3
 551
 552        RESTORE_ALL
 553
 554        /* This routine handles Watchpoint Exceptions. */
 555        .align  4
 556        .globl  do_watchpoint
 557do_watchpoint:
 558        SAVE_ALL
 559
 560        wr      %l0, PSR_ET, %psr               ! re-enable traps
 561        WRITE_PAUSE
 562
 563        add     %sp, STACKFRAME_SZ, %o0
 564        mov     %l1, %o1
 565        mov     %l2, %o2
 566        call    handle_watchpoint
 567         mov    %l0, %o3
 568
 569        RESTORE_ALL
 570
 571        /* This routine handles Register Access Exceptions. */
 572        .align  4
 573        .globl  do_reg_access
 574do_reg_access:
 575        SAVE_ALL
 576
 577        wr      %l0, PSR_ET, %psr               ! re-enable traps
 578        WRITE_PAUSE
 579
 580        add     %sp, STACKFRAME_SZ, %o0
 581        mov     %l1, %o1
 582        mov     %l2, %o2
 583        call    handle_reg_access
 584         mov    %l0, %o3
 585
 586        RESTORE_ALL
 587
 588        /* This routine handles Co-Processor Disabled Exceptions. */
 589        .align  4
 590        .globl  do_cp_disabled
 591do_cp_disabled:
 592        SAVE_ALL
 593
 594        wr      %l0, PSR_ET, %psr               ! re-enable traps
 595        WRITE_PAUSE
 596
 597        add     %sp, STACKFRAME_SZ, %o0
 598        mov     %l1, %o1
 599        mov     %l2, %o2
 600        call    handle_cp_disabled
 601         mov    %l0, %o3
 602
 603        RESTORE_ALL
 604
 605        /* This routine handles Co-Processor Exceptions. */
 606        .align  4
 607        .globl  do_cp_exception
 608do_cp_exception:
 609        SAVE_ALL
 610
 611        wr      %l0, PSR_ET, %psr               ! re-enable traps
 612        WRITE_PAUSE
 613
 614        add     %sp, STACKFRAME_SZ, %o0
 615        mov     %l1, %o1
 616        mov     %l2, %o2
 617        call    handle_cp_exception
 618         mov    %l0, %o3
 619
 620        RESTORE_ALL
 621
 622        /* This routine handles Hardware Divide By Zero Exceptions. */
 623        .align  4
 624        .globl  do_hw_divzero
 625do_hw_divzero:
 626        SAVE_ALL
 627
 628        wr      %l0, PSR_ET, %psr               ! re-enable traps
 629        WRITE_PAUSE
 630
 631        add     %sp, STACKFRAME_SZ, %o0
 632        mov     %l1, %o1
 633        mov     %l2, %o2
 634        call    handle_hw_divzero
 635         mov    %l0, %o3
 636
 637        RESTORE_ALL
 638
 639        .align  4
 640        .globl  do_flush_windows
 641do_flush_windows:
 642        SAVE_ALL
 643
 644        wr      %l0, PSR_ET, %psr
 645        WRITE_PAUSE
 646
 647        andcc   %l0, PSR_PS, %g0
 648        bne     dfw_kernel
 649         nop
 650
 651        call    flush_user_windows
 652         nop
 653
 654        /* Advance over the trap instruction. */
 655        ld      [%sp + STACKFRAME_SZ + PT_NPC], %l1
 656        add     %l1, 0x4, %l2
 657        st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
 658        st      %l2, [%sp + STACKFRAME_SZ + PT_NPC]
 659
 660        RESTORE_ALL
 661
 662        .globl  flush_patch_one
 663
 664        /* We get these for debugging routines using __builtin_return_address() */
 665dfw_kernel:
 666flush_patch_one:
 667        FLUSH_ALL_KERNEL_WINDOWS
 668
 669        /* Advance over the trap instruction. */
 670        ld      [%sp + STACKFRAME_SZ + PT_NPC], %l1
 671        add     %l1, 0x4, %l2
 672        st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
 673        st      %l2, [%sp + STACKFRAME_SZ + PT_NPC]
 674
 675        RESTORE_ALL
 676
 677        /* The getcc software trap.  The user wants the condition codes from
 678         * the %psr in register %g1.
 679         */
 680
 681        .align  4
 682        .globl  getcc_trap_handler
 683getcc_trap_handler:
 684        srl     %l0, 20, %g1    ! give user
 685        and     %g1, 0xf, %g1   ! only ICC bits in %psr
 686        jmp     %l2             ! advance over trap instruction
 687        rett    %l2 + 0x4       ! like this...
 688
 689        /* The setcc software trap.  The user has condition codes in %g1
 690         * that it would like placed in the %psr.  Be careful not to flip
 691         * any unintentional bits!
 692         */
 693
 694        .align  4
 695        .globl  setcc_trap_handler
 696setcc_trap_handler:
 697        sll     %g1, 0x14, %l4
 698        set     PSR_ICC, %l5
 699        andn    %l0, %l5, %l0   ! clear ICC bits in %psr
 700        and     %l4, %l5, %l4   ! clear non-ICC bits in user value
 701        or      %l4, %l0, %l4   ! or them in... mix mix mix
 702
 703        wr      %l4, 0x0, %psr  ! set new %psr
 704        WRITE_PAUSE             ! TI scumbags...
 705
 706        jmp     %l2             ! advance over trap instruction
 707        rett    %l2 + 0x4       ! like this...
 708
 709        .align  4
 710        .globl  linux_trap_nmi_sun4c
 711linux_trap_nmi_sun4c:
 712        SAVE_ALL
 713
 714        /* Ugh, we need to clear the IRQ line.  This is now
 715         * a very sun4c specific trap handler...
 716         */
 717        sethi   %hi(interrupt_enable), %l5
 718        ld      [%l5 + %lo(interrupt_enable)], %l5
 719        ldub    [%l5], %l6
 720        andn    %l6, INTS_ENAB, %l6
 721        stb     %l6, [%l5]
 722
 723        /* Now it is safe to re-enable traps without recursion. */
 724        or      %l0, PSR_PIL, %l0
 725        wr      %l0, PSR_ET, %psr
 726        WRITE_PAUSE
 727
 728        /* Now call the c-code with the pt_regs frame ptr and the
 729         * memory error registers as arguments.  The ordering chosen
 730         * here is due to unlatching semantics.
 731         */
 732        sethi   %hi(AC_SYNC_ERR), %o0
 733        add     %o0, 0x4, %o0
 734        lda     [%o0] ASI_CONTROL, %o2  ! sync vaddr
 735        sub     %o0, 0x4, %o0
 736        lda     [%o0] ASI_CONTROL, %o1  ! sync error
 737        add     %o0, 0xc, %o0
 738        lda     [%o0] ASI_CONTROL, %o4  ! async vaddr
 739        sub     %o0, 0x4, %o0
 740        lda     [%o0] ASI_CONTROL, %o3  ! async error
 741        call    sparc_lvl15_nmi
 742         add    %sp, STACKFRAME_SZ, %o0
 743
 744        RESTORE_ALL
 745
 746        .align  4
 747        .globl  invalid_segment_patch1_ff
 748        .globl  invalid_segment_patch2_ff
 749invalid_segment_patch1_ff:      cmp     %l4, 0xff
 750invalid_segment_patch2_ff:      mov     0xff, %l3
 751
 752        .align  4
 753        .globl  invalid_segment_patch1_1ff
 754        .globl  invalid_segment_patch2_1ff
 755invalid_segment_patch1_1ff:     cmp     %l4, 0x1ff
 756invalid_segment_patch2_1ff:     mov     0x1ff, %l3
 757
 758        .align  4
 759        .globl  num_context_patch1_16, num_context_patch2_16
 760num_context_patch1_16:          mov     0x10, %l7
 761num_context_patch2_16:          mov     0x10, %l7
 762
 763        .align  4
 764        .globl  vac_linesize_patch_32
 765vac_linesize_patch_32:          subcc   %l7, 32, %l7
 766
 767        .align  4
 768        .globl  vac_hwflush_patch1_on, vac_hwflush_patch2_on
 769
 770/*
 771 * Ugly, but we cant use hardware flushing on the sun4 and we'd require
 772 * two instructions (Anton)
 773 */
 774vac_hwflush_patch1_on:          addcc   %l7, -PAGE_SIZE, %l7
 775
 776vac_hwflush_patch2_on:          sta     %g0, [%l3 + %l7] ASI_HWFLUSHSEG
 777
 778        .globl  invalid_segment_patch1, invalid_segment_patch2
 779        .globl  num_context_patch1
 780        .globl  vac_linesize_patch, vac_hwflush_patch1
 781        .globl  vac_hwflush_patch2
 782
 783        .align  4
 784        .globl  sun4c_fault
 785
 786! %l0 = %psr
 787! %l1 = %pc
 788! %l2 = %npc
 789! %l3 = %wim
 790! %l7 = 1 for textfault
 791! We want error in %l5, vaddr in %l6
 792sun4c_fault:
 793        sethi   %hi(AC_SYNC_ERR), %l4
 794        add     %l4, 0x4, %l6                   ! AC_SYNC_VA in %l6
 795        lda     [%l6] ASI_CONTROL, %l5          ! Address
 796        lda     [%l4] ASI_CONTROL, %l6          ! Error, retained for a bit
 797
 798        andn    %l5, 0xfff, %l5                 ! Encode all info into l7
 799        srl     %l6, 14, %l4
 800
 801        and     %l4, 2, %l4
 802        or      %l5, %l4, %l4
 803
 804        or      %l4, %l7, %l7                   ! l7 = [addr,write,txtfault]
 805
 806        andcc   %l0, PSR_PS, %g0
 807        be      sun4c_fault_fromuser
 808         andcc  %l7, 1, %g0                     ! Text fault?
 809
 810        be      1f
 811         sethi  %hi(KERNBASE), %l4
 812
 813        mov     %l1, %l5                        ! PC
 814
 8151:
 816        cmp     %l5, %l4
 817        blu     sun4c_fault_fromuser
 818         sethi  %hi(~((1 << SUN4C_REAL_PGDIR_SHIFT) - 1)), %l4
 819
 820        /* If the kernel references a bum kernel pointer, or a pte which
 821         * points to a non existant page in ram, we will run this code
 822         * _forever_ and lock up the machine!!!!! So we must check for
 823         * this condition, the AC_SYNC_ERR bits are what we must examine.
 824         * Also a parity error would make this happen as well.  So we just
 825         * check that we are in fact servicing a tlb miss and not some
 826         * other type of fault for the kernel.
 827         */
 828        andcc   %l6, 0x80, %g0
 829        be      sun4c_fault_fromuser
 830         and    %l5, %l4, %l5
 831
 832        /* Test for NULL pte_t * in vmalloc area. */
 833        sethi   %hi(VMALLOC_START), %l4
 834        cmp     %l5, %l4
 835        blu,a   invalid_segment_patch1
 836         lduXa  [%l5] ASI_SEGMAP, %l4
 837
 838        sethi   %hi(swapper_pg_dir), %l4
 839        srl     %l5, SUN4C_PGDIR_SHIFT, %l6
 840        or      %l4, %lo(swapper_pg_dir), %l4
 841        sll     %l6, 2, %l6
 842        ld      [%l4 + %l6], %l4
 843        andcc   %l4, PAGE_MASK, %g0
 844        be      sun4c_fault_fromuser
 845         lduXa  [%l5] ASI_SEGMAP, %l4
 846
 847invalid_segment_patch1:
 848        cmp     %l4, 0x7f
 849        bne     1f
 850         sethi  %hi(sun4c_kfree_ring), %l4
 851        or      %l4, %lo(sun4c_kfree_ring), %l4
 852        ld      [%l4 + 0x18], %l3
 853        deccc   %l3                     ! do we have a free entry?
 854        bcs,a   2f                      ! no, unmap one.
 855         sethi  %hi(sun4c_kernel_ring), %l4
 856
 857        st      %l3, [%l4 + 0x18]       ! sun4c_kfree_ring.num_entries--
 858
 859        ld      [%l4 + 0x00], %l6       ! entry = sun4c_kfree_ring.ringhd.next
 860        st      %l5, [%l6 + 0x08]       ! entry->vaddr = address
 861
 862        ld      [%l6 + 0x00], %l3       ! next = entry->next
 863        ld      [%l6 + 0x04], %l7       ! entry->prev
 864
 865        st      %l7, [%l3 + 0x04]       ! next->prev = entry->prev
 866        st      %l3, [%l7 + 0x00]       ! entry->prev->next = next
 867
 868        sethi   %hi(sun4c_kernel_ring), %l4
 869        or      %l4, %lo(sun4c_kernel_ring), %l4
 870                                        ! head = &sun4c_kernel_ring.ringhd
 871
 872        ld      [%l4 + 0x00], %l7       ! head->next
 873
 874        st      %l4, [%l6 + 0x04]       ! entry->prev = head
 875        st      %l7, [%l6 + 0x00]       ! entry->next = head->next
 876        st      %l6, [%l7 + 0x04]       ! head->next->prev = entry
 877
 878        st      %l6, [%l4 + 0x00]       ! head->next = entry
 879
 880        ld      [%l4 + 0x18], %l3
 881        inc     %l3                     ! sun4c_kernel_ring.num_entries++
 882        st      %l3, [%l4 + 0x18]
 883        b       4f
 884         ld     [%l6 + 0x08], %l5
 885
 8862:
 887        or      %l4, %lo(sun4c_kernel_ring), %l4
 888                                        ! head = &sun4c_kernel_ring.ringhd
 889
 890        ld      [%l4 + 0x04], %l6       ! entry = head->prev
 891
 892        ld      [%l6 + 0x08], %l3       ! tmp = entry->vaddr
 893
 894        ! Flush segment from the cache.
 895        sethi   %hi((64 * 1024)), %l7
 8969:
 897vac_hwflush_patch1:
 898vac_linesize_patch:
 899        subcc   %l7, 16, %l7
 900        bne     9b
 901vac_hwflush_patch2:
 902         sta    %g0, [%l3 + %l7] ASI_FLUSHSEG
 903
 904        st      %l5, [%l6 + 0x08]       ! entry->vaddr = address
 905
 906        ld      [%l6 + 0x00], %l5       ! next = entry->next
 907        ld      [%l6 + 0x04], %l7       ! entry->prev
 908
 909        st      %l7, [%l5 + 0x04]       ! next->prev = entry->prev
 910        st      %l5, [%l7 + 0x00]       ! entry->prev->next = next
 911        st      %l4, [%l6 + 0x04]       ! entry->prev = head
 912
 913        ld      [%l4 + 0x00], %l7       ! head->next
 914
 915        st      %l7, [%l6 + 0x00]       ! entry->next = head->next
 916        st      %l6, [%l7 + 0x04]       ! head->next->prev = entry
 917        st      %l6, [%l4 + 0x00]       ! head->next = entry
 918
 919        mov     %l3, %l5                ! address = tmp
 920
 9214:
 922num_context_patch1:
 923        mov     0x08, %l7
 924
 925        ld      [%l6 + 0x08], %l4
 926        ldub    [%l6 + 0x0c], %l3
 927        or      %l4, %l3, %l4           ! encode new vaddr/pseg into l4
 928
 929        sethi   %hi(AC_CONTEXT), %l3
 930        lduba   [%l3] ASI_CONTROL, %l6
 931
 932        /* Invalidate old mapping, instantiate new mapping,
 933         * for each context.  Registers l6/l7 are live across
 934         * this loop.
 935         */
 9363:      deccc   %l7
 937        sethi   %hi(AC_CONTEXT), %l3
 938        stba    %l7, [%l3] ASI_CONTROL
 939invalid_segment_patch2:
 940        mov     0x7f, %l3
 941        stXa    %l3, [%l5] ASI_SEGMAP
 942        andn    %l4, 0x1ff, %l3
 943        bne     3b
 944         stXa   %l4, [%l3] ASI_SEGMAP
 945
 946        sethi   %hi(AC_CONTEXT), %l3
 947        stba    %l6, [%l3] ASI_CONTROL
 948
 949        andn    %l4, 0x1ff, %l5
 950
 9511:
 952        sethi   %hi(VMALLOC_START), %l4
 953        cmp     %l5, %l4
 954
 955        bgeu    1f
 956         mov    1 << (SUN4C_REAL_PGDIR_SHIFT - PAGE_SHIFT), %l7
 957
 958        sethi   %hi(KERNBASE), %l6
 959
 960        sub     %l5, %l6, %l4
 961        srl     %l4, PAGE_SHIFT, %l4
 962        sethi   %hi((SUN4C_PAGE_KERNEL & 0xf4000000)), %l3
 963        or      %l3, %l4, %l3
 964
 965        sethi   %hi(PAGE_SIZE), %l4
 966
 9672:
 968        sta     %l3, [%l5] ASI_PTE
 969        deccc   %l7
 970        inc     %l3
 971        bne     2b
 972         add    %l5, %l4, %l5
 973
 974        b       7f
 975         sethi  %hi(sun4c_kernel_faults), %l4
 976
 9771:
 978        srl     %l5, SUN4C_PGDIR_SHIFT, %l3
 979        sethi   %hi(swapper_pg_dir), %l4
 980        or      %l4, %lo(swapper_pg_dir), %l4
 981        sll     %l3, 2, %l3
 982        ld      [%l4 + %l3], %l4
 983        and     %l4, PAGE_MASK, %l4
 984
 985        srl     %l5, (PAGE_SHIFT - 2), %l6
 986        and     %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
 987        add     %l6, %l4, %l6
 988
 989        sethi   %hi(PAGE_SIZE), %l4
 990
 9912:
 992        ld      [%l6], %l3
 993        deccc   %l7
 994        sta     %l3, [%l5] ASI_PTE
 995        add     %l6, 0x4, %l6
 996        bne     2b
 997         add    %l5, %l4, %l5
 998
 999        sethi   %hi(sun4c_kernel_faults), %l4
10007:
1001        ld      [%l4 + %lo(sun4c_kernel_faults)], %l3
1002        inc     %l3
1003        st      %l3, [%l4 + %lo(sun4c_kernel_faults)]
1004
1005        /* Restore condition codes */
1006        wr      %l0, 0x0, %psr
1007        WRITE_PAUSE
1008        jmp     %l1
1009         rett   %l2
1010
1011sun4c_fault_fromuser:
1012        SAVE_ALL
1013         nop
1014        
1015        mov     %l7, %o1                ! Decode the info from %l7
1016        mov     %l7, %o2
1017        and     %o1, 1, %o1             ! arg2 = text_faultp
1018        mov     %l7, %o3
1019        and     %o2, 2, %o2             ! arg3 = writep
1020        andn    %o3, 0xfff, %o3         ! arg4 = faulting address
1021
1022        wr      %l0, PSR_ET, %psr
1023        WRITE_PAUSE
1024
1025        call    do_sun4c_fault
1026         add    %sp, STACKFRAME_SZ, %o0 ! arg1 = pt_regs ptr
1027
1028        RESTORE_ALL
1029
1030        .align  4
1031        .globl  srmmu_fault
1032srmmu_fault:
1033        mov     0x400, %l5
1034        mov     0x300, %l4
1035
1036        lda     [%l5] ASI_M_MMUREGS, %l6        ! read sfar first
1037        lda     [%l4] ASI_M_MMUREGS, %l5        ! read sfsr last
1038
1039        andn    %l6, 0xfff, %l6
1040        srl     %l5, 6, %l5                     ! and encode all info into l7
1041
1042        and     %l5, 2, %l5
1043        or      %l5, %l6, %l6
1044
1045        or      %l6, %l7, %l7                   ! l7 = [addr,write,txtfault]
1046
1047        SAVE_ALL
1048
1049        mov     %l7, %o1
1050        mov     %l7, %o2
1051        and     %o1, 1, %o1             ! arg2 = text_faultp
1052        mov     %l7, %o3
1053        and     %o2, 2, %o2             ! arg3 = writep
1054        andn    %o3, 0xfff, %o3         ! arg4 = faulting address
1055
1056        wr      %l0, PSR_ET, %psr
1057        WRITE_PAUSE
1058
1059        call    do_sparc_fault
1060         add    %sp, STACKFRAME_SZ, %o0 ! arg1 = pt_regs ptr
1061
1062        RESTORE_ALL
1063
1064        .align  4
1065        .globl  sys_nis_syscall
1066sys_nis_syscall:
1067        mov     %o7, %l5
1068        add     %sp, STACKFRAME_SZ, %o0         ! pt_regs *regs arg
1069        call    c_sys_nis_syscall
1070         mov    %l5, %o7
1071
1072        .align  4
1073        .globl  sys_execve
1074sys_execve:
1075        mov     %o7, %l5
1076        add     %sp, STACKFRAME_SZ, %o0         ! pt_regs *regs arg
1077        call    sparc_execve
1078         mov    %l5, %o7
1079
1080        .globl  sunos_execv
1081sunos_execv:
1082        st      %g0, [%sp + STACKFRAME_SZ + PT_I2]
1083
1084        call    sparc_execve
1085         add    %sp, STACKFRAME_SZ, %o0
1086
1087        b       ret_sys_call
1088         ld     [%sp + STACKFRAME_SZ + PT_I0], %o0
1089
1090        .align  4
1091        .globl  sys_sparc_pipe
1092sys_sparc_pipe:
1093        mov     %o7, %l5
1094        add     %sp, STACKFRAME_SZ, %o0         ! pt_regs *regs arg
1095        call    sparc_pipe
1096         mov    %l5, %o7
1097
1098        .align  4
1099        .globl  sys_sigaltstack
1100sys_sigaltstack:
1101        mov     %o7, %l5
1102        mov     %fp, %o2
1103        call    do_sigaltstack
1104         mov    %l5, %o7
1105
1106        .align  4
1107        .globl  sys_sigstack
1108sys_sigstack:
1109        mov     %o7, %l5
1110        mov     %fp, %o2
1111        call    do_sys_sigstack
1112         mov    %l5, %o7
1113
1114        .align  4
1115        .globl  sys_sigreturn
1116sys_sigreturn:
1117        call    do_sigreturn
1118         add    %sp, STACKFRAME_SZ, %o0
1119
1120        ld      [%curptr + TI_FLAGS], %l5
1121        andcc   %l5, _TIF_SYSCALL_TRACE, %g0
1122        be      1f
1123         nop
1124
1125        call    syscall_trace
1126         nop
1127
11281:
1129        /* We don't want to muck with user registers like a
1130         * normal syscall, just return.
1131         */
1132        RESTORE_ALL
1133
1134        .align  4
1135        .globl  sys_rt_sigreturn
1136sys_rt_sigreturn:
1137        call    do_rt_sigreturn
1138         add    %sp, STACKFRAME_SZ, %o0
1139
1140        ld      [%curptr + TI_FLAGS], %l5
1141        andcc   %l5, _TIF_SYSCALL_TRACE, %g0
1142        be      1f
1143         nop
1144
1145        add     %sp, STACKFRAME_SZ, %o0
1146        call    syscall_trace
1147         mov    1, %o1
1148
11491:
1150        /* We are returning to a signal handler. */
1151        RESTORE_ALL
1152
1153        /* Now that we have a real sys_clone, sys_fork() is
1154         * implemented in terms of it.  Our _real_ implementation
1155         * of SunOS vfork() will use sys_vfork().
1156         *
1157         * XXX These three should be consolidated into mostly shared
1158         * XXX code just like on sparc64... -DaveM
1159         */
1160        .align  4
1161        .globl  sys_fork, flush_patch_two
1162sys_fork:
1163        mov     %o7, %l5
1164flush_patch_two:
1165        FLUSH_ALL_KERNEL_WINDOWS;
1166        ld      [%curptr + TI_TASK], %o4
1167        rd      %psr, %g4
1168        WRITE_PAUSE
1169        mov     SIGCHLD, %o0                    ! arg0: clone flags
1170        rd      %wim, %g5
1171        WRITE_PAUSE
1172        mov     %fp, %o1                        ! arg1: usp
1173        std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
1174        add     %sp, STACKFRAME_SZ, %o2         ! arg2: pt_regs ptr
1175        mov     0, %o3
1176        call    sparc_do_fork
1177         mov    %l5, %o7
1178
1179        /* Whee, kernel threads! */
1180        .globl  sys_clone, flush_patch_three
1181sys_clone:
1182        mov     %o7, %l5
1183flush_patch_three:
1184        FLUSH_ALL_KERNEL_WINDOWS;
1185        ld      [%curptr + TI_TASK], %o4
1186        rd      %psr, %g4
1187        WRITE_PAUSE
1188
1189        /* arg0,1: flags,usp  -- loaded already */
1190        cmp     %o1, 0x0                        ! Is new_usp NULL?
1191        rd      %wim, %g5
1192        WRITE_PAUSE
1193        be,a    1f
1194         mov    %fp, %o1                        ! yes, use callers usp
1195        andn    %o1, 7, %o1                     ! no, align to 8 bytes
11961:
1197        std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
1198        add     %sp, STACKFRAME_SZ, %o2         ! arg2: pt_regs ptr
1199        mov     0, %o3
1200        call    sparc_do_fork
1201         mov    %l5, %o7
1202
1203        /* Whee, real vfork! */
1204        .globl  sys_vfork, flush_patch_four
1205sys_vfork:
1206flush_patch_four:
1207        FLUSH_ALL_KERNEL_WINDOWS;
1208        ld      [%curptr + TI_TASK], %o4
1209        rd      %psr, %g4
1210        WRITE_PAUSE
1211        rd      %wim, %g5
1212        WRITE_PAUSE
1213        std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
1214        sethi   %hi(0x4000 | 0x0100 | SIGCHLD), %o0
1215        mov     %fp, %o1
1216        or      %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
1217        sethi   %hi(sparc_do_fork), %l1
1218        mov     0, %o3
1219        jmpl    %l1 + %lo(sparc_do_fork), %g0
1220         add    %sp, STACKFRAME_SZ, %o2
1221
1222        .align  4
1223linux_sparc_ni_syscall:
1224        sethi   %hi(sys_ni_syscall), %l7
1225        b       syscall_is_too_hard
1226         or     %l7, %lo(sys_ni_syscall), %l7
1227
1228linux_fast_syscall:
1229        andn    %l7, 3, %l7
1230        mov     %i0, %o0
1231        mov     %i1, %o1
1232        mov     %i2, %o2
1233        jmpl    %l7 + %g0, %g0
1234         mov    %i3, %o3
1235
1236linux_syscall_trace:
1237        add     %sp, STACKFRAME_SZ, %o0
1238        call    syscall_trace
1239         mov    0, %o1
1240        cmp     %o0, 0
1241        bne     3f
1242         mov    -ENOSYS, %o0
1243        mov     %i0, %o0
1244        mov     %i1, %o1
1245        mov     %i2, %o2
1246        mov     %i3, %o3
1247        b       2f
1248         mov    %i4, %o4
1249
1250        .globl  ret_from_fork
1251ret_from_fork:
1252        call    schedule_tail
1253         mov    %g3, %o0
1254        b       ret_sys_call
1255         ld     [%sp + STACKFRAME_SZ + PT_I0], %o0
1256
1257        /* Linux native system calls enter here... */
1258        .align  4
1259        .globl  linux_sparc_syscall
1260linux_sparc_syscall:
1261        sethi   %hi(PSR_SYSCALL), %l4
1262        or      %l0, %l4, %l0
1263        /* Direct access to user regs, must faster. */
1264        cmp     %g1, NR_SYSCALLS
1265        bgeu    linux_sparc_ni_syscall
1266         sll    %g1, 2, %l4
1267        ld      [%l7 + %l4], %l7
1268        andcc   %l7, 1, %g0
1269        bne     linux_fast_syscall
1270         /* Just do first insn from SAVE_ALL in the delay slot */
1271
1272syscall_is_too_hard:
1273        SAVE_ALL_HEAD
1274         rd     %wim, %l3
1275
1276        wr      %l0, PSR_ET, %psr
1277        mov     %i0, %o0
1278        mov     %i1, %o1
1279        mov     %i2, %o2
1280
1281        ld      [%curptr + TI_FLAGS], %l5
1282        mov     %i3, %o3
1283        andcc   %l5, _TIF_SYSCALL_TRACE, %g0
1284        mov     %i4, %o4
1285        bne     linux_syscall_trace
1286         mov    %i0, %l5
12872:
1288        call    %l7
1289         mov    %i5, %o5
1290
12913:
1292        st      %o0, [%sp + STACKFRAME_SZ + PT_I0]
1293
1294ret_sys_call:
1295        ld      [%curptr + TI_FLAGS], %l6
1296        cmp     %o0, -ERESTART_RESTARTBLOCK
1297        ld      [%sp + STACKFRAME_SZ + PT_PSR], %g3
1298        set     PSR_C, %g2
1299        bgeu    1f
1300         andcc  %l6, _TIF_SYSCALL_TRACE, %g0
1301
1302        /* System call success, clear Carry condition code. */
1303        andn    %g3, %g2, %g3
1304        clr     %l6
1305        st      %g3, [%sp + STACKFRAME_SZ + PT_PSR]     
1306        bne     linux_syscall_trace2
1307         ld     [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */
1308        add     %l1, 0x4, %l2                   /* npc = npc+4 */
1309        st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
1310        b       ret_trap_entry
1311         st     %l2, [%sp + STACKFRAME_SZ + PT_NPC]
13121:
1313        /* System call failure, set Carry condition code.
1314         * Also, get abs(errno) to return to the process.
1315         */
1316        sub     %g0, %o0, %o0
1317        or      %g3, %g2, %g3
1318        st      %o0, [%sp + STACKFRAME_SZ + PT_I0]
1319        mov     1, %l6
1320        st      %g3, [%sp + STACKFRAME_SZ + PT_PSR]
1321        bne     linux_syscall_trace2
1322         ld     [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */
1323        add     %l1, 0x4, %l2                   /* npc = npc+4 */
1324        st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
1325        b       ret_trap_entry
1326         st     %l2, [%sp + STACKFRAME_SZ + PT_NPC]
1327
1328linux_syscall_trace2:
1329        add     %sp, STACKFRAME_SZ, %o0
1330        mov     1, %o1
1331        call    syscall_trace
1332         add    %l1, 0x4, %l2                   /* npc = npc+4 */
1333        st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
1334        b       ret_trap_entry
1335         st     %l2, [%sp + STACKFRAME_SZ + PT_NPC]
1336
1337
1338/* Saving and restoring the FPU state is best done from lowlevel code.
1339 *
1340 * void fpsave(unsigned long *fpregs, unsigned long *fsr,
1341 *             void *fpqueue, unsigned long *fpqdepth)
1342 */
1343
1344        .globl  fpsave
1345fpsave:
1346        st      %fsr, [%o1]     ! this can trap on us if fpu is in bogon state
1347        ld      [%o1], %g1
1348        set     0x2000, %g4
1349        andcc   %g1, %g4, %g0
1350        be      2f
1351         mov    0, %g2
1352
1353        /* We have an fpqueue to save. */
13541:
1355        std     %fq, [%o2]
1356fpsave_magic:
1357        st      %fsr, [%o1]
1358        ld      [%o1], %g3
1359        andcc   %g3, %g4, %g0
1360        add     %g2, 1, %g2
1361        bne     1b
1362         add    %o2, 8, %o2
1363
13642:
1365        st      %g2, [%o3]
1366
1367        std     %f0, [%o0 + 0x00]
1368        std     %f2, [%o0 + 0x08]
1369        std     %f4, [%o0 + 0x10]
1370        std     %f6, [%o0 + 0x18]
1371        std     %f8, [%o0 + 0x20]
1372        std     %f10, [%o0 + 0x28]
1373        std     %f12, [%o0 + 0x30]
1374        std     %f14, [%o0 + 0x38]
1375        std     %f16, [%o0 + 0x40]
1376        std     %f18, [%o0 + 0x48]
1377        std     %f20, [%o0 + 0x50]
1378        std     %f22, [%o0 + 0x58]
1379        std     %f24, [%o0 + 0x60]
1380        std     %f26, [%o0 + 0x68]
1381        std     %f28, [%o0 + 0x70]
1382        retl
1383         std    %f30, [%o0 + 0x78]
1384
1385        /* Thanks for Theo Deraadt and the authors of the Sprite/netbsd/openbsd
1386         * code for pointing out this possible deadlock, while we save state
1387         * above we could trap on the fsr store so our low level fpu trap
1388         * code has to know how to deal with this.
1389         */
1390fpsave_catch:
1391        b       fpsave_magic + 4
1392         st     %fsr, [%o1]
1393
1394fpsave_catch2:
1395        b       fpsave + 4
1396         st     %fsr, [%o1]
1397
1398        /* void fpload(unsigned long *fpregs, unsigned long *fsr); */
1399
1400        .globl  fpload
1401fpload:
1402        ldd     [%o0 + 0x00], %f0
1403        ldd     [%o0 + 0x08], %f2
1404        ldd     [%o0 + 0x10], %f4
1405        ldd     [%o0 + 0x18], %f6
1406        ldd     [%o0 + 0x20], %f8
1407        ldd     [%o0 + 0x28], %f10
1408        ldd     [%o0 + 0x30], %f12
1409        ldd     [%o0 + 0x38], %f14
1410        ldd     [%o0 + 0x40], %f16
1411        ldd     [%o0 + 0x48], %f18
1412        ldd     [%o0 + 0x50], %f20
1413        ldd     [%o0 + 0x58], %f22
1414        ldd     [%o0 + 0x60], %f24
1415        ldd     [%o0 + 0x68], %f26
1416        ldd     [%o0 + 0x70], %f28
1417        ldd     [%o0 + 0x78], %f30
1418        ld      [%o1], %fsr
1419        retl
1420         nop
1421
1422        /* __ndelay and __udelay take two arguments:
1423         * 0 - nsecs or usecs to delay
1424         * 1 - per_cpu udelay_val (loops per jiffy)
1425         *
1426         * Note that ndelay gives HZ times higher resolution but has a 10ms
1427         * limit.  udelay can handle up to 1s.
1428         */
1429        .globl  __ndelay
1430__ndelay:
1431        save    %sp, -STACKFRAME_SZ, %sp
1432        mov     %i0, %o0
1433        call    .umul                   ! round multiplier up so large ns ok
1434         mov    0x1ae, %o1              ! 2**32 / (1 000 000 000 / HZ)
1435        call    .umul
1436         mov    %i1, %o1                ! udelay_val
1437        ba      delay_continue
1438         mov    %o1, %o0                ! >>32 later for better resolution
1439
1440        .globl  __udelay
1441__udelay:
1442        save    %sp, -STACKFRAME_SZ, %sp
1443        mov     %i0, %o0
1444        sethi   %hi(0x10c7), %o1        ! round multiplier up so large us ok
1445        call    .umul
1446         or     %o1, %lo(0x10c7), %o1   ! 2**32 / 1 000 000
1447        call    .umul
1448         mov    %i1, %o1                ! udelay_val
1449        sethi   %hi(0x028f4b62), %l0    ! Add in rounding constant * 2**32,
1450        or      %g0, %lo(0x028f4b62), %l0
1451        addcc   %o0, %l0, %o0           ! 2**32 * 0.009 999
1452        bcs,a   3f
1453         add    %o1, 0x01, %o1
14543:
1455        call    .umul
1456         mov    HZ, %o0                 ! >>32 earlier for wider range
1457
1458delay_continue:
1459        cmp     %o0, 0x0
14601:
1461        bne     1b
1462         subcc  %o0, 1, %o0
1463        
1464        ret
1465        restore
1466
1467        /* Handle a software breakpoint */
1468        /* We have to inform parent that child has stopped */
1469        .align 4
1470        .globl breakpoint_trap
1471breakpoint_trap:
1472        rd      %wim,%l3
1473        SAVE_ALL
1474        wr      %l0, PSR_ET, %psr
1475        WRITE_PAUSE
1476
1477        st      %i0, [%sp + STACKFRAME_SZ + PT_G0] ! for restarting syscalls
1478        call    sparc_breakpoint
1479         add    %sp, STACKFRAME_SZ, %o0
1480
1481        RESTORE_ALL
1482
1483#ifdef CONFIG_KGDB
1484        .align  4
1485        .globl  kgdb_trap_low
1486        .type   kgdb_trap_low,#function
1487kgdb_trap_low:
1488        rd      %wim,%l3
1489        SAVE_ALL
1490        wr      %l0, PSR_ET, %psr
1491        WRITE_PAUSE
1492
1493        call    kgdb_trap
1494         add    %sp, STACKFRAME_SZ, %o0
1495
1496        RESTORE_ALL
1497        .size   kgdb_trap_low,.-kgdb_trap_low
1498#endif
1499
1500        .align  4
1501        .globl  flush_patch_exception
1502flush_patch_exception:
1503        FLUSH_ALL_KERNEL_WINDOWS;
1504        ldd     [%o0], %o6
1505        jmpl    %o7 + 0xc, %g0                  ! see asm-sparc/processor.h
1506         mov    1, %g1                          ! signal EFAULT condition
1507
1508        .align  4
1509        .globl  kill_user_windows, kuw_patch1_7win
1510        .globl  kuw_patch1
1511kuw_patch1_7win:        sll     %o3, 6, %o3
1512
1513        /* No matter how much overhead this routine has in the worst
1514         * case scenerio, it is several times better than taking the
1515         * traps with the old method of just doing flush_user_windows().
1516         */
1517kill_user_windows:
1518        ld      [%g6 + TI_UWINMASK], %o0        ! get current umask
1519        orcc    %g0, %o0, %g0                   ! if no bits set, we are done
1520        be      3f                              ! nothing to do
1521         rd     %psr, %o5                       ! must clear interrupts
1522        or      %o5, PSR_PIL, %o4               ! or else that could change
1523        wr      %o4, 0x0, %psr                  ! the uwinmask state
1524        WRITE_PAUSE                             ! burn them cycles
15251:
1526        ld      [%g6 + TI_UWINMASK], %o0        ! get consistent state
1527        orcc    %g0, %o0, %g0                   ! did an interrupt come in?
1528        be      4f                              ! yep, we are done
1529         rd     %wim, %o3                       ! get current wim
1530        srl     %o3, 1, %o4                     ! simulate a save
1531kuw_patch1:
1532        sll     %o3, 7, %o3                     ! compute next wim
1533        or      %o4, %o3, %o3                   ! result
1534        andncc  %o0, %o3, %o0                   ! clean this bit in umask
1535        bne     kuw_patch1                      ! not done yet
1536         srl    %o3, 1, %o4                     ! begin another save simulation
1537        wr      %o3, 0x0, %wim                  ! set the new wim
1538        st      %g0, [%g6 + TI_UWINMASK]        ! clear uwinmask
15394:
1540        wr      %o5, 0x0, %psr                  ! re-enable interrupts
1541        WRITE_PAUSE                             ! burn baby burn
15423:
1543        retl                                    ! return
1544         st     %g0, [%g6 + TI_W_SAVED]         ! no windows saved
1545
1546        .align  4
1547        .globl  restore_current
1548restore_current:
1549        LOAD_CURRENT(g6, o0)
1550        retl
1551         nop
1552
1553#ifdef CONFIG_PCI
1554#include <asm/pcic.h>
1555
1556        .align  4
1557        .globl  linux_trap_ipi15_pcic
1558linux_trap_ipi15_pcic:
1559        rd      %wim, %l3
1560        SAVE_ALL
1561
1562        /*
1563         * First deactivate NMI
1564         * or we cannot drop ET, cannot get window spill traps.
1565         * The busy loop is necessary because the PIO error
1566         * sometimes does not go away quickly and we trap again.
1567         */
1568        sethi   %hi(pcic_regs), %o1
1569        ld      [%o1 + %lo(pcic_regs)], %o2
1570
1571        ! Get pending status for printouts later.
1572        ld      [%o2 + PCI_SYS_INT_PENDING], %o0
1573
1574        mov     PCI_SYS_INT_PENDING_CLEAR_ALL, %o1
1575        stb     %o1, [%o2 + PCI_SYS_INT_PENDING_CLEAR]
15761:
1577        ld      [%o2 + PCI_SYS_INT_PENDING], %o1
1578        andcc   %o1, ((PCI_SYS_INT_PENDING_PIO|PCI_SYS_INT_PENDING_PCI)>>24), %g0
1579        bne     1b
1580         nop
1581
1582        or      %l0, PSR_PIL, %l4
1583        wr      %l4, 0x0, %psr
1584        WRITE_PAUSE
1585        wr      %l4, PSR_ET, %psr
1586        WRITE_PAUSE
1587
1588        call    pcic_nmi
1589         add    %sp, STACKFRAME_SZ, %o1 ! struct pt_regs *regs
1590        RESTORE_ALL
1591
1592        .globl  pcic_nmi_trap_patch
1593pcic_nmi_trap_patch:
1594        sethi   %hi(linux_trap_ipi15_pcic), %l3
1595        jmpl    %l3 + %lo(linux_trap_ipi15_pcic), %g0
1596         rd     %psr, %l0
1597        .word   0
1598
1599#endif /* CONFIG_PCI */
1600
1601        .globl  flushw_all
1602flushw_all:
1603        save    %sp, -0x40, %sp
1604        save    %sp, -0x40, %sp
1605        save    %sp, -0x40, %sp
1606        save    %sp, -0x40, %sp
1607        save    %sp, -0x40, %sp
1608        save    %sp, -0x40, %sp
1609        save    %sp, -0x40, %sp
1610        restore
1611        restore
1612        restore
1613        restore
1614        restore
1615        restore
1616        ret
1617         restore
1618
1619/* End of entry.S */
1620
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.