root/arch/sparc/kernel/entry.S

/* [previous][next][first][last][top][bottom][index][help] */
   1 /* $Id: entry.S,v 1.79 1996/03/01 07:15:54 davem Exp $
   2  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
   3  *
   4  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   5  */
   6 
   7 #include <linux/config.h>
   8 #include <linux/errno.h>
   9 
  10 #include <asm/head.h>
  11 #include <asm/asi.h>
  12 #include <asm/kgdb.h>
  13 #include <asm/contregs.h>
  14 #include <asm/ptrace.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 #include <asm/winmacro.h>
  21 #include <asm/signal.h>
  22 
  23 #define NR_SYSCALLS 255      /* Each OS is different... */
  24 
  25 /* All trap entry points _must_ begin with this macro or else you
  26  * lose.  It makes sure the kernel has a proper window so that
  27  * c-code can be called.  Some day for SMP we'll grab klock here.
  28  */
  29 #define SAVE_ALL \
  30         sethi   %hi(trap_setup), %l4; \
  31         jmpl    %l4 + %lo(trap_setup), %l6; \
  32          nop;
  33 
  34 /* All traps low-level code here must end with this macro.
  35  * For SMP configurations the ret_trap_entry routine will
  36  * have to appropriate code to actually release the kernel
  37  * entry lock.
  38  */
  39 #define RESTORE_ALL \
  40         b       ret_trap_entry; \
  41          nop;
  42 
  43 /* First, KGDB low level things.  This is a rewrite
  44  * of the routines found in the sparc-stub.c asm() statement
  45  * from the gdb distribution.  This is also dual-purpose
  46  * as a software trap for userlevel programs.
  47  */
  48         .data
  49         .align  4
  50 
  51 in_trap_handler:
  52         .word   0
  53 
  54         .text
  55         .align  4
  56 
  57 ! This function is called when any SPARC trap (except window overflow or
  58 ! underflow) occurs.  It makes sure that the invalid register window is still
  59 ! available before jumping into C code.  It will also restore the world if you
  60 ! return from handle_exception.
  61 
  62         .globl  C_LABEL(trap_low)
  63 C_LABEL(trap_low):
  64         rd      %wim, %l3
  65         SAVE_ALL
  66 
  67         sethi   %hi(in_trap_handler), %l4
  68         ld      [%lo(in_trap_handler) + %l4], %l5
  69         inc     %l5
  70         st      %l5, [%lo(in_trap_handler) + %l4]
  71 
  72         /* Make sure kgdb sees the same state we just saved. */
  73         LOAD_PT_GLOBALS(sp)
  74         LOAD_PT_INS(sp)
  75         ld      [%sp + REGWIN_SZ + PT_Y], %l4
  76         ld      [%sp + REGWIN_SZ + PT_WIM], %l3
  77         ld      [%sp + REGWIN_SZ + PT_PSR], %l0
  78         ld      [%sp + REGWIN_SZ + PT_PC], %l1
  79         ld      [%sp + REGWIN_SZ + PT_NPC], %l2
  80         rd      %tbr, %l5       /* Never changes... */
  81 
  82         /* Make kgdb exception frame. */        
  83         sub     %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
  84                                         ! + hidden arg + arg spill
  85                                         ! + doubleword alignment
  86                                         ! + registers[72] local var
  87         SAVE_KGDB_GLOBALS(sp)
  88         SAVE_KGDB_INS(sp)
  89         SAVE_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
  90 
  91         /* We are increasing PIL, so two writes. */
  92         or      %l0, PSR_PIL, %l0
  93         wr      %l0, 0, %psr
  94         wr      %l0, PSR_ET, %psr
  95         WRITE_PAUSE
  96 
  97         call    C_LABEL(handle_exception)
  98          add    %sp, REGWIN_SZ, %o0     ! Pass address of registers
  99 
 100         /* Load new kgdb register set. */
 101         LOAD_KGDB_GLOBALS(sp)
 102         LOAD_KGDB_INS(sp)
 103         LOAD_KGDB_SREGS(sp, l0, l2)
 104         wr      %l0, 0x0, %y
 105 
 106         sethi   %hi(in_trap_handler), %l4
 107         ld      [%lo(in_trap_handler) + %l4], %l5
 108         dec     %l5
 109         st      %l5, [%lo(in_trap_handler) + %l4]
 110 
 111         add     %sp,(16+1+6+1+72)*4,%sp ! Undo the kgdb trap frame.
 112 
 113         /* Now take what kgdb did and place it into the pt_regs
 114          * frame which SparcLinux RESTORE_ALL understands.,
 115          */
 116         STORE_PT_INS(sp)
 117         STORE_PT_GLOBALS(sp)
 118         STORE_PT_YREG(sp, g2)
 119         STORE_PT_PRIV(sp, l1, l2, l3)
 120 
 121         RESTORE_ALL
 122 
 123 
 124 #ifdef CONFIG_BLK_DEV_FD
 125 #ifdef TRACE_FLOPPY_HARDINT
 126 /* Useful tracing */
 127         .data
 128         .align  4
 129         .globl  C_LABEL(floppy_hardint_trace)
 130 C_LABEL(floppy_hardint_trace):
 131         .skip   32
 132         .globl  C_LABEL(floppy_hardint_index)
 133 C_LABEL(floppy_hardint_index):
 134         .word   0
 135 #endif
 136 
 137         .text
 138         .align  4
 139         .globl  C_LABEL(floppy_hardint)
 140 C_LABEL(floppy_hardint):
 141         /* Can only use regs %l3->%l7:
 142          * %l3 -- base address of fdc registers
 143          * %l4 -- pdma_vaddr
 144          * %l5 -- scratch for ld/st address
 145          * %l6 -- pdma_size
 146          * %l7 -- floppy_softint
 147          */
 148 
 149 #ifdef TRACE_FLOPPY_HARDINT
 150         sethi   %hi(C_LABEL(floppy_hardint_trace)), %l5
 151         or      %l5, %lo(C_LABEL(floppy_hardint_trace)), %l5
 152         ld      [%l5 + 32], %l7
 153         add     %l7, 1, %l7
 154         and     %l7, 31, %l7
 155         st      %l7, [%l5 + 32]
 156         sub     %l7, 1, %l7
 157         and     %l7, 31, %l7
 158         add     %l7, %l5, %l5
 159         or      %g0, 0xf, %l7
 160         stb     %l7, [%l5]
 161 #endif
 162 
 163         /* Do we have work to do? */
 164         sethi   %hi(C_LABEL(doing_pdma)), %l4
 165         ld      [%l4 + %lo(C_LABEL(doing_pdma))], %l4
 166         cmp     %l4, 0
 167         be      floppy_dosoftint
 168          nop
 169 
 170         /* Load fdc register base */
 171         sethi   %hi(C_LABEL(fdc_status)), %l3
 172         ld      [%l3 + %lo(C_LABEL(fdc_status))], %l3
 173 
 174         /* Setup register addresses */
 175         sethi   %hi(C_LABEL(pdma_vaddr)), %l5   ! transfer buffer
 176         ld      [%l5 + %lo(C_LABEL(pdma_vaddr))], %l4
 177         sethi   %hi(C_LABEL(pdma_size)), %l5    ! bytes to go
 178         ld      [%l5 + %lo(C_LABEL(pdma_size))], %l6
 179 next_byte:
 180 #ifdef TRACE_FLOPPY_HARDINT
 181         sethi   %hi(C_LABEL(floppy_hardint_trace)), %l5
 182         or      %l5, %lo(C_LABEL(floppy_hardint_trace)), %l5
 183         ld      [%l5 + 32], %l7
 184         add     %l7, 1, %l7
 185         and     %l7, 31, %l7
 186         st      %l7, [%l5 + 32]
 187         sub     %l7, 1, %l7
 188         and     %l7, 31, %l7
 189         add     %l7, %l5, %l5
 190         ldub    [%l3], %l7
 191         stb     %l7, [%l5]
 192 #else
 193         ldub    [%l3], %l7
 194 #endif
 195 
 196         andcc   %l7, 0x80, %g0          ! Does fifo still have data
 197         bz      floppy_fifo_emptied     ! fifo has been emptied...
 198          andcc  %l7, 0x20, %g0          ! in non-dma mode still?
 199         bz      floppy_overrun          ! nope, overrun
 200          andcc  %l7, 0x40, %g0          ! 0=write 1=read
 201         bz      floppy_write
 202          sub    %l6, 0x1, %l6
 203 
 204         /* Ok, actually read this byte */
 205         ldub    [%l3 + 1], %l7
 206         orcc    %g0, %l6, %g0
 207         stb     %l7, [%l4]
 208         bne     next_byte
 209          add    %l4, 0x1, %l4
 210 
 211         b       floppy_tdone
 212          nop
 213 
 214 floppy_write:
 215         /* Ok, actually write this byte */
 216         ldub    [%l4], %l7
 217         orcc    %g0, %l6, %g0
 218         stb     %l7, [%l3 + 1]
 219         bne     next_byte
 220          add    %l4, 0x1, %l4
 221 
 222         /* fall through... */
 223 floppy_tdone:
 224         sethi   %hi(C_LABEL(pdma_vaddr)), %l5
 225         st      %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))]
 226         sethi   %hi(C_LABEL(pdma_size)), %l5
 227         st      %l6, [%l5 + %lo(C_LABEL(pdma_size))]
 228         /* Flip terminal count pin */
 229         set     C_LABEL(auxio_register), %l4
 230         ld      [%l4], %l4
 231         ldub    [%l4], %l5
 232         or      %l5, 0xf4, %l5
 233         stb     %l5, [%l4]
 234 
 235         /* Kill some time so the bits set */
 236         WRITE_PAUSE
 237         WRITE_PAUSE
 238 
 239         ldub    [%l4], %l5
 240         andn    %l5, 0x04, %l5
 241         or      %l5, 0xf0, %l5
 242         stb     %l5, [%l4]
 243 
 244         /* Prevent recursion */
 245         sethi   %hi(C_LABEL(doing_pdma)), %l4
 246         b       floppy_dosoftint
 247          st     %g0, [%l4 + %lo(C_LABEL(doing_pdma))]
 248 
 249         /* We emptied the FIFO, but we haven't read everything
 250          * as of yet.  Store the current transfer address and
 251          * bytes left to read so we can continue when the next
 252          * fast IRQ comes in.
 253          */
 254 floppy_fifo_emptied:
 255         sethi   %hi(C_LABEL(pdma_vaddr)), %l5
 256         st      %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))]
 257         sethi   %hi(C_LABEL(pdma_size)), %l7
 258         st      %l6, [%l7 + %lo(C_LABEL(pdma_size))]
 259 
 260         /* Restore condition codes */
 261         wr      %l0, 0x0, %psr
 262         WRITE_PAUSE
 263 
 264         jmp     %l1
 265         rett    %l2
 266 
 267 floppy_overrun:
 268         sethi   %hi(C_LABEL(pdma_vaddr)), %l5
 269         st      %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))]
 270         sethi   %hi(C_LABEL(pdma_size)), %l5
 271         st      %l6, [%l5 + %lo(C_LABEL(pdma_size))]
 272         /* Prevent recursion */
 273         sethi   %hi(C_LABEL(doing_pdma)), %l4
 274         st      %g0, [%l4 + %lo(C_LABEL(doing_pdma))]
 275 
 276         /* fall through... */
 277 floppy_dosoftint:
 278         rd      %wim, %l3
 279         SAVE_ALL
 280 
 281         /* Set all IRQs off. */
 282         or      %l0, PSR_PIL, %l4
 283         wr      %l4, 0x0, %psr
 284         wr      %l4, PSR_ET, %psr
 285         WRITE_PAUSE
 286 
 287         mov     11, %o0                 ! floppy irq level
 288         call    C_LABEL(floppy_interrupt)
 289          add    %sp, REGWIN_SZ, %o1     ! struct pt_regs *regs
 290 
 291         RESTORE_ALL
 292         
 293 #endif /* (CONFIG_BLK_DEV_FD) */
 294 
 295         /* Bad trap handler */
 296         .globl  bad_trap_handler
 297 bad_trap_handler:
 298         SAVE_ALL
 299 
 300         wr      %l0, PSR_ET, %psr
 301         WRITE_PAUSE
 302 
 303         mov     %l7, %o0                ! trap number
 304         mov     %l0, %o1                ! psr
 305         call    C_LABEL(do_hw_interrupt)
 306          mov    %l1, %o2                ! pc
 307 
 308         RESTORE_ALL
 309         
 310 /* For now all IRQ's not registered get sent here. handler_irq() will
 311  * see if a routine is registered to handle this interrupt and if not
 312  * it will say so on the console.
 313  */
 314 
 315         .align  4
 316         .globl  real_irq_entry
 317 real_irq_entry:
 318         SAVE_ALL
 319 
 320         /* start atomic operation with respect to software interrupts */
 321         sethi   %hi(C_LABEL(intr_count)), %l4
 322         ld      [%l4 + %lo(C_LABEL(intr_count))], %l5
 323         add     %l5, 0x1, %l5
 324         st      %l5, [%l4 + %lo(C_LABEL(intr_count))]
 325 
 326         /* Enable traps w/IRQs off, so we can call c-code properly.
 327          * Note how we are increasing PIL so we need to do two writes
 328          * to work around a MicroSPARC bug of sorts.
 329          */
 330         or      %l0, PSR_PIL, %l4
 331         wr      %l4, 0x0, %psr
 332         wr      %l4, PSR_ET, %psr
 333         WRITE_PAUSE
 334 
 335         mov     %l7, %o0                ! irq level
 336         call    C_LABEL(handler_irq)
 337          add    %sp, REGWIN_SZ, %o1     ! pt_regs ptr
 338 
 339 rie_checkbh:
 340         sethi   %hi(C_LABEL(intr_count)), %l4
 341         ld      [%l4 + %lo(C_LABEL(intr_count))], %l5
 342         subcc   %l5, 0x1, %l5
 343         bne     2f      /* IRQ within IRQ, get out of here... */
 344          nop
 345 
 346         sethi   %hi(C_LABEL(bh_active)), %l3
 347         ld      [%l3 + %lo(C_LABEL(bh_active))], %g2
 348         sethi   %hi(C_LABEL(bh_mask)), %l3
 349         ld      [%l3 + %lo(C_LABEL(bh_mask))], %g3
 350         andcc   %g2, %g3, %g0
 351         be      2f
 352          nop
 353 
 354         /* do_bottom_half must run at normal kernel priority, ie. all
 355          * IRQ's on.
 356          */
 357         rd      %psr, %g4
 358         andn    %g4, PSR_PIL, %g4
 359         wr      %g4, 0x0, %psr
 360         WRITE_PAUSE
 361         call    C_LABEL(do_bottom_half) 
 362          nop
 363 
 364         /* Try again... */
 365         b       rie_checkbh
 366          nop
 367         
 368 2:
 369         st      %l5, [%l4 + %lo(C_LABEL(intr_count))]
 370 
 371         RESTORE_ALL
 372 
 373         /* This routine handles illegal instructions and privileged
 374          * instruction attempts from user code.
 375          */
 376         .align  4
 377         .globl  bad_instruction
 378 bad_instruction:
 379         SAVE_ALL
 380 
 381         wr      %l0, PSR_ET, %psr               ! re-enable traps
 382         WRITE_PAUSE
 383 
 384         add     %sp, REGWIN_SZ, %o0
 385         mov     %l1, %o1
 386         mov     %l2, %o2
 387         call    C_LABEL(do_illegal_instruction)
 388          mov    %l0, %o3
 389         RESTORE_ALL
 390 
 391         .align  4
 392         .globl  priv_instruction
 393 priv_instruction:
 394         SAVE_ALL
 395 
 396         wr      %l0, PSR_ET, %psr
 397         WRITE_PAUSE
 398 
 399         add     %sp, REGWIN_SZ, %o0
 400         mov     %l1, %o1
 401         mov     %l2, %o2
 402         call    C_LABEL(do_priv_instruction)
 403          mov    %l0, %o3
 404 
 405         RESTORE_ALL
 406 
 407         /* This routine handles unaligned data accesses.
 408          */
 409         .align  4
 410         .globl  mna_handler
 411 mna_handler:
 412         SAVE_ALL
 413 
 414         wr      %l0, PSR_ET, %psr               ! re-enable traps
 415         WRITE_PAUSE
 416 
 417         add     %sp, REGWIN_SZ, %o0
 418         mov     %l1, %o1
 419         mov     %l2, %o2
 420         call    C_LABEL(do_memaccess_unaligned)
 421          mov    %l0, %o3
 422 
 423         RESTORE_ALL
 424 
 425         /* This routine handles floating point disabled traps. */
 426         .align  4
 427         .globl  fpd_trap_handler
 428 fpd_trap_handler:
 429         SAVE_ALL
 430 
 431         wr      %l0, PSR_ET, %psr               ! re-enable traps
 432         WRITE_PAUSE
 433 
 434         add     %sp, REGWIN_SZ, %o0
 435         mov     %l1, %o1
 436         mov     %l2, %o2
 437         call    C_LABEL(do_fpd_trap)
 438          mov    %l0, %o3
 439 
 440         RESTORE_ALL
 441 
 442         /* This routine handles Floating Point Exceptions. */
 443         .align  4
 444         .globl  fpe_trap_handler
 445 fpe_trap_handler:
 446         set     fpsave_magic, %l5
 447         cmp     %l1, %l5
 448         bne     1f
 449          sethi  %hi(fpsave_catch), %l5
 450         or      %l5, %lo(fpsave_catch), %l5
 451         wr      %l0, 0x0, %psr
 452         WRITE_PAUSE
 453         jmp     %l5
 454          rett   %l5 + 4
 455 
 456 1:
 457         SAVE_ALL
 458 
 459         wr      %l0, PSR_ET, %psr               ! re-enable traps
 460         WRITE_PAUSE
 461 
 462         add     %sp, REGWIN_SZ, %o0
 463         mov     %l1, %o1
 464         mov     %l2, %o2
 465         call    C_LABEL(do_fpe_trap)
 466          mov    %l0, %o3
 467 
 468         RESTORE_ALL
 469 
 470         /* This routine handles Tag Overflow Exceptions. */
 471         .align  4
 472         .globl  do_tag_overflow
 473 do_tag_overflow:
 474         SAVE_ALL
 475 
 476         wr      %l0, PSR_ET, %psr               ! re-enable traps
 477         WRITE_PAUSE
 478 
 479         add     %sp, REGWIN_SZ, %o0
 480         mov     %l1, %o1
 481         mov     %l2, %o2
 482         call    C_LABEL(handle_tag_overflow)
 483          mov    %l0, %o3
 484 
 485         RESTORE_ALL
 486 
 487         /* This routine handles Watchpoint Exceptions. */
 488         .align  4
 489         .globl  do_watchpoint
 490 do_watchpoint:
 491         SAVE_ALL
 492 
 493         wr      %l0, PSR_ET, %psr               ! re-enable traps
 494         WRITE_PAUSE
 495 
 496         add     %sp, REGWIN_SZ, %o0
 497         mov     %l1, %o1
 498         mov     %l2, %o2
 499         call    C_LABEL(handle_watchpoint)
 500          mov    %l0, %o3
 501 
 502         RESTORE_ALL
 503 
 504         /* This routine handles Register Access Exceptions. */
 505         .align  4
 506         .globl  do_reg_access
 507 do_reg_access:
 508         SAVE_ALL
 509 
 510         wr      %l0, PSR_ET, %psr               ! re-enable traps
 511         WRITE_PAUSE
 512 
 513         add     %sp, REGWIN_SZ, %o0
 514         mov     %l1, %o1
 515         mov     %l2, %o2
 516         call    C_LABEL(handle_reg_access)
 517          mov    %l0, %o3
 518 
 519         RESTORE_ALL
 520 
 521         /* This routine handles Co-Processor Disabled Exceptions. */
 522         .align  4
 523         .globl  do_cp_disabled
 524 do_cp_disabled:
 525         SAVE_ALL
 526 
 527         wr      %l0, PSR_ET, %psr               ! re-enable traps
 528         WRITE_PAUSE
 529 
 530         add     %sp, REGWIN_SZ, %o0
 531         mov     %l1, %o1
 532         mov     %l2, %o2
 533         call    C_LABEL(handle_cp_disabled)
 534          mov    %l0, %o3
 535 
 536         RESTORE_ALL
 537 
 538         /* This routine handles Unimplemented FLUSH Exceptions. */
 539         .align  4
 540         .globl  do_bad_flush
 541 do_bad_flush:
 542         SAVE_ALL
 543 
 544         wr      %l0, PSR_ET, %psr               ! re-enable traps
 545         WRITE_PAUSE
 546 
 547         add     %sp, REGWIN_SZ, %o0
 548         mov     %l1, %o1
 549         mov     %l2, %o2
 550         call    C_LABEL(handle_bad_flush)
 551          mov    %l0, %o3
 552 
 553         RESTORE_ALL
 554 
 555         /* This routine handles Co-Processor Exceptions. */
 556         .align  4
 557         .globl  do_cp_exception
 558 do_cp_exception:
 559         SAVE_ALL
 560 
 561         wr      %l0, PSR_ET, %psr               ! re-enable traps
 562         WRITE_PAUSE
 563 
 564         add     %sp, REGWIN_SZ, %o0
 565         mov     %l1, %o1
 566         mov     %l2, %o2
 567         call    C_LABEL(handle_cp_exception)
 568          mov    %l0, %o3
 569 
 570         RESTORE_ALL
 571 
 572         /* This routine handles Hardware Divide By Zero Exceptions. */
 573         .align  4
 574         .globl  do_hw_divzero
 575 do_hw_divzero:
 576         SAVE_ALL
 577 
 578         wr      %l0, PSR_ET, %psr               ! re-enable traps
 579         WRITE_PAUSE
 580 
 581         add     %sp, REGWIN_SZ, %o0
 582         mov     %l1, %o1
 583         mov     %l2, %o2
 584         call    C_LABEL(handle_hw_divzero)
 585          mov    %l0, %o3
 586 
 587         RESTORE_ALL
 588 
 589         .align  4
 590         .globl  do_flush_windows
 591 do_flush_windows:
 592         SAVE_ALL
 593 
 594         wr      %l0, PSR_ET, %psr
 595         WRITE_PAUSE
 596 
 597         andcc   %l0, PSR_PS, %g0
 598         bne     dfw_kernel
 599          nop
 600 
 601         call    C_LABEL(flush_user_windows)
 602          nop
 603 
 604         /* Advance over the trap instruction. */
 605         ld      [%sp + REGWIN_SZ + PT_NPC], %l1
 606         add     %l1, 0x4, %l2
 607         st      %l1, [%sp + REGWIN_SZ + PT_PC]
 608         st      %l2, [%sp + REGWIN_SZ + PT_NPC]
 609 
 610         RESTORE_ALL
 611 
 612         /* We get these for debugging routines using __builtin_return_address() */
 613 dfw_kernel:
 614         FLUSH_ALL_KERNEL_WINDOWS
 615         RESTORE_ALL
 616 
 617         /* The getcc software trap.  The user wants the condition codes from
 618          * the %psr in register %g1.
 619          */
 620 
 621         .align  4
 622         .globl  getcc_trap_handler
 623 getcc_trap_handler:
 624         srl     %l0, 20, %g1    ! give user
 625         and     %g1, 0xf, %g1   ! only ICC bits in %psr
 626         jmp     %l2             ! advance over trap instruction
 627         rett    %l2 + 0x4       ! like this...
 628 
 629         /* The setcc software trap.  The user has condition codes in %g1
 630          * that it would like placed in the %psr.  Be careful not to flip
 631          * any unintentional bits!
 632          */
 633 
 634         .align  4
 635         .globl  setcc_trap_handler
 636 setcc_trap_handler:
 637         sll     %g1, 0x14, %l4
 638         set     PSR_ICC, %l5
 639         andn    %l0, %l5, %l0   ! clear ICC bits in current %psr
 640         and     %l4, %l5, %l4   ! clear non-ICC bits in user value
 641         or      %l4, %l0, %l4   ! or them in... mix mix mix
 642 
 643         wr      %l4, 0x0, %psr  ! set new %psr
 644         WRITE_PAUSE             ! TI scumbags...
 645 
 646         jmp     %l2             ! advance over trap instruction
 647         rett    %l2 + 0x4       ! like this...
 648 
 649         .align  4
 650         .globl  linux_trap_nmi_sun4c
 651 linux_trap_nmi_sun4c:
 652         SAVE_ALL
 653 
 654         /* Ugh, we need to clear the IRQ line.  This is now
 655          * a very sun4c specific trap handler...
 656          */
 657         sethi   %hi(C_LABEL(interrupt_enable)), %l5
 658         ld      [%l5 + %lo(C_LABEL(interrupt_enable))], %l5
 659         ldub    [%l5], %l6
 660         andn    %l6, INTS_ENAB, %l6
 661         stb     %l6, [%l5]
 662 
 663         /* Now it is safe to re-enable traps without recursion. */
 664         or      %l0, PSR_PIL, %l0
 665         wr      %l0, PSR_ET, %psr
 666         WRITE_PAUSE
 667 
 668         /* Now call the c-code with the pt_regs frame ptr and the
 669          * memory error registers as arguments.  The ordering chosen
 670          * here is due to unlatching semantics.
 671          */
 672         sethi   %hi(AC_SYNC_ERR), %o0
 673         add     %o0, 0x4, %o0
 674         lda     [%o0] ASI_CONTROL, %o2  ! sync vaddr
 675         sub     %o0, 0x4, %o0
 676         lda     [%o0] ASI_CONTROL, %o1  ! sync error
 677         add     %o0, 0xc, %o0
 678         lda     [%o0] ASI_CONTROL, %o4  ! async vaddr
 679         sub     %o0, 0x4, %o0
 680         lda     [%o0] ASI_CONTROL, %o3  ! async error
 681         call    C_LABEL(sparc_lvl15_nmi)
 682          add    %sp, REGWIN_SZ, %o0
 683 
 684         RESTORE_ALL
 685 
 686 #if 0 /* WIP */
 687         /* Inter-Processor Interrupts on the Sun4m. */
 688         .align  4
 689         .globl  sun4m_ipi
 690 sun4m_ipi:
 691         SAVE_ALL_IPI4M
 692 
 693         set     MAILBOX_ADDRESS, %l4
 694         ldub    [%l4], %l5
 695         subcc   %l5, MBOX_STOPCPU, %g0
 696         bne,a   1f
 697          subcc  %l5, MBOX_STOPCPU2, %g0
 698 
 699         call    C_LABEL(prom_stopcpu)
 700          mov    0, %o0
 701         ba,a    2f      
 702 
 703 1:
 704         bne,a   1f
 705          subcc  %l5, MBOX_IDLECPU, %g0
 706 
 707         call    C_LABEL(prom_stopcpu)
 708          mov    0, %o0
 709         ba,a    2f      
 710 
 711 1:
 712         bne,a   1f
 713          subcc  %l5, MBOX_IDLECPU2, %g0
 714 
 715         call    C_LABEL(prom_idlecpu)
 716          mov    0, %o0
 717         ba,a    2f      
 718 
 719 1:
 720         bne,a   2f
 721          nop
 722 
 723         call    C_LABEL(prom_idlecpu)
 724          mov    0, %o0
 725         ba,a    2f      
 726 
 727 2:
 728         call    C_LABEL(smp_callin)
 729 
 730         RESTORE_ALL_IPI4M
 731 #endif
 732 
 733         .align  4
 734         .globl  sun4c_fault
 735 sun4c_fault:
 736         SAVE_ALL
 737 
 738         /* XXX This needs to be scheduled better */
 739         sethi   %hi(AC_SYNC_ERR), %l4
 740         add     %l4, 0x4, %l5           ! AC_SYNC_VA in %l5
 741         lda     [%l5] ASI_CONTROL, %o3          /* Address */
 742         lda     [%l4] ASI_CONTROL, %l6
 743         srl     %l6, 15, %l6
 744         and     %l6, 1, %o2     /* Write? */
 745 
 746         wr      %l0, PSR_ET, %psr
 747         WRITE_PAUSE
 748 
 749         mov     %l7, %o1                        /* Text fault? */
 750         call    C_LABEL(do_sparc_fault)
 751          add    %sp, REGWIN_SZ, %o0             /* pt_regs */
 752 
 753         RESTORE_ALL
 754 
 755         .align  4
 756         .globl  C_LABEL(srmmu_fault)
 757 C_LABEL(srmmu_fault):
 758         /* Slot 1 */
 759         mov     0x400, %l5
 760         mov     0x300, %l4
 761 
 762         /* Slot 2 */
 763         lda     [%l5] ASI_M_MMUREGS, %l6        ! read sfar first
 764         lda     [%l4] ASI_M_MMUREGS, %l5        ! read sfsr last
 765 
 766         /* Slot 3 */
 767         andn    %l6, 0xfff, %l6
 768         srl     %l5, 6, %l5                     ! and encode all info into l7
 769 
 770         /* Slot 4 */
 771         and     %l5, 2, %l5
 772         or      %l5, %l6, %l6
 773 
 774         /* Slot 5 */
 775         or      %l6, %l7, %l7                   ! l7 = [addr,write,txtfault]
 776 
 777         SAVE_ALL
 778 
 779         mov     %l7, %o1
 780         mov     %l7, %o2
 781         and     %o1, 1, %o1             ! arg2 = text_faultp
 782         mov     %l7, %o3
 783         and     %o2, 2, %o2             ! arg3 = writep
 784         andn    %o3, 0xfff, %o3         ! arg4 = faulting address
 785 
 786         wr      %l0, PSR_ET, %psr
 787         WRITE_PAUSE
 788 
 789         call    C_LABEL(do_sparc_fault)
 790          add    %sp, REGWIN_SZ, %o0     ! arg1 = pt_regs ptr
 791 
 792         RESTORE_ALL
 793 
 794         /* SunOS uses syscall zero as the 'indirect syscall' it looks
 795          * like indir_syscall(scall_num, arg0, arg1, arg2...);  etc.
 796          * This is complete brain damage.
 797          */
 798         .globl  C_LABEL(sunos_indir)
 799 C_LABEL(sunos_indir):
 800         ld      [%sp + REGWIN_SZ + PT_I0], %g1
 801         cmp     %g1, NR_SYSCALLS
 802         blu,a   1f
 803          sll    %g1, 0x2, %g1
 804 
 805         set     C_LABEL(sunos_nosys), %l6
 806         b       2f
 807          nop
 808 
 809 1:
 810         set     C_LABEL(sunos_sys_table), %l7
 811         ld      [%l7 + %g1], %l6
 812 
 813 2:      
 814         ld      [%sp + REGWIN_SZ + PT_I1], %o0
 815         ld      [%sp + REGWIN_SZ + PT_I2], %o1
 816         ld      [%sp + REGWIN_SZ + PT_I3], %o2
 817         ld      [%sp + REGWIN_SZ + PT_I4], %o3
 818         call    %l6
 819          ld     [%sp + REGWIN_SZ + PT_I5], %o4
 820 
 821         b       scall_store_args                /* so stupid... */
 822          nop
 823 
 824 #if 0 /* work in progress */
 825         .align 4
 826         .globl  C_LABEL(sys_ptrace)
 827 C_LABEL(sys_ptrace):
 828         call    C_LABEL(do_ptrace)
 829          add    %sp, REGWIN_SZ, %o0
 830 
 831         RESTORE_ALL
 832 #endif
 833 
 834         .align  4
 835         .globl  C_LABEL(sys_execve)
 836 C_LABEL(sys_execve):
 837         call    C_LABEL(sparc_execve)
 838          add    %sp, REGWIN_SZ, %o0             ! pt_regs *regs arg
 839 
 840         b       scall_store_args
 841          nop
 842 
 843         .align  4
 844         .globl  C_LABEL(sys_pipe)
 845 C_LABEL(sys_pipe):
 846         call    C_LABEL(sparc_pipe)
 847          add    %sp, REGWIN_SZ, %o0             ! pt_regs *regs arg
 848 
 849         b       C_LABEL(ret_sys_call)
 850          nop
 851 
 852         .align  4
 853         .globl  C_LABEL(sys_sigpause)
 854 C_LABEL(sys_sigpause):
 855         ld      [%sp + REGWIN_SZ + PT_I0], %o0
 856         call    C_LABEL(do_sigpause)
 857          add    %sp, REGWIN_SZ, %o1
 858 
 859         /* We are returning to a signal handler. */
 860 
 861         RESTORE_ALL
 862 
 863         .align  4
 864         .globl  C_LABEL(sys_sigsuspend)
 865 C_LABEL(sys_sigsuspend):
 866         ld      [%sp + REGWIN_SZ + PT_I0], %o0
 867         call    C_LABEL(do_sigsuspend)
 868          add    %sp, REGWIN_SZ, %o1
 869 
 870         /* We are returning to a signal handler. */
 871 
 872         RESTORE_ALL
 873 
 874         .align  4
 875         .globl  C_LABEL(sys_sigreturn)
 876 C_LABEL(sys_sigreturn):
 877         call    C_LABEL(do_sigreturn)
 878          add    %sp, REGWIN_SZ, %o0
 879 
 880         /* We don't want to muck with user registers like a
 881          * normal syscall, just return.
 882          */
 883         RESTORE_ALL
 884 
 885         /* Now that we have a real sys_clone, sys_fork() is
 886          * implemented in terms of it.  Our _real_ implementation
 887          * of SunOS vfork() will use sys_clone() instead.
 888          */
 889         .align  4
 890         .globl  C_LABEL(sys_fork), C_LABEL(sys_vfork)
 891 C_LABEL(sys_vfork):
 892 C_LABEL(sys_fork):
 893         /* Save the kernel state as of now. */
 894         FLUSH_ALL_KERNEL_WINDOWS;
 895         STORE_WINDOW(sp)
 896         LOAD_CURRENT(g6, g5)
 897         rd      %psr, %g4
 898         rd      %wim, %g5
 899         std     %g4, [%g6 + THREAD_FORK_KPSR]
 900 
 901         mov     SIGCHLD, %o0                    ! arg0: clone flags
 902         ld      [%sp + REGWIN_SZ + PT_FP], %o1  ! arg1: usp
 903         call    C_LABEL(do_fork)
 904          add    %sp, REGWIN_SZ, %o2             ! arg2: pt_regs ptr
 905 
 906         b       scall_store_args
 907          nop
 908         
 909         /* Whee, kernel threads! */
 910         .globl  C_LABEL(sys_clone)
 911 C_LABEL(sys_clone):
 912         /* Save the kernel state as of now. */
 913         FLUSH_ALL_KERNEL_WINDOWS;
 914         STORE_WINDOW(sp)
 915         LOAD_CURRENT(g6, g5)
 916         rd      %psr, %g4
 917         rd      %wim, %g5
 918         std     %g4, [%g6 + THREAD_FORK_KPSR]
 919 
 920         ldd     [%sp + REGWIN_SZ + PT_I0], %o0  ! arg0,1: flags,usp
 921         cmp     %o1, 0x0                        ! Is new_usp NULL?
 922         be,a    1f
 923          ld     [%sp + REGWIN_SZ + PT_FP], %o1  ! yes, use current usp
 924 1:
 925         call    C_LABEL(do_fork)
 926          add    %sp, REGWIN_SZ, %o2             ! arg2: pt_regs ptr
 927 
 928         b       scall_store_args
 929          nop
 930 
 931         /* All system calls enter here... */
 932         .align  4
 933         .globl  linux_sparc_syscall
 934 linux_sparc_syscall:
 935         /* While we are here trying to optimize our lives
 936          * away, handle the easy bogus cases like a
 937          * ni_syscall or sysnum > NR_SYSCALLS etc.
 938          * In the cases where we cannot optimize the
 939          * call inline we don't really lose anything
 940          * performance wise because we are doing here
 941          * things which we did anyway in the original
 942          * routine.  The only added complexity is a
 943          * bit test, compare, and branch to decide
 944          * if we need to save process state or not.
 945          */
 946 
 947         /* XXX TODO: When we have ptrace working test
 948          * XXX       test for PF_TRACESYS in task flags.
 949          */
 950 
 951         /* Direct access to user regs, must faster. */
 952         cmp     %g1, NR_SYSCALLS
 953         blu,a   1f
 954          sll    %g1, 2, %l4
 955 
 956         b       syscall_is_too_hard
 957          set    C_LABEL(sys_ni_syscall), %l7
 958 
 959 1:
 960         ld      [%l7 + %l4], %l7
 961 
 962         /* If bit-1 is set, this is a "fast" syscall.
 963          * This is the _complete_ overhead of this optimization,
 964          * and we save ourselves a load, so it evens out to nothing.
 965          */
 966         andcc   %l7, 0x1, %g0
 967         be      syscall_is_too_hard
 968          andn   %l7, 0x1, %l7
 969 
 970         jmpl    %l7, %g0
 971          nop
 972 
 973         .globl  syscall_is_too_hard
 974 syscall_is_too_hard:
 975         rd      %wim, %l3
 976         SAVE_ALL
 977 
 978         wr      %l0, PSR_ET, %psr
 979         WRITE_PAUSE
 980 
 981 2:
 982         ldd     [%sp + REGWIN_SZ + PT_I0], %o0
 983         st      %o0, [%sp + REGWIN_SZ + PT_G0]  ! for restarting syscalls
 984         ldd     [%sp + REGWIN_SZ + PT_I2], %o2
 985         call    %l7
 986          ldd    [%sp + REGWIN_SZ + PT_I4], %o4
 987 
 988 scall_store_args:
 989         st      %o0, [%sp + REGWIN_SZ + PT_I0]
 990 
 991         .globl  C_LABEL(ret_sys_call)
 992 C_LABEL(ret_sys_call):
 993         ld      [%sp + REGWIN_SZ + PT_I0], %o0
 994         set     PSR_C, %l6
 995         cmp     %o0, -ENOIOCTLCMD
 996         bgeu    1f
 997          ld     [%sp + REGWIN_SZ + PT_PSR], %l5
 998 
 999         /* System call success, clear Carry condition code. */          
