1/* $Id: entry.S,v 1.170 2001/11/13 00:57:05 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 * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) 6 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) 7 * Copyright (C) 1996-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 8 * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) 9 */ 10 11#include <linux/config.h> 12#include <linux/errno.h> 13 14#include <asm/head.h> 15#include <asm/asi.h> 16#include <asm/smp.h> 17#include <asm/kgdb.h> 18#include <asm/contregs.h> 19#include <asm/ptrace.h> 20#include <asm/psr.h> 21#include <asm/cprefix.h> 22#include <asm/vaddrs.h> 23#include <asm/memreg.h> 24#include <asm/page.h> 25#ifdef CONFIG_SUN4 26#include <asm/pgtsun4.h> 27#else 28#include <asm/pgtsun4c.h> 29#endif 30#include <asm/winmacro.h> 31#include <asm/signal.h> 32#include <asm/obio.h> 33#include <asm/mxcc.h> 34 35#include <asm/asmmacro.h> 36 37#define curptr g6 38 39#define NR_SYSCALLS 256 /* Each OS is different... */ 40 41/* These are just handy. */ 42#define _SV save %sp, -STACKFRAME_SZ, %sp 43#define _RS restore 44 45#define FLUSH_ALL_KERNEL_WINDOWS \ 46 _SV; _SV; _SV; _SV; _SV; _SV; _SV; \ 47 _RS; _RS; _RS; _RS; _RS; _RS; _RS; 48 49/* First, KGDB low level things. This is a rewrite 50 * of the routines found in the sparc-stub.c asm() statement 51 * from the gdb distribution. This is also dual-purpose 52 * as a software trap for userlevel programs. 53 */ 54 .data 55 .align 4 56 57in_trap_handler: 58 .word 0 59 60 .text 61 .align 4 62 63! This function is called when any SPARC trap (except window overflow or 64! underflow) occurs. It makes sure that the invalid register window is still 65! available before jumping into C code. It will also restore the world if you 66! return from handle_exception. 67 68 .globl C_LABEL(trap_low) 69C_LABEL(trap_low): 70 rd %wim, %l3 71 SAVE_ALL 72 73 sethi %hi(in_trap_handler), %l4 74 ld [%lo(in_trap_handler) + %l4], %l5 75 inc %l5 76 st %l5, [%lo(in_trap_handler) + %l4] 77 78 /* Make sure kgdb sees the same state we just saved. */ 79 LOAD_PT_GLOBALS(sp) 80 LOAD_PT_INS(sp) 81 ld [%sp + STACKFRAME_SZ + PT_Y], %l4 82 ld [%sp + STACKFRAME_SZ + PT_WIM], %l3 83 ld [%sp + STACKFRAME_SZ + PT_PSR], %l0 84 ld [%sp + STACKFRAME_SZ + PT_PC], %l1 85 ld [%sp + STACKFRAME_SZ + PT_NPC], %l2 86 rd %tbr, %l5 /* Never changes... */ 87 88 /* Make kgdb exception frame. */ 89 sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals 90 ! + hidden arg + arg spill 91 ! + doubleword alignment 92 ! + registers[72] local var 93 SAVE_KGDB_GLOBALS(sp) 94 SAVE_KGDB_INS(sp) 95 SAVE_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2) 96 97 /* We are increasing PIL, so two writes. */ 98 or %l0, PSR_PIL, %l0 99 wr %l0, 0, %psr 100 WRITE_PAUSE 101 wr %l0, PSR_ET, %psr 102 WRITE_PAUSE 103 104 call C_LABEL(handle_exception) 105 add %sp, STACKFRAME_SZ, %o0 ! Pass address of registers 106 107 /* Load new kgdb register set. */ 108 LOAD_KGDB_GLOBALS(sp) 109 LOAD_KGDB_INS(sp) 110 LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2) 111 wr %l4, 0x0, %y 112 113 sethi %hi(in_trap_handler), %l4 114 ld [%lo(in_trap_handler) + %l4], %l5 115 dec %l5 116 st %l5, [%lo(in_trap_handler) + %l4] 117 118 add %sp,(16+1+6+1+72)*4,%sp ! Undo the kgdb trap frame. 119 120 /* Now take what kgdb did and place it into the pt_regs 121 * frame which SparcLinux RESTORE_ALL understands., 122 */ 123 STORE_PT_INS(sp) 124 STORE_PT_GLOBALS(sp) 125 STORE_PT_YREG(sp, g2) 126 STORE_PT_PRIV(sp, l0, l1, l2) 127 128 RESTORE_ALL 129 130 131#ifdef CONFIG_BLK_DEV_FD 132 .text 133 .align 4 134 .globl C_LABEL(floppy_hardint) 135C_LABEL(floppy_hardint): 136 /* 137 * This code cannot touch registers %l0 %l1 and %l2 138 * because SAVE_ALL depends on their values. It depends 139 * on %l3 also, but we regenerate it before a call. 140 * Other registers are: 141 * %l3 -- base address of fdc registers 142 * %l4 -- pdma_vaddr 143 * %l5 -- scratch for ld/st address 144 * %l6 -- pdma_size 145 * %l7 -- scratch [floppy byte, ld/st address, aux. data] 146 */ 147 148 /* Do we have work to do? */ 149 sethi %hi(C_LABEL(doing_pdma)), %l7 150 ld [%l7 + %lo(C_LABEL(doing_pdma))], %l7 151 cmp %l7, 0 152 be floppy_dosoftint 153 nop 154 155 /* Load fdc register base */ 156 sethi %hi(C_LABEL(fdc_status)), %l3 157 ld [%l3 + %lo(C_LABEL(fdc_status))], %l3 158 159 /* Setup register addresses */ 160 sethi %hi(C_LABEL(pdma_vaddr)), %l5 ! transfer buffer 161 ld [%l5 + %lo(C_LABEL(pdma_vaddr))], %l4 162 sethi %hi(C_LABEL(pdma_size)), %l5 ! bytes to go 163 ld [%l5 + %lo(C_LABEL(pdma_size))], %l6 164next_byte: 165 ldub [%l3], %l7 166 167 andcc %l7, 0x80, %g0 ! Does fifo still have data 168 bz floppy_fifo_emptied ! fifo has been emptied... 169 andcc %l7, 0x20, %g0 ! in non-dma mode still? 170 bz floppy_overrun ! nope, overrun 171 andcc %l7, 0x40, %g0 ! 0=write 1=read 172 bz floppy_write 173 sub %l6, 0x1, %l6 174 175 /* Ok, actually read this byte */ 176 ldub [%l3 + 1], %l7 177 orcc %g0, %l6, %g0 178 stb %l7, [%l4] 179 bne next_byte 180 add %l4, 0x1, %l4 181 182 b floppy_tdone 183 nop 184 185floppy_write: 186 /* Ok, actually write this byte */ 187 ldub [%l4], %l7 188 orcc %g0, %l6, %g0 189 stb %l7, [%l3 + 1] 190 bne next_byte 191 add %l4, 0x1, %l4 192 193 /* fall through... */ 194floppy_tdone: 195 sethi %hi(C_LABEL(pdma_vaddr)), %l5 196 st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] 197 sethi %hi(C_LABEL(pdma_size)), %l5 198 st %l6, [%l5 + %lo(C_LABEL(pdma_size))] 199 /* Flip terminal count pin */ 200 set C_LABEL(auxio_register), %l7 201 ld [%l7], %l7 202 203 set C_LABEL(sparc_cpu_model), %l5 204 ld [%l5], %l5 205 subcc %l5, 1, %g0 /* enum { sun4c = 1 }; */ 206 be 1f 207 ldub [%l7], %l5 208 209 or %l5, 0xc2, %l5 210 stb %l5, [%l7] 211 andn %l5, 0x02, %l5 212 b 2f 213 nop 214 2151: 216 or %l5, 0xf4, %l5 217 stb %l5, [%l7] 218 andn %l5, 0x04, %l5 219 2202: 221 /* Kill some time so the bits set */ 222 WRITE_PAUSE 223 WRITE_PAUSE 224 225 stb %l5, [%l7] 226 227 /* Prevent recursion */ 228 sethi %hi(C_LABEL(doing_pdma)), %l7 229 b floppy_dosoftint 230 st %g0, [%l7 + %lo(C_LABEL(doing_pdma))] 231 232 /* We emptied the FIFO, but we haven't read everything 233 * as of yet. Store the current transfer address and 234 * bytes left to read so we can continue when the next 235 * fast IRQ comes in. 236 */ 237floppy_fifo_emptied: 238 sethi %hi(C_LABEL(pdma_vaddr)), %l5 239 st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] 240 sethi %hi(C_LABEL(pdma_size)), %l7 241 st %l6, [%l7 + %lo(C_LABEL(pdma_size))] 242 243 /* Restore condition codes */ 244 wr %l0, 0x0, %psr 245 WRITE_PAUSE 246 247 jmp %l1 248 rett %l2 249 250floppy_overrun: 251 sethi %hi(C_LABEL(pdma_vaddr)), %l5 252 st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] 253 sethi %hi(C_LABEL(pdma_size)), %l5 254 st %l6, [%l5 + %lo(C_LABEL(pdma_size))] 255 /* Prevent recursion */ 256 sethi %hi(C_LABEL(doing_pdma)), %l7 257 st %g0, [%l7 + %lo(C_LABEL(doing_pdma))] 258 259 /* fall through... */ 260floppy_dosoftint: 261 rd %wim, %l3 262 SAVE_ALL 263 264 /* Set all IRQs off. */ 265 or %l0, PSR_PIL, %l4 266 wr %l4, 0x0, %psr 267 WRITE_PAUSE 268 wr %l4, PSR_ET, %psr 269 WRITE_PAUSE 270 271 mov 11, %o0 ! floppy irq level (unused anyway) 272 mov %g0, %o1 ! devid is not used in fast interrupts 273 call C_LABEL(sparc_floppy_irq) 274 add %sp, STACKFRAME_SZ, %o2 ! struct pt_regs *regs 275 276 RESTORE_ALL 277 278#endif /* (CONFIG_BLK_DEV_FD) */ 279 280 /* Bad trap handler */ 281 .globl bad_trap_handler 282bad_trap_handler: 283 SAVE_ALL 284 285 wr %l0, PSR_ET, %psr 286 WRITE_PAUSE 287 288 mov %l7, %o0 ! trap number 289 mov %l0, %o1 ! psr 290 call C_LABEL(do_hw_interrupt) 291 mov %l1, %o2 ! pc 292 293 RESTORE_ALL 294 295/* For now all IRQ's not registered get sent here. handler_irq() will 296 * see if a routine is registered to handle this interrupt and if not 297 * it will say so on the console. 298 */ 299 300 .align 4 301 .globl real_irq_entry, patch_handler_irq 302real_irq_entry: 303 SAVE_ALL 304 305#ifdef CONFIG_SMP 306 .globl patchme_maybe_smp_msg 307 308 cmp %l7, 12 309patchme_maybe_smp_msg: 310 bgu maybe_smp4m_msg 311 nop 312#endif 313 314real_irq_continue: 315 or %l0, PSR_PIL, %g2 316 wr %g2, 0x0, %psr 317 WRITE_PAUSE 318 wr %g2, PSR_ET, %psr 319 WRITE_PAUSE 320 mov %l7, %o0 ! irq level 321patch_handler_irq: 322 call C_LABEL(handler_irq) 323 add %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr 324 or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq 325 wr %g2, PSR_ET, %psr ! keep ET up 326 WRITE_PAUSE 327 328 RESTORE_ALL 329 330#ifdef CONFIG_SMP 331 /* SMP per-cpu ticker interrupts are handled specially. */ 332smp4m_ticker: 333 bne real_irq_continue+4 334 or %l0, PSR_PIL, %g2 335 wr %g2, 0x0, %psr 336 WRITE_PAUSE 337 wr %g2, PSR_ET, %psr 338 WRITE_PAUSE 339 call C_LABEL(smp4m_percpu_timer_interrupt) 340 add %sp, STACKFRAME_SZ, %o0 341 wr %l0, PSR_ET, %psr 342 WRITE_PAUSE 343 RESTORE_ALL 344 345 /* Here is where we check for possible SMP IPI passed to us 346 * on some level other than 15 which is the NMI and only used 347 * for cross calls. That has a separate entry point below. 348 */ 349maybe_smp4m_msg: 350 GET_PROCESSOR_MID(o3, o2) 351 set C_LABEL(sun4m_interrupts), %l5 352 ld [%l5], %o5 353 sethi %hi(0x60000000), %o4 354 sll %o3, 12, %o3 355 ld [%o5 + %o3], %o1 356 andcc %o1, %o4, %g0 357 be,a smp4m_ticker 358 cmp %l7, 14 359 cmp %l7, 13 360 add %o5, %o3, %o5 361 bne,a 1f 362 sethi %hi(0x40000000), %o2 363 sethi %hi(0x20000000), %o2 3641: 365 st %o2, [%o5 + 0x4] 366 WRITE_PAUSE 367 ld [%o5], %g0 368 WRITE_PAUSE 369 or %l0, PSR_PIL, %l4 370 wr %l4, 0x0, %psr 371 WRITE_PAUSE 372 wr %l4, PSR_ET, %psr 373 WRITE_PAUSE 374 cmp %l7, 13 375 bne 2f 376 nop 377 call C_LABEL(smp_reschedule_irq) 378 add %o7, 8, %o7 3792: 380 call C_LABEL(smp_stop_cpu_irq) 381 nop 382 RESTORE_ALL 383 384 .align 4 385 .globl linux_trap_ipi15_sun4m 386linux_trap_ipi15_sun4m: 387 SAVE_ALL 388 sethi %hi(0x80000000), %o2 389 GET_PROCESSOR_MID(o0, o1) 390 set C_LABEL(sun4m_interrupts), %l5 391 ld [%l5], %o5 392 sll %o0, 12, %o0 393 add %o5, %o0, %o5 394 ld [%o5], %o3 395 andcc %o3, %o2, %g0 396 be 1f ! Must be an NMI async memory error 397 st %o2, [%o5 + 4] 398 WRITE_PAUSE 399 ld [%o5], %g0 400 WRITE_PAUSE 401 or %l0, PSR_PIL, %l4 402 wr %l4, 0x0, %psr 403 WRITE_PAUSE 404 wr %l4, PSR_ET, %psr 405 WRITE_PAUSE 406 call C_LABEL(smp4m_cross_call_irq) 407 nop 408 b ret_trap_lockless_ipi 409 clr %l6 4101: 411 /* NMI async memory error handling. */ 412 sethi %hi(0x80000000), %l4 413 sethi %hi(0x4000), %o3 414 sub %o5, %o0, %o5 415 add %o5, %o3, %l5 416 st %l4, [%l5 + 0xc] 417 WRITE_PAUSE 418 ld [%l5], %g0 419 WRITE_PAUSE 420 or %l0, PSR_PIL, %l4 421 wr %l4, 0x0, %psr 422 WRITE_PAUSE 423 wr %l4, PSR_ET, %psr 424 WRITE_PAUSE 425 call C_LABEL(sun4m_nmi) 426 nop 427 st %l4, [%l5 + 0x8] 428 WRITE_PAUSE 429 ld [%l5], %g0 430 WRITE_PAUSE 431 RESTORE_ALL 432 433 .globl smp4d_ticker 434 /* SMP per-cpu ticker interrupts are handled specially. */ 435smp4d_ticker: 436 SAVE_ALL 437 or %l0, PSR_PIL, %g2 438 sethi %hi(CC_ICLR), %o0 439 sethi %hi(1 << 14), %o1 440 or %o0, %lo(CC_ICLR), %o0 441 stha %o1, [%o0] ASI_M_MXCC /* Clear PIL 14 in MXCC's ICLR */ 442 wr %g2, 0x0, %psr 443 WRITE_PAUSE 444 wr %g2, PSR_ET, %psr 445 WRITE_PAUSE 446 call C_LABEL(smp4d_percpu_timer_interrupt) 447 add %sp, STACKFRAME_SZ, %o0 448 wr %l0, PSR_ET, %psr 449 WRITE_PAUSE 450 RESTORE_ALL 451 452 .align 4 453 .globl linux_trap_ipi15_sun4d 454linux_trap_ipi15_sun4d: 455 SAVE_ALL 456 sethi %hi(CC_BASE), %o4 457 sethi %hi(MXCC_ERR_ME|MXCC_ERR_PEW|MXCC_ERR_ASE|MXCC_ERR_PEE), %o2 458 or %o4, (CC_EREG - CC_BASE), %o0 459 ldda [%o0] ASI_M_MXCC, %o0 460 andcc %o0, %o2, %g0 461 bne 1f 462 sethi %hi(BB_STAT2), %o2 463 lduba [%o2] ASI_M_CTL, %o2 464 andcc %o2, BB_STAT2_MASK, %g0 465 bne 2f 466 or %o4, (CC_ICLR - CC_BASE), %o0 467 sethi %hi(1 << 15), %o1 468 stha %o1, [%o0] ASI_M_MXCC /* Clear PIL 15 in MXCC's ICLR */ 469 or %l0, PSR_PIL, %l4 470 wr %l4, 0x0, %psr 471 WRITE_PAUSE 472 wr %l4, PSR_ET, %psr 473 WRITE_PAUSE 474 call C_LABEL(smp4d_cross_call_irq) 475 nop 476 b ret_trap_lockless_ipi 477 clr %l6 478 4791: /* MXCC error */ 4802: /* BB error */ 481 /* Disable PIL 15 */ 482 set CC_IMSK, %l4 483 lduha [%l4] ASI_M_MXCC, %l5 484 sethi %hi(1 << 15), %l7 485 or %l5, %l7, %l5 486 stha %l5, [%l4] ASI_M_MXCC 487 /* FIXME */ 4881: b,a 1b 489 490#endif /* CONFIG_SMP */ 491 492 /* This routine handles illegal instructions and privileged 493 * instruction attempts from user code. 494 */ 495 .align 4 496 .globl bad_instruction 497bad_instruction: 498 sethi %hi(0xc1f80000), %l4 499 ld [%l1], %l5 500 sethi %hi(0x81d80000), %l7 501 and %l5, %l4, %l5 502 cmp %l5, %l7 503 be 1f 504 SAVE_ALL 505 506 wr %l0, PSR_ET, %psr ! re-enable traps 507 WRITE_PAUSE 508 509 add %sp, STACKFRAME_SZ, %o0 510 mov %l1, %o1 511 mov %l2, %o2 512 call C_LABEL(do_illegal_instruction) 513 mov %l0, %o3 514 515 RESTORE_ALL 516 5171: /* unimplemented flush - just skip */ 518 jmpl %l2, %g0 519 rett %l2 + 4 520 521 .align 4 522 .globl priv_instruction 523priv_instruction: 524 SAVE_ALL 525 526 wr %l0, PSR_ET, %psr 527 WRITE_PAUSE 528 529 add %sp, STACKFRAME_SZ, %o0 530 mov %l1, %o1 531 mov %l2, %o2 532 call C_LABEL(do_priv_instruction) 533 mov %l0, %o3 534 535 RESTORE_ALL 536 537 /* This routine handles unaligned data accesses. */ 538 .align 4 539 .globl mna_handler 540mna_handler: 541 andcc %l0, PSR_PS, %g0 542 be mna_fromuser 543 nop 544 545 SAVE_ALL 546 547 wr %l0, PSR_ET, %psr 548 WRITE_PAUSE 549 550 ld [%l1], %o1 551 call C_LABEL(kernel_unaligned_trap) 552 add %sp, STACKFRAME_SZ, %o0 553 554 RESTORE_ALL 555 556mna_fromuser: 557 SAVE_ALL 558 559 wr %l0, PSR_ET, %psr ! re-enable traps 560 WRITE_PAUSE 561 562 ld [%l1], %o1 563 call C_LABEL(user_unaligned_trap) 564 add %sp, STACKFRAME_SZ, %o0 565 566 RESTORE_ALL 567 568 /* This routine handles floating point disabled traps. */ 569 .align 4 570 .globl fpd_trap_handler 571fpd_trap_handler: 572 SAVE_ALL 573 574 wr %l0, PSR_ET, %psr ! re-enable traps 575 WRITE_PAUSE 576 577 add %sp, STACKFRAME_SZ, %o0 578 mov %l1, %o1 579 mov %l2, %o2 580 call C_LABEL(do_fpd_trap) 581 mov %l0, %o3 582 583 RESTORE_ALL 584 585 /* This routine handles Floating Point Exceptions. */ 586 .align 4 587 .globl fpe_trap_handler 588fpe_trap_handler: 589 set fpsave_magic, %l5 590 cmp %l1, %l5 591 be 1f 592 sethi %hi(C_LABEL(fpsave)), %l5 593 or %l5, %lo(C_LABEL(fpsave)), %l5 594 cmp %l1, %l5 595 bne 2f 596 sethi %hi(fpsave_catch2), %l5 597 or %l5, %lo(fpsave_catch2), %l5 598 wr %l0, 0x0, %psr 599 WRITE_PAUSE 600 jmp %l5 601 rett %l5 + 4 6021: 603 sethi %hi(fpsave_catch), %l5 604 or %l5, %lo(fpsave_catch), %l5 605 wr %l0, 0x0, %psr 606 WRITE_PAUSE 607 jmp %l5 608 rett %l5 + 4 609 6102: 611 SAVE_ALL 612 613 wr %l0, PSR_ET, %psr ! re-enable traps 614 WRITE_PAUSE 615 616 add %sp, STACKFRAME_SZ, %o0 617 mov %l1, %o1 618 mov %l2, %o2 619 call C_LABEL(do_fpe_trap) 620 mov %l0, %o3 621 622 RESTORE_ALL 623 624 /* This routine handles Tag Overflow Exceptions. */ 625 .align 4 626 .globl do_tag_overflow 627do_tag_overflow: 628 SAVE_ALL 629 630 wr %l0, PSR_ET, %psr ! re-enable traps 631 WRITE_PAUSE 632 633 add %sp, STACKFRAME_SZ, %o0 634 mov %l1, %o1 635 mov %l2, %o2 636 call C_LABEL(handle_tag_overflow) 637 mov %l0, %o3 638 639 RESTORE_ALL 640 641 /* This routine handles Watchpoint Exceptions. */ 642 .align 4 643 .globl do_watchpoint 644do_watchpoint: 645 SAVE_ALL 646 647 wr %l0, PSR_ET, %psr ! re-enable traps 648 WRITE_PAUSE 649 650 add %sp, STACKFRAME_SZ, %o0 651 mov %l1, %o1 652 mov %l2, %o2 653 call C_LABEL(handle_watchpoint) 654 mov %l0, %o3 655 656 RESTORE_ALL 657 658 /* This routine handles Register Access Exceptions. */ 659 .align 4 660 .globl do_reg_access 661do_reg_access: 662 SAVE_ALL 663 664 wr %l0, PSR_ET, %psr ! re-enable traps 665 WRITE_PAUSE 666 667 add %sp, STACKFRAME_SZ, %o0 668 mov %l1, %o1 669 mov %l2, %o2 670 call C_LABEL(handle_reg_access) 671 mov %l0, %o3 672 673 RESTORE_ALL 674 675 /* This routine handles Co-Processor Disabled Exceptions. */ 676 .align 4 677 .globl do_cp_disabled 678do_cp_disabled: 679 SAVE_ALL 680 681 wr %l0, PSR_ET, %psr ! re-enable traps 682 WRITE_PAUSE 683 684 add %sp, STACKFRAME_SZ, %o0 685 mov %l1, %o1 686 mov %l2, %o2 687 call C_LABEL(handle_cp_disabled) 688 mov %l0, %o3 689 690 RESTORE_ALL 691 692 /* This routine handles Co-Processor Exceptions. */ 693 .align 4 694 .globl do_cp_exception 695do_cp_exception: 696 SAVE_ALL 697 698 wr %l0, PSR_ET, %psr ! re-enable traps 699 WRITE_PAUSE 700 701 add %sp, STACKFRAME_SZ, %o0 702 mov %l1, %o1 703 mov %l2, %o2 704 call C_LABEL(handle_cp_exception) 705 mov %l0, %o3 706 707 RESTORE_ALL 708 709 /* This routine handles Hardware Divide By Zero Exceptions. */ 710 .align 4 711 .globl do_hw_divzero 712do_hw_divzero: 713 SAVE_ALL 714 715 wr %l0, PSR_ET, %psr ! re-enable traps 716 WRITE_PAUSE 717 718 add %sp, STACKFRAME_SZ, %o0 719 mov %l1, %o1 720 mov %l2, %o2 721 call C_LABEL(handle_hw_divzero) 722 mov %l0, %o3 723 724 RESTORE_ALL 725 726 .align 4 727 .globl do_flush_windows 728do_flush_windows: 729 SAVE_ALL 730 731 wr %l0, PSR_ET, %psr 732 WRITE_PAUSE 733 734 andcc %l0, PSR_PS, %g0 735 bne dfw_kernel 736 nop 737 738 call C_LABEL(flush_user_windows) 739 nop 740 741 /* Advance over the trap instruction. */ 742 ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 743 add %l1, 0x4, %l2 744 st %l1, [%sp + STACKFRAME_SZ + PT_PC] 745 st %l2, [%sp + STACKFRAME_SZ + PT_NPC] 746 747 RESTORE_ALL 748 749 .globl flush_patch_one 750 751 /* We get these for debugging routines using __builtin_return_address() */ 752dfw_kernel: 753flush_patch_one: 754 FLUSH_ALL_KERNEL_WINDOWS 755 756 /* Advance over the trap instruction. */ 757 ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 758 add %l1, 0x4, %l2 759 st %l1, [%sp + STACKFRAME_SZ + PT_PC] 760 st %l2, [%sp + STACKFRAME_SZ + PT_NPC] 761 762 RESTORE_ALL 763 764 /* The getcc software trap. The user wants the condition codes from 765 * the %psr in register %g1. 766 */ 767 768 .align 4 769 .globl getcc_trap_handler 770getcc_trap_handler: 771 srl %l0, 20, %g1 ! give user 772 and %g1, 0xf, %g1 ! only ICC bits in %psr 773 jmp %l2 ! advance over trap instruction 774 rett %l2 + 0x4 ! like this... 775 776 /* The setcc software trap. The user has condition codes in %g1 777 * that it would like placed in the %psr. Be careful not to flip 778 * any unintentional bits! 779 */ 780 781 .align 4 782 .globl setcc_trap_handler 783setcc_trap_handler: 784 sll %g1, 0x14, %l4 785 set PSR_ICC, %l5 786 andn %l0, %l5, %l0 ! clear ICC bits in %psr 787 and %l4, %l5, %l4 ! clear non-ICC bits in user value 788 or %l4, %l0, %l4 ! or them in... mix mix mix 789 790 wr %l4, 0x0, %psr ! set new %psr 791 WRITE_PAUSE ! TI scumbags... 792 793 jmp %l2 ! advance over trap instruction 794 rett %l2 + 0x4 ! like this... 795 796 .align 4 797 .globl linux_trap_nmi_sun4c 798linux_trap_nmi_sun4c: 799 SAVE_ALL 800 801 /* Ugh, we need to clear the IRQ line. This is now 802 * a very sun4c specific trap handler... 803 */ 804 sethi %hi(C_LABEL(interrupt_enable)), %l5 805 ld [%l5 + %lo(C_LABEL(interrupt_enable))], %l5 806 ldub [%l5], %l6 807 andn %l6, INTS_ENAB, %l6 808 stb %l6, [%l5] 809 810 /* Now it is safe to re-enable traps without recursion. */ 811 or %l0, PSR_PIL, %l0 812 wr %l0, PSR_ET, %psr 813 WRITE_PAUSE 814 815 /* Now call the c-code with the pt_regs frame ptr and the 816 * memory error registers as arguments. The ordering chosen 817 * here is due to unlatching semantics. 818 */ 819 sethi %hi(AC_SYNC_ERR), %o0 820 add %o0, 0x4, %o0 821 lda [%o0] ASI_CONTROL, %o2 ! sync vaddr 822 sub %o0, 0x4, %o0 823 lda [%o0] ASI_CONTROL, %o1 ! sync error 824 add %o0, 0xc, %o0 825 lda [%o0] ASI_CONTROL, %o4 ! async vaddr 826 sub %o0, 0x4, %o0 827 lda [%o0] ASI_CONTROL, %o3 ! async error 828 call C_LABEL(sparc_lvl15_nmi) 829 add %sp, STACKFRAME_SZ, %o0 830 831 RESTORE_ALL 832 833 .align 4 834 .globl C_LABEL(invalid_segment_patch1_ff) 835 .globl C_LABEL(invalid_segment_patch2_ff) 836C_LABEL(invalid_segment_patch1_ff): cmp %l4, 0xff 837C_LABEL(invalid_segment_patch2_ff): mov 0xff, %l3 838 839 .align 4 840 .globl C_LABEL(invalid_segment_patch1_1ff) 841 .globl C_LABEL(invalid_segment_patch2_1ff) 842C_LABEL(invalid_segment_patch1_1ff): cmp %l4, 0x1ff 843C_LABEL(invalid_segment_patch2_1ff): mov 0x1ff, %l3 844 845 .align 4 846 .globl C_LABEL(num_context_patch1_16), C_LABEL(num_context_patch2_16) 847C_LABEL(num_context_patch1_16): mov 0x10, %l7 848C_LABEL(num_context_patch2_16): mov 0x10, %l7 849 850 .align 4 851 .globl C_LABEL(vac_linesize_patch_32) 852C_LABEL(vac_linesize_patch_32): subcc %l7, 32, %l7 853 854 .align 4 855 .globl C_LABEL(vac_hwflush_patch1_on), C_LABEL(vac_hwflush_patch2_on) 856 857/* 858 * Ugly, but we cant use hardware flushing on the sun4 and we'd require 859 * two instructions (Anton) 860 */ 861#ifdef CONFIG_SUN4 862C_LABEL(vac_hwflush_patch1_on): nop 863#else 864C_LABEL(vac_hwflush_patch1_on): addcc %l7, -PAGE_SIZE, %l7 865#endif 866 867C_LABEL(vac_hwflush_patch2_on): sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG 868 869 .globl C_LABEL(invalid_segment_patch1), C_LABEL(invalid_segment_patch2) 870 .globl C_LABEL(num_context_patch1), C_LABEL(num_context_patch2) 871 .globl C_LABEL(vac_linesize_patch), C_LABEL(vac_hwflush_patch1) 872 .globl C_LABEL(vac_hwflush_patch2) 873 874 .align 4 875 .globl sun4c_fault 876 877! %l0 = %psr 878! %l1 = %pc 879! %l2 = %npc 880! %l3 = %wim 881! %l7 = 1 for textfault 882! We want error in %l5, vaddr in %l6 883sun4c_fault: 884#ifdef CONFIG_SUN4 885 sethi %hi(C_LABEL(sun4c_memerr_reg)), %l4 886 ld [%l4+%lo(C_LABEL(sun4c_memerr_reg))], %l4 ! memerr ctrl reg addr 887 ld [%l4], %l6 ! memerr ctrl reg 888 ld [%l4 + 4], %l5 ! memerr vaddr reg 889 andcc %l6, 0x80, %g0 ! check for error type 890 st %g0, [%l4 + 4] ! clear the error 891 be 0f ! normal error 892 sethi %hi(AC_BUS_ERROR), %l4 ! bus err reg addr 893 894 call C_LABEL(prom_halt) ! something weird happened 895 ! what exactly did happen? 896 ! what should we do here? 897 8980: or %l4, %lo(AC_BUS_ERROR), %l4 ! bus err reg addr 899 lduba [%l4] ASI_CONTROL, %l6 ! bus err reg 900 901 cmp %l7, 1 ! text fault? 902 be 1f ! yes 903 nop 904 905 ld [%l1], %l4 ! load instruction that caused fault 906 srl %l4, 21, %l4 907 andcc %l4, 1, %g0 ! store instruction? 908 909 be 1f ! no 910 sethi %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep 911 ! %lo(SUN4C_SYNC_BADWRITE) = 0 912 or %l4, %l6, %l6 ! set write bit to emulate sun4c 9131: 914#else 915 sethi %hi(AC_SYNC_ERR), %l4 916 add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6 917 lda [%l6] ASI_CONTROL, %l5 ! Address 918 lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit 919#endif 920 921 andn %l5, 0xfff, %l5 ! Encode all info into l7 922 srl %l6, 14, %l4 923 924 and %l4, 2, %l4 925 or %l5, %l4, %l4 926 927 or %l4, %l7, %l7 ! l7 = [addr,write,txtfault] 928 929 andcc %l0, PSR_PS, %g0 930 be sun4c_fault_fromuser 931 andcc %l7, 1, %g0 ! Text fault? 932 933 be 1f 934 sethi %hi(KERNBASE), %l4 935 936 mov %l1, %l5 ! PC 937 9381: 939 cmp %l5, %l4 940 blu sun4c_fault_fromuser 941 sethi %hi(~((1 << SUN4C_REAL_PGDIR_SHIFT) - 1)), %l4 942 943 /* If the kernel references a bum kernel pointer, or a pte which 944 * points to a non existant page in ram, we will run this code 945 * _forever_ and lock up the machine!!!!! So we must check for 946 * this condition, the AC_SYNC_ERR bits are what we must examine. 947 * Also a parity error would make this happen as well. So we just 948 * check that we are in fact servicing a tlb miss and not some 949 * other type of fault for the kernel. 950 */ 951 andcc %l6, 0x80, %g0 952 be sun4c_fault_fromuser 953 and %l5, %l4, %l5 954 955 /* Test for NULL pte_t * in vmalloc area. */ 956 sethi %hi(VMALLOC_START), %l4 957 cmp %l5, %l4 958 blu,a C_LABEL(invalid_segment_patch1) 959 lduXa [%l5] ASI_SEGMAP, %l4 960 961 sethi %hi(C_LABEL(swapper_pg_dir)), %l4 962 srl %l5, SUN4C_PGDIR_SHIFT, %l6 963 or %l4, %lo(C_LABEL(swapper_pg_dir)), %l4 964 sll %l6, 2, %l6 965 ld [%l4 + %l6], %l4 966#ifdef CONFIG_SUN4 967 sethi %hi(PAGE_MASK), %l6 968 andcc %l4, %l6, %g0 969#else 970 andcc %l4, PAGE_MASK, %g0 971#endif 972 be sun4c_fault_fromuser 973 lduXa [%l5] ASI_SEGMAP, %l4 974 975C_LABEL(invalid_segment_patch1): 976 cmp %l4, 0x7f 977 bne 1f 978 sethi %hi(C_LABEL(sun4c_kfree_ring)), %l4 979 or %l4, %lo(C_LABEL(sun4c_kfree_ring)), %l4 980 ld [%l4 + 0x18], %l3 981 deccc %l3 ! do we have a free entry? 982 bcs,a 2f ! no, unmap one. 983 sethi %hi(C_LABEL(sun4c_kernel_ring)), %l4 984 985 st %l3, [%l4 + 0x18] ! sun4c_kfree_ring.num_entries-- 986 987 ld [%l4 + 0x00], %l6 ! entry = sun4c_kfree_ring.ringhd.next 988 st %l5, [%l6 + 0x08] ! entry->vaddr = address 989 990 ld [%l6 + 0x00], %l3 ! next = entry->next 991 ld [%l6 + 0x04], %l7 ! entry->prev 992 993 st %l7, [%l3 + 0x04] ! next->prev = entry->prev 994 st %l3, [%l7 + 0x00] ! entry->prev->next = next 995 996 sethi %hi(C_LABEL(sun4c_kernel_ring)), %l4 997 or %l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4 998 ! head = &sun4c_kernel_ring.ringhd 999 1000 ld [%l4 + 0x00], %l7 ! head->next 1001 1002 st %l4, [%l6 + 0x04] ! entry->prev = head 1003 st %l7, [%l6 + 0x00] ! entry->next = head->next 1004 st %l6, [%l7 + 0x04] ! head->next->prev = entry 1005 1006 st %l6, [%l4 + 0x00] ! head->next = entry 1007 1008 ld [%l4 + 0x18], %l3 1009 inc %l3 ! sun4c_kernel_ring.num_entries++ 1010 st %l3, [%l4 + 0x18] 1011 b 4f 1012 ld [%l6 + 0x08], %l5 1013 10142: 1015 or %l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4 1016 ! head = &sun4c_kernel_ring.ringhd 1017 1018 ld [%l4 + 0x04], %l6 ! entry = head->prev 1019 1020 ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr 1021 1022 ! Flush segment from the cache. 1023#ifdef CONFIG_SUN4 1024 sethi %hi((128 * 1024)), %l7 1025#else 1026 sethi %hi((64 * 1024)), %l7 1027#endif 10289: 1029C_LABEL(vac_hwflush_patch1): 1030C_LABEL(vac_linesize_patch): 1031 subcc %l7, 16, %l7 1032 bne 9b 1033C_LABEL(vac_hwflush_patch2): 1034 sta %g0, [%l3 + %l7] ASI_FLUSHSEG 1035 1036 st %l5, [%l6 + 0x08] ! entry->vaddr = address 1037 1038 ld [%l6 + 0x00], %l5 ! next = entry->next 1039 ld [%l6 + 0x04], %l7 ! entry->prev 1040 1041 st %l7, [%l5 + 0x04] ! next->prev = entry->prev 1042 st %l5, [%l7 + 0x00] ! entry->prev->next = next 1043 st %l4, [%l6 + 0x04] ! entry->prev = head 1044 1045 ld [%l4 + 0x00], %l7 ! head->next 1046 1047 st %l7, [%l6 + 0x00] ! entry->next = head->next 1048 st %l6, [%l7 + 0x04] ! head->next->prev = entry 1049 st %l6, [%l4 + 0x00] ! head->next = entry 1050 1051 mov %l3, %l5 ! address = tmp 1052 10534: 1054C_LABEL(num_context_patch1): 1055 mov 0x08, %l7 1056 1057 ld [%l6 + 0x08], %l4 1058 ldub [%l6 + 0x0c], %l3 1059 or %l4, %l3, %l4 ! encode new vaddr/pseg into l4 1060 1061 sethi %hi(AC_CONTEXT), %l3 1062 lduba [%l3] ASI_CONTROL, %l6 1063 1064 /* Invalidate old mapping, instantiate new mapping, 1065 * for each context. Registers l6/l7 are live across 1066 * this loop. 1067 */ 10683: deccc %l7 1069 sethi %hi(AC_CONTEXT), %l3 1070 stba %l7, [%l3] ASI_CONTROL 1071C_LABEL(invalid_segment_patch2): 1072 mov 0x7f, %l3 1073 stXa %l3, [%l5] ASI_SEGMAP 1074 andn %l4, 0x1ff, %l3 1075 bne 3b 1076 stXa %l4, [%l3] ASI_SEGMAP 1077 1078 sethi %hi(AC_CONTEXT), %l3 1079 stba %l6, [%l3] ASI_CONTROL 1080 1081 andn %l4, 0x1ff, %l5 1082 10831: 1084 sethi %hi(VMALLOC_START), %l4 1085 cmp %l5, %l4 1086 1087 bgeu 1f 1088 mov 1 << (SUN4C_REAL_PGDIR_SHIFT - PAGE_SHIFT), %l7 1089 1090 sethi %hi(KERNBASE), %l6 1091 1092 sub %l5, %l6, %l4 1093 srl %l4, PAGE_SHIFT, %l4 1094 sethi %hi((SUN4C_PAGE_KERNEL & 0xf4000000)), %l3 1095 or %l3, %l4, %l3 1096 1097 sethi %hi(PAGE_SIZE), %l4 1098 10992: 1100 sta %l3, [%l5] ASI_PTE 1101 deccc %l7 1102 inc %l3 1103 bne 2b 1104 add %l5, %l4, %l5 1105 1106 b 7f 1107 sethi %hi(C_LABEL(sun4c_kernel_faults)), %l4 1108 11091: 1110 srl %l5, SUN4C_PGDIR_SHIFT, %l3 1111 sethi %hi(C_LABEL(swapper_pg_dir)), %l4 1112 or %l4, %lo(C_LABEL(swapper_pg_dir)), %l4 1113 sll %l3, 2, %l3 1114 ld [%l4 + %l3], %l4 1115#ifndef CONFIG_SUN4 1116 and %l4, PAGE_MASK, %l4 1117#else 1118 sethi %hi(PAGE_MASK), %l6 1119 and %l4, %l6, %l4 1120#endif 1121 1122 srl %l5, (PAGE_SHIFT - 2), %l6 1123 and %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6 1124 add %l6, %l4, %l6 1125 1126 sethi %hi(PAGE_SIZE), %l4 1127 11282: 1129 ld [%l6], %l3 1130 deccc %l7 1131 sta %l3, [%l5] ASI_PTE 1132 add %l6, 0x4, %l6 1133 bne 2b 1134 add %l5, %l4, %l5 1135 1136 sethi %hi(C_LABEL(sun4c_kernel_faults)), %l4 11377: 1138 ld [%l4 + %lo(C_LABEL(sun4c_kernel_faults))], %l3 1139 inc %l3 1140 st %l3, [%l4 + %lo(C_LABEL(sun4c_kernel_faults))] 1141 1142 /* Restore condition codes */ 1143 wr %l0, 0x0, %psr 1144 WRITE_PAUSE 1145 jmp %l1 1146 rett %l2 1147 1148sun4c_fault_fromuser: 1149 SAVE_ALL 1150 nop 1151 1152 mov %l7, %o1 ! Decode the info from %l7 1153 mov %l7, %o2 1154 and %o1, 1, %o1 ! arg2 = text_faultp 1155 mov %l7, %o3 1156 and %o2, 2, %o2 ! arg3 = writep 1157 andn %o3, 0xfff, %o3 ! arg4 = faulting address 1158 1159 wr %l0, PSR_ET, %psr 1160 WRITE_PAUSE 1161 1162 call C_LABEL(do_sun4c_fault) 1163 add %sp, STACKFRAME_SZ, %o0 ! arg1 = pt_regs ptr 1164 1165 RESTORE_ALL 1166 1167 .align 4 1168 .globl C_LABEL(srmmu_fault) 1169C_LABEL(srmmu_fault): 1170 mov 0x400, %l5 1171 mov 0x300, %l4 1172 1173 lda [%l5] ASI_M_MMUREGS, %l6 ! read sfar first 1174 lda [%l4] ASI_M_MMUREGS, %l5 ! read sfsr last 1175 1176 andn %l6, 0xfff, %l6 1177 srl %l5, 6, %l5 ! and encode all info into l7 1178 1179 and %l5, 2, %l5 1180 or %l5, %l6, %l6 1181 1182 or %l6, %l7, %l7 ! l7 = [addr,write,txtfault] 1183 1184 SAVE_ALL 1185 1186 mov %l7, %o1 1187 mov %l7, %o2 1188 and %o1, 1, %o1 ! arg2 = text_faultp 1189 mov %l7, %o3 1190 and %o2, 2, %o2 ! arg3 = writep 1191 andn %o3, 0xfff, %o3 ! arg4 = faulting address 1192 1193 wr %l0, PSR_ET, %psr 1194 WRITE_PAUSE 1195 1196 call C_LABEL(do_sparc_fault) 1197 add %sp, STACKFRAME_SZ, %o0 ! arg1 = pt_regs ptr 1198 1199 RESTORE_ALL 1200 1201#ifdef CONFIG_SUNOS_EMUL 1202 /* SunOS uses syscall zero as the 'indirect syscall' it looks 1203 * like indir_syscall(scall_num, arg0, arg1, arg2...); etc. 1204 * This is complete brain damage. 1205 */ 1206 .globl C_LABEL(sunos_indir) 1207C_LABEL(sunos_indir): 1208 mov %o7, %l4 1209 cmp %o0, NR_SYSCALLS 1210 blu,a 1f 1211 sll %o0, 0x2, %o0 1212 1213 sethi %hi(C_LABEL(sunos_nosys)), %l6 1214 b 2f 1215 or %l6, %lo(C_LABEL(sunos_nosys)), %l6 1216 12171: 1218 set C_LABEL(sunos_sys_table), %l7 1219 ld [%l7 + %o0], %l6 1220 12212: 1222 mov %o1, %o0 1223 mov %o2, %o1 1224 mov %o3, %o2 1225 mov %o4, %o3 1226 mov %o5, %o4 1227 call %l6 1228 mov %l4, %o7 1229#endif 1230 1231 .align 4 1232 .globl C_LABEL(sys_nis_syscall) 1233C_LABEL(sys_nis_syscall): 1234 mov %o7, %l5 1235 add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg 1236 call C_LABEL(c_sys_nis_syscall) 1237 mov %l5, %o7 1238 1239 .align 4 1240 .globl C_LABEL(sys_ptrace) 1241C_LABEL(sys_ptrace): 1242 call C_LABEL(do_ptrace) 1243 add %sp, STACKFRAME_SZ, %o0 1244 1245 ld [%curptr + AOFF_task_ptrace], %l5 1246 andcc %l5, 0x02, %g0 1247 be 1f 1248 nop 1249 1250 call C_LABEL(syscall_trace) 1251 nop 1252 12531: 1254 RESTORE_ALL 1255 1256 .align 4 1257 .globl C_LABEL(sys_execve) 1258C_LABEL(sys_execve): 1259 mov %o7, %l5 1260 add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg 1261 call C_LABEL(sparc_execve) 1262 mov %l5, %o7 1263 1264 .align 4 1265 .globl C_LABEL(sys_pipe) 1266C_LABEL(sys_pipe): 1267 mov %o7, %l5 1268 add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg 1269 call C_LABEL(sparc_pipe) 1270 mov %l5, %o7 1271 1272 .align 4 1273 .globl C_LABEL(sys_sigaltstack) 1274C_LABEL(sys_sigaltstack): 1275 mov %o7, %l5 1276 mov %fp, %o2 1277 call C_LABEL(do_sigaltstack) 1278 mov %l5, %o7 1279 1280 .align 4 1281 .globl C_LABEL(sys_sigstack) 1282C_LABEL(sys_sigstack): 1283 mov %o7, %l5 1284 mov %fp, %o2 1285 call C_LABEL(do_sys_sigstack) 1286 mov %l5, %o7 1287 1288 .align 4 1289 .globl C_LABEL(sys_sigpause) 1290C_LABEL(sys_sigpause): 1291 /* Note: %o0 already has correct value... */ 1292 call C_LABEL(do_sigpause) 1293 add %sp, STACKFRAME_SZ, %o1 1294 1295 ld [%curptr + AOFF_task_ptrace], %l5 1296 andcc %l5, 0x02, %g0 1297 be 1f 1298 nop 1299 1300 call C_LABEL(syscall_trace) 1301 nop 1302 13031: 1304 /* We are returning to a signal handler. */ 1305 RESTORE_ALL 1306 1307 .align 4 1308 .globl C_LABEL(sys_sigsuspend) 1309C_LABEL(sys_sigsuspend): 1310 call C_LABEL(do_sigsuspend) 1311 add %sp, STACKFRAME_SZ, %o0 1312 1313 ld [%curptr + AOFF_task_ptrace], %l5 1314 andcc %l5, 0x02, %g0 1315 be 1f 1316 nop 1317 1318 call C_LABEL(syscall_trace) 1319 nop 1320 13211: 1322 /* We are returning to a signal handler. */ 1323 RESTORE_ALL 1324 1325 .align 4 1326 .globl C_LABEL(sys_rt_sigsuspend) 1327C_LABEL(sys_rt_sigsuspend): 1328 /* Note: %o0, %o1 already have correct value... */ 1329 call C_LABEL(do_rt_sigsuspend) 1330 add %sp, STACKFRAME_SZ, %o2 1331 1332 ld [%curptr + AOFF_task_ptrace], %l5 1333 andcc %l5, 0x02, %g0 1334 be 1f 1335 nop 1336 1337 call C_LABEL(syscall_trace) 1338 nop 1339 13401: 1341 /* We are returning to a signal handler. */ 1342 RESTORE_ALL 1343 1344 .align 4 1345 .globl C_LABEL(sys_sigreturn) 1346C_LABEL(sys_sigreturn): 1347 call C_LABEL(do_sigreturn) 1348 add %sp, STACKFRAME_SZ, %o0 1349 1350 ld [%curptr + AOFF_task_ptrace], %l5 1351 andcc %l5, 0x02, %g0 1352 be 1f 1353 nop 1354 1355 call C_LABEL(syscall_trace) 1356 nop 1357 13581: 1359 /* We don't want to muck with user registers like a 1360 * normal syscall, just return. 1361 */ 1362 RESTORE_ALL 1363 1364 .align 4 1365 .globl C_LABEL(sys_rt_sigreturn) 1366C_LABEL(sys_rt_sigreturn): 1367 call C_LABEL(do_rt_sigreturn) 1368 add %sp, STACKFRAME_SZ, %o0 1369 1370 ld [%curptr + AOFF_task_ptrace], %l5 1371 andcc %l5, 0x02, %g0 1372 be 1f 1373 nop 1374 1375 call C_LABEL(syscall_trace) 1376 nop 1377 13781: 1379 /* We are returning to a signal handler. */ 1380 RESTORE_ALL 1381 1382 /* Now that we have a real sys_clone, sys_fork() is 1383 * implemented in terms of it. Our _real_ implementation 1384 * of SunOS vfork() will use sys_vfork(). 1385 * 1386 * XXX These three should be consolidated into mostly shared 1387 * XXX code just like on sparc64... -DaveM 1388 */ 1389 .align 4 1390 .globl C_LABEL(sys_fork), flush_patch_two 1391C_LABEL(sys_fork): 1392 mov %o7, %l5 1393flush_patch_two: 1394 FLUSH_ALL_KERNEL_WINDOWS; 1395 rd %psr, %g4 1396 WRITE_PAUSE 1397 mov SIGCHLD, %o0 ! arg0: clone flags 1398 rd %wim, %g5 1399 WRITE_PAUSE 1400 mov %fp, %o1 ! arg1: usp 1401 std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] 1402 add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr 1403 mov 0, %o3 1404 call C_LABEL(do_fork) 1405 mov %l5, %o7 1406 1407 /* Whee, kernel threads! */ 1408 .globl C_LABEL(sys_clone), flush_patch_three 1409C_LABEL(sys_clone): 1410 mov %o7, %l5 1411flush_patch_three: 1412 FLUSH_ALL_KERNEL_WINDOWS; 1413 rd %psr, %g4 1414 WRITE_PAUSE 1415 1416 /* arg0,1: flags,usp -- loaded already */ 1417 cmp %o1, 0x0 ! Is new_usp NULL? 1418 rd %wim, %g5 1419 WRITE_PAUSE 1420 be,a 1f 1421 mov %fp, %o1 ! yes, use callers usp 1422 andn %o1, 7, %o1 ! no, align to 8 bytes 14231: 1424 std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] 1425 add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr 1426 mov 0, %o3 1427 call C_LABEL(do_fork) 1428 mov %l5, %o7 1429 1430 /* Whee, real vfork! */ 1431 .globl C_LABEL(sys_vfork), flush_patch_four 1432C_LABEL(sys_vfork): 1433flush_patch_four: 1434 FLUSH_ALL_KERNEL_WINDOWS; 1435 rd %psr, %g4 1436 WRITE_PAUSE 1437 rd %wim, %g5 1438 WRITE_PAUSE 1439 std %g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr] 1440 sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 1441 mov %fp, %o1 1442 or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 1443 sethi %hi(C_LABEL(do_fork)), %l1 1444 mov 0, %o3 1445 jmpl %l1 + %lo(C_LABEL(do_fork)), %g0 1446 add %sp, STACKFRAME_SZ, %o2 1447 1448 .align 4 1449linux_sparc_ni_syscall: 1450 sethi %hi(C_LABEL(sys_ni_syscall)), %l7 1451 b syscall_is_too_hard 1452 or %l7, %lo(C_LABEL(sys_ni_syscall)), %l7 1453 1454linux_fast_syscall: 1455 andn %l7, 3, %l7 1456 mov %i0, %o0 1457 mov %i1, %o1 1458 mov %i2, %o2 1459 jmpl %l7 + %g0, %g0 1460 mov %i3, %o3 1461 1462linux_syscall_trace: 1463 call C_LABEL(syscall_trace) 1464 nop 1465 mov %i0, %o0 1466 mov %i1, %o1 1467 mov %i2, %o2 1468 mov %i3, %o3 1469 b 2f 1470 mov %i4, %o4 1471 1472 .globl C_LABEL(ret_from_fork) 1473C_LABEL(ret_from_fork): 1474 call schedule_tail 1475 mov %g3, %o0 1476 b C_LABEL(ret_sys_call) 1477 ld [%sp + STACKFRAME_SZ + PT_I0], %o0 1478 1479 /* Linux native and SunOS system calls enter here... */ 1480 .align 4 1481 .globl linux_sparc_syscall 1482linux_sparc_syscall: 1483 /* Direct access to user regs, must faster. */ 1484 cmp %g1, NR_SYSCALLS 1485 bgeu linux_sparc_ni_syscall 1486 sll %g1, 2, %l4 1487 ld [%l7 + %l4], %l7 1488 andcc %l7, 1, %g0 1489 bne linux_fast_syscall 1490 /* Just do first insn from SAVE_ALL in the delay slot */ 1491 1492 .globl syscall_is_too_hard 1493syscall_is_too_hard: 1494 SAVE_ALL_HEAD 1495 rd %wim, %l3 1496 1497 wr %l0, PSR_ET, %psr 1498 mov %i0, %o0 1499 mov %i1, %o1 1500 mov %i2, %o2 1501 1502 ld [%curptr + AOFF_task_ptrace], %l5 1503 mov %i3, %o3 1504 andcc %l5, 0x02, %g0 1505 mov %i4, %o4 1506 bne linux_syscall_trace 1507 mov %i0, %l5 15082: 1509 call %l7 1510 mov %i5, %o5 1511 1512 st %o0, [%sp + STACKFRAME_SZ + PT_I0] 1513 1514 .globl C_LABEL(ret_sys_call) 1515C_LABEL(ret_sys_call): 1516 ld [%curptr + AOFF_task_ptrace], %l6 1517 cmp %o0, -ENOIOCTLCMD 1518 ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 1519 set PSR_C, %g2 1520 bgeu 1f 1521 andcc %l6, 0x02, %l6 1522 1523 /* System call success, clear Carry condition code. */ 1524 andn %g3, %g2, %g3 1525 clr %l6 1526 st %g3, [%sp + STACKFRAME_SZ + PT_PSR] 1527 bne linux_syscall_trace2 1528 ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ 1529 add %l1, 0x4, %l2 /* npc = npc+4 */ 1530 st %l1, [%sp + STACKFRAME_SZ + PT_PC] 1531 b ret_trap_entry 1532 st %l2, [%sp + STACKFRAME_SZ + PT_NPC] 15331: 1534 /* System call failure, set Carry condition code. 1535 * Also, get abs(errno) to return to the process. 1536 */ 1537 sub %g0, %o0, %o0 1538 or %g3, %g2, %g3 1539 st %o0, [%sp + STACKFRAME_SZ + PT_I0] 1540 mov 1, %l6 1541 st %g3, [%sp + STACKFRAME_SZ + PT_PSR] 1542 bne linux_syscall_trace2 1543 ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ 1544 add %l1, 0x4, %l2 /* npc = npc+4 */ 1545 st %l1, [%sp + STACKFRAME_SZ + PT_PC] 1546 b ret_trap_entry 1547 st %l2, [%sp + STACKFRAME_SZ + PT_NPC] 1548 1549linux_syscall_trace2: 1550 call C_LABEL(syscall_trace) 1551 add %l1, 0x4, %l2 /* npc = npc+4 */ 1552 st %l1, [%sp + STACKFRAME_SZ + PT_PC] 1553 b ret_trap_entry 1554 st %l2, [%sp + STACKFRAME_SZ + PT_NPC] 1555 1556 1557 /* 1558 * Solaris system calls and indirect system calls enter here. 1559 * 1560 * I have named the solaris indirect syscalls like that because 1561 * it seems like Solaris has some fast path syscalls that can 1562 * be handled as indirect system calls. - mig 1563 */ 1564 1565linux_syscall_for_solaris: 1566 sethi %hi(sys_call_table), %l7 1567 b linux_sparc_syscall 1568 or %l7, %lo(sys_call_table), %l7 1569 1570 .align 4 1571 .globl solaris_syscall 1572solaris_syscall: 1573 cmp %g1,59 1574 be linux_syscall_for_solaris 1575 cmp %g1,2 1576 be linux_syscall_for_solaris 1577 cmp %g1,42 1578 be linux_syscall_for_solaris 1579 cmp %g1,119 1580 be,a linux_syscall_for_solaris 1581 mov 2, %g1 15821: 1583 SAVE_ALL_HEAD 1584 rd %wim, %l3 1585 1586 wr %l0, PSR_ET, %psr 1587 nop 1588 nop 1589 mov %i0, %l5 1590 1591 call C_LABEL(do_solaris_syscall) 1592 add %sp, STACKFRAME_SZ, %o0 1593 1594 st %o0, [%sp + STACKFRAME_SZ + PT_I0] 1595 set PSR_C, %g2 1596 cmp %o0, -ENOIOCTLCMD 1597 bgeu 1f 1598 ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 1599 1600 /* System call success, clear Carry condition code. */ 1601 andn %g3, %g2, %g3 1602 clr %l6 1603 b 2f 1604 st %g3, [%sp + STACKFRAME_SZ + PT_PSR] 1605 16061: 1607 /* System call failure, set Carry condition code. 1608 * Also, get abs(errno) to return to the process. 1609 */ 1610 sub %g0, %o0, %o0 1611 mov 1, %l6 1612 st %o0, [%sp + STACKFRAME_SZ + PT_I0] 1613 or %g3, %g2, %g3 1614 st %g3, [%sp + STACKFRAME_SZ + PT_PSR] 1615 1616 /* Advance the pc and npc over the trap instruction. 1617 * If the npc is unaligned (has a 1 in the lower byte), it means 1618 * the kernel does not want us to play magic (ie, skipping over 1619 * traps). Mainly when the Solaris code wants to set some PC and 1620 * nPC (setcontext). 1621 */ 16222: 1623 ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ 1624 andcc %l1, 1, %g0 1625 bne 1f 1626 add %l1, 0x4, %l2 /* npc = npc+4 */ 1627 st %l1, [%sp + STACKFRAME_SZ + PT_PC] 1628 b ret_trap_entry 1629 st %l2, [%sp + STACKFRAME_SZ + PT_NPC] 1630 1631 /* kernel knows what it is doing, fixup npc and continue */ 16321: 1633 sub %l1, 1, %l1 1634 b ret_trap_entry 1635 st %l1, [%sp + STACKFRAME_SZ + PT_NPC] 1636 1637#ifndef CONFIG_SUNOS_EMUL 1638 .align 4 1639 .globl sunos_syscall 1640sunos_syscall: 1641 SAVE_ALL_HEAD 1642 rd %wim, %l3 1643 wr %l0, PSR_ET, %psr 1644 nop 1645 nop 1646 mov %i0, %l5 1647 call C_LABEL(do_sunos_syscall) 1648 add %sp, STACKFRAME_SZ, %o0 1649#endif 1650 1651 /* {net, open}bsd system calls enter here... */ 1652 .align 4 1653 .globl bsd_syscall 1654bsd_syscall: 1655 /* Direct access to user regs, must faster. */ 1656 cmp %g1, NR_SYSCALLS 1657 blu,a 1f 1658 sll %g1, 2, %l4 1659 1660 set C_LABEL(sys_ni_syscall), %l7 1661 b bsd_is_too_hard 1662 nop 1663 16641: 1665 ld [%l7 + %l4], %l7 1666 1667 .globl bsd_is_too_hard 1668bsd_is_too_hard: 1669 rd %wim, %l3 1670 SAVE_ALL 1671 1672 wr %l0, PSR_ET, %psr 1673 WRITE_PAUSE 1674 16752: 1676 mov %i0, %o0 1677 mov %i1, %o1 1678 mov %i2, %o2 1679 mov %i0, %l5 1680 mov %i3, %o3 1681 mov %i4, %o4 1682 call %l7 1683 mov %i5, %o5 1684 1685 st %o0, [%sp + STACKFRAME_SZ + PT_I0] 1686 set PSR_C, %g2 1687 cmp %o0, -ENOIOCTLCMD 1688 bgeu 1f 1689 ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 1690 1691 /* System call success, clear Carry condition code. */ 1692 andn %g3, %g2, %g3 1693 clr %l6 1694 b 2f 1695 st %g3, [%sp + STACKFRAME_SZ + PT_PSR] 1696 16971: 1698 /* System call failure, set Carry condition code. 1699 * Also, get abs(errno) to return to the process. 1700 */ 1701 sub %g0, %o0, %o0 1702#if 0 /* XXX todo XXX */ 1703 sethi %hi(C_LABEL(bsd_xlatb_rorl), %o3 1704 or %o3, %lo(C_LABEL(bsd_xlatb_rorl)), %o3 1705 sll %o0, 2, %o0 1706 ld [%o3 + %o0], %o0 1707#endif 1708 mov 1, %l6 1709 st %o0, [%sp + STACKFRAME_SZ + PT_I0] 1710 or %g3, %g2, %g3 1711 st %g3, [%sp + STACKFRAME_SZ + PT_PSR] 1712 1713 /* Advance the pc and npc over the trap instruction. */ 17142: 1715 ld [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */ 1716 add %l1, 0x4, %l2 /* npc = npc+4 */ 1717 st %l1, [%sp + STACKFRAME_SZ + PT_PC] 1718 b ret_trap_entry 1719 st %l2, [%sp + STACKFRAME_SZ + PT_NPC] 1720 1721/* Saving and restoring the FPU state is best done from lowlevel code. 1722 * 1723 * void fpsave(unsigned long *fpregs, unsigned long *fsr, 1724 * void *fpqueue, unsigned long *fpqdepth) 1725 */ 1726 1727 .globl C_LABEL(fpsave) 1728C_LABEL(fpsave): 1729 st %fsr, [%o1] ! this can trap on us if fpu is in bogon state 1730 ld [%o1], %g1 1731 set 0x2000, %g4 1732 andcc %g1, %g4, %g0 1733 be 2f 1734 mov 0, %g2 1735 1736 /* We have an fpqueue to save. */ 17371: 1738 std %fq, [%o2] 1739fpsave_magic: 1740 st %fsr, [%o1] 1741 ld [%o1], %g3 1742 andcc %g3, %g4, %g0 1743 add %g2, 1, %g2 1744 bne 1b 1745 add %o2, 8, %o2 1746 17472: 1748 st %g2, [%o3] 1749 1750 std %f0, [%o0 + 0x00] 1751 std %f2, [%o0 + 0x08] 1752 std %f4, [%o0 + 0x10] 1753 std %f6, [%o0 + 0x18] 1754 std %f8, [%o0 + 0x20] 1755 std %f10, [%o0 + 0x28] 1756 std %f12, [%o0 + 0x30] 1757 std %f14, [%o0 + 0x38] 1758 std %f16, [%o0 + 0x40] 1759 std %f18, [%o0 + 0x48] 1760 std %f20, [%o0 + 0x50] 1761 std %f22, [%o0 + 0x58] 1762 std %f24, [%o0 + 0x60] 1763 std %f26, [%o0 + 0x68] 1764 std %f28, [%o0 + 0x70] 1765 retl 1766 std %f30, [%o0 + 0x78] 1767 1768 /* Thanks for Theo Deraadt and the authors of the Sprite/netbsd/openbsd 1769 * code for pointing out this possible deadlock, while we save state 1770 * above we could trap on the fsr store so our low level fpu trap 1771 * code has to know how to deal with this. 1772 */ 1773fpsave_catch: 1774 b fpsave_magic + 4 1775 st %fsr, [%o1] 1776 1777fpsave_catch2: 1778 b C_LABEL(fpsave) + 4 1779 st %fsr, [%o1] 1780 1781 /* void fpload(unsigned long *fpregs, unsigned long *fsr); */ 1782 1783 .globl C_LABEL(fpload) 1784C_LABEL(fpload): 1785 ldd [%o0 + 0x00], %f0 1786 ldd [%o0 + 0x08], %f2 1787 ldd [%o0 + 0x10], %f4 1788 ldd [%o0 + 0x18], %f6 1789 ldd [%o0 + 0x20], %f8 1790 ldd [%o0 + 0x28], %f10 1791 ldd [%o0 + 0x30], %f12 1792 ldd [%o0 + 0x38], %f14 1793 ldd [%o0 + 0x40], %f16 1794 ldd [%o0 + 0x48], %f18 1795 ldd [%o0 + 0x50], %f20 1796 ldd [%o0 + 0x58], %f22 1797 ldd [%o0 + 0x60], %f24 1798 ldd [%o0 + 0x68], %f26 1799 ldd [%o0 + 0x70], %f28 1800 ldd [%o0 + 0x78], %f30 1801 ld [%o1], %fsr 1802 retl 1803 nop 1804 1805 .globl C_LABEL(ndelay) 1806C_LABEL(ndelay): 1807 save %sp, -STACKFRAME_SZ, %sp 1808 mov %i0, %o0 1809 call .umul 1810 mov 5, %o1 1811 ba delay_continue 1812 nop 1813 1814 .globl C_LABEL(udelay) 1815C_LABEL(udelay): 1816 save %sp, -STACKFRAME_SZ, %sp 1817 mov %i0, %o0 1818 sethi %hi(0x10c6), %o1 1819 call .umul 1820 or %o1, %lo(0x10c6), %o1 1821delay_continue: 1822#ifndef CONFIG_SMP 1823 sethi %hi(C_LABEL(loops_per_jiffy)), %o3 1824 call .umul 1825 ld [%o3 + %lo(C_LABEL(loops_per_jiffy))], %o1 1826#else 1827 GET_PROCESSOR_OFFSET(o4, o2) 1828 set C_LABEL(cpu_data), %o3 1829 call .umul 1830 ld [%o3 + %o4], %o1 1831#endif 1832 call .umul 1833 mov 100, %o0 1834 1835 cmp %o0, 0x0 18361: 1837 bne 1b 1838 subcc %o0, 1, %o0 1839 1840 ret 1841 restore 1842 1843 /* Handle a software breakpoint */ 1844 /* We have to inform parent that child has stopped */ 1845 .align 4 1846 .globl breakpoint_trap 1847breakpoint_trap: 1848 rd %wim,%l3 1849 SAVE_ALL 1850 wr %l0, PSR_ET, %psr 1851 WRITE_PAUSE 1852 1853 st %i0, [%sp + STACKFRAME_SZ + PT_G0] ! for restarting syscalls 1854 call C_LABEL(sparc_breakpoint) 1855 add %sp, STACKFRAME_SZ, %o0 1856 1857 RESTORE_ALL 1858 1859 .align 4 1860 .globl C_LABEL(__handle_exception), flush_patch_exception 1861C_LABEL(__handle_exception): 1862flush_patch_exception: 1863 FLUSH_ALL_KERNEL_WINDOWS; 1864 ldd [%o0], %o6 1865 jmpl %o7 + 0xc, %g0 ! see asm-sparc/processor.h 1866 mov 1, %g1 ! signal EFAULT condition 1867 1868 .align 4 1869 .globl C_LABEL(kill_user_windows), kuw_patch1_7win 1870 .globl kuw_patch1 1871kuw_patch1_7win: sll %o3, 6, %o3 1872 1873 /* No matter how much overhead this routine has in the worst 1874 * case scenerio, it is several times better than taking the 1875 * traps with the old method of just doing flush_user_windows(). 1876 */ 1877C_LABEL(kill_user_windows): 1878 ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], %o0 ! get current umask 1879 orcc %g0, %o0, %g0 ! if no bits set, we are done 1880 be 3f ! nothing to do 1881 rd %psr, %o5 ! must clear interrupts 1882 or %o5, PSR_PIL, %o4 ! or else that could change 1883 wr %o4, 0x0, %psr ! the uwinmask state 1884 WRITE_PAUSE ! burn them cycles 18851: 1886 ld [%g6 + AOFF_task_thread + AOFF_thread_uwinmask], %o0 ! get consistant state 1887 orcc %g0, %o0, %g0 ! did an interrupt come in? 1888 be 4f ! yep, we are done 1889 rd %wim, %o3 ! get current wim 1890 srl %o3, 1, %o4 ! simulate a save 1891kuw_patch1: 1892 sll %o3, 7, %o3 ! compute next wim 1893 or %o4, %o3, %o3 ! result 1894 andncc %o0, %o3, %o0 ! clean this bit in umask 1895 bne kuw_patch1 ! not done yet 1896 srl %o3, 1, %o4 ! begin another save simulation 1897 wr %o3, 0x0, %wim ! set the new wim 1898 st %g0, [%g6 + AOFF_task_thread + AOFF_thread_uwinmask] ! clear uwinmask 18994: 1900 wr %o5, 0x0, %psr ! re-enable interrupts 1901 WRITE_PAUSE ! burn baby burn 19023: 1903 retl ! return 1904 st %g0, [%g6 + AOFF_task_thread + AOFF_thread_w_saved] ! no windows saved 1905 1906 .align 4 1907 .globl C_LABEL(restore_current) 1908C_LABEL(restore_current): 1909 LOAD_CURRENT(g6, o0) 1910 retl 1911 nop 1912 1913#ifdef CONFIG_PCI 1914#include <asm/pcic.h> 1915 1916 .align 4 1917 .globl linux_trap_ipi15_pcic 1918linux_trap_ipi15_pcic: 1919 rd %wim, %l3 1920 SAVE_ALL 1921 1922 /* 1923 * First deactivate NMI 1924 * or we cannot drop ET, cannot get window spill traps. 1925 * The busy loop is necessary because the PIO error 1926 * sometimes does not go away quickly and we trap again. 1927 */ 1928 sethi %hi(C_LABEL(pcic_regs)), %o1 1929 ld [%o1 + %lo(C_LABEL(pcic_regs))], %o2 1930 1931 ! Get pending status for printouts later. 1932 ld [%o2 + PCI_SYS_INT_PENDING], %o0 1933 1934 mov PCI_SYS_INT_PENDING_CLEAR_ALL, %o1 1935 stb %o1, [%o2 + PCI_SYS_INT_PENDING_CLEAR] 19361: 1937 ld [%o2 + PCI_SYS_INT_PENDING], %o1 1938 andcc %o1, ((PCI_SYS_INT_PENDING_PIO|PCI_SYS_INT_PENDING_PCI)>>24), %g0 1939 bne 1b 1940 nop 1941 1942 or %l0, PSR_PIL, %l4 1943 wr %l4, 0x0, %psr 1944 WRITE_PAUSE 1945 wr %l4, PSR_ET, %psr 1946 WRITE_PAUSE 1947 1948 call C_LABEL(pcic_nmi) 1949 add %sp, STACKFRAME_SZ, %o1 ! struct pt_regs *regs 1950 RESTORE_ALL 1951 1952 .globl C_LABEL(pcic_nmi_trap_patch) 1953C_LABEL(pcic_nmi_trap_patch): 1954 sethi %hi(linux_trap_ipi15_pcic), %l3 1955 jmpl %l3 + %lo(linux_trap_ipi15_pcic), %g0 1956 rd %psr, %l0 1957 .word 0 1958 1959#endif /* CONFIG_PCI */ 1960 1961/* End of entry.S */ 1962