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