1000         andn    %l5, %l6, %l5
1001         b       2f
1002          st     %l5, [%sp + REGWIN_SZ + PT_PSR] 
1003 
1004 1:
1005         /* System call failure, set Carry condition code.
1006          * Also, get abs(errno) to return to the process.
1007          */
1008         sub     %g0, %o0, %o0
1009         st      %o0, [%sp + REGWIN_SZ + PT_I0]
1010         or      %l5, %l6, %l5
1011         st      %l5, [%sp + REGWIN_SZ + PT_PSR]
1012 
1013         /* Advance the pc and npc over the trap instruction. */
1014 2:
1015         ld      [%sp + REGWIN_SZ + PT_NPC], %l1 /* pc  = npc   */
1016         add     %l1, 0x4, %l2                   /* npc = npc+4 */
1017         st      %l1, [%sp + REGWIN_SZ + PT_PC]
1018         st      %l2, [%sp + REGWIN_SZ + PT_NPC]
1019 
1020         RESTORE_ALL
1021 
1022 /* Saving and restoring the FPU state is best done from lowlevel code.
1023  *
1024  * void fpsave(unsigned long *fpregs, unsigned long *fsr,
1025  *             void *fpqueue, unsigned long *fpqdepth)
1026  */
1027 
1028         .globl  C_LABEL(fpsave)
1029 C_LABEL(fpsave):
1030         st      %fsr, [%o1]
1031         ld      [%o1], %g1
1032         set     0x2000, %g4
1033         andcc   %g1, %g4, %g0
1034         be      2f
1035          mov    0, %g2
1036 
1037         /* We have an fpqueue to save. */
1038 1:
1039         std     %fq, [%o2]
1040 fpsave_magic:
1041         st      %fsr, [%o1]
1042         ld      [%o1], %g3
1043         andcc   %g3, %g4, %g0
1044         add     %g2, 1, %g2
1045         bne     1b
1046          add    %o2, 8, %o2
1047 
1048 2:
1049         st      %g2, [%o3]
1050 
1051         std     %f0, [%o0 + 0x00]
1052         std     %f2, [%o0 + 0x08]
1053         std     %f4, [%o0 + 0x10]
1054         std     %f6, [%o0 + 0x18]
1055         std     %f8, [%o0 + 0x20]
1056         std     %f10, [%o0 + 0x28]
1057         std     %f12, [%o0 + 0x30]
1058         std     %f14, [%o0 + 0x38]
1059         std     %f16, [%o0 + 0x40]
1060         std     %f18, [%o0 + 0x48]
1061         std     %f20, [%o0 + 0x50]
1062         std     %f22, [%o0 + 0x58]
1063         std     %f24, [%o0 + 0x60]
1064         std     %f26, [%o0 + 0x68]
1065         std     %f28, [%o0 + 0x70]
1066         retl
1067          std    %f30, [%o0 + 0x78]
1068 
1069         /* Thanks for Theo Deraadt and the authors of the Sprite/netbsd/openbsd
1070          * code for pointing out this possible deadlock, while we save state
1071          * above we could trap on the fsr store so our low level fpu trap
1072          * code has to know how to deal with this.
1073          */
1074 fpsave_catch:
1075         b       fpsave_magic + 4
1076          st     %fsr, [%o1]
1077 
1078         /* void fpload(unsigned long *fpregs, unsigned long *fsr); */
1079 
1080         .globl  C_LABEL(fpload)
1081 C_LABEL(fpload):
1082         ldd     [%o0 + 0x00], %f0
1083         ldd     [%o0 + 0x08], %f2
1084         ldd     [%o0 + 0x10], %f4
1085         ldd     [%o0 + 0x18], %f6
1086         ldd     [%o0 + 0x20], %f8
1087         ldd     [%o0 + 0x28], %f10
1088         ldd     [%o0 + 0x30], %f12
1089         ldd     [%o0 + 0x38], %f14
1090         ldd     [%o0 + 0x40], %f16
1091         ldd     [%o0 + 0x48], %f18
1092         ldd     [%o0 + 0x50], %f20
1093         ldd     [%o0 + 0x58], %f22
1094         ldd     [%o0 + 0x60], %f24
1095         ldd     [%o0 + 0x68], %f26
1096         ldd     [%o0 + 0x70], %f28
1097         ldd     [%o0 + 0x78], %f30
1098         ld      [%o1], %fsr
1099         retl
1100          nop
1101 
1102         .globl  C_LABEL(udelay)
1103 C_LABEL(udelay):
1104         save    %sp, -REGWIN_SZ, %sp
1105         mov     %i0, %o0
1106         sethi   %hi(0x10c6), %o1
1107         call    .umul
1108          or     %o1, %lo(0x10c6), %o1
1109         sethi   %hi(C_LABEL(loops_per_sec)), %o3
1110         call    .umul
1111          ld     [%o3 + %lo(C_LABEL(loops_per_sec))], %o1
1112 
1113         cmp     %o1, 0x0
1114 1:
1115         bne     1b
1116          subcc  %o1, 1, %o1
1117         
1118         ret
1119         restore
1120 
1121 /* End of entry.S */

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