1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * General assembly language routines. 28 * It is the intent of this file to contain routines that are 29 * independent of the specific kernel architecture, and those that are 30 * common across kernel architectures. 31 * As architectures diverge, and implementations of specific 32 * architecture-dependent routines change, the routines should be moved 33 * from this file into the respective ../`arch -k`/subr.s file. 34 * Or, if you want to be really nice, move them to a file whose 35 * name has something to do with the routine you are moving. 36 */ 37 38 #if defined(lint) 39 #include <sys/types.h> 40 #include <sys/scb.h> 41 #include <sys/systm.h> 42 #include <sys/regset.h> 43 #include <sys/sunddi.h> 44 #include <sys/lockstat.h> 45 #include <sys/dtrace.h> 46 #include <sys/ftrace.h> 47 #endif /* lint */ 48 49 #include <sys/asm_linkage.h> 50 #include <sys/privregs.h> 51 #include <sys/machparam.h> /* To get SYSBASE and PAGESIZE */ 52 #include <sys/machthread.h> 53 #include <sys/clock.h> 54 #include <sys/psr_compat.h> 55 #include <sys/isa_defs.h> 56 #include <sys/dditypes.h> 57 #include <sys/panic.h> 58 #include <sys/machlock.h> 59 #include <sys/ontrap.h> 60 61 #if !defined(lint) 62 #include "assym.h" 63 64 .seg ".text" 65 .align 4 66 67 /* 68 * Macro to raise processor priority level. 69 * Avoid dropping processor priority if already at high level. 70 * Also avoid going below CPU->cpu_base_spl, which could've just been set by 71 * a higher-level interrupt thread that just blocked. 72 * 73 * level can be %o0 (not other regs used here) or a constant. 74 */ 75 #define RAISE(level) \ 76 rdpr %pil, %o1; /* get current PIL */ \ 77 cmp %o1, level; /* is PIL high enough? */ \ 78 bge 1f; /* yes, return */ \ 79 nop; \ 80 wrpr %g0, PIL_MAX, %pil; /* freeze CPU_BASE_SPL */ \ 81 ldn [THREAD_REG + T_CPU], %o2; \ 82 ld [%o2 + CPU_BASE_SPL], %o2; \ 83 cmp %o2, level; /* compare new to base */ \ 84 movl %xcc, level, %o2; /* use new if base lower */ \ 85 wrpr %g0, %o2, %pil; \ 86 1: \ 87 retl; \ 88 mov %o1, %o0 /* return old PIL */ 89 90 /* 91 * Macro to raise processor priority level to level >= DISP_LEVEL. 92 * Doesn't require comparison to CPU->cpu_base_spl. 93 * 94 * newpil can be %o0 (not other regs used here) or a constant. 95 */ 96 #define RAISE_HIGH(level) \ 97 rdpr %pil, %o1; /* get current PIL */ \ 98 cmp %o1, level; /* is PIL high enough? */ \ 99 bge 1f; /* yes, return */ \ 100 nop; \ 101 wrpr %g0, level, %pil; /* use chose value */ \ 102 1: \ 103 retl; \ 104 mov %o1, %o0 /* return old PIL */ 105 106 /* 107 * Macro to set the priority to a specified level. 108 * Avoid dropping the priority below CPU->cpu_base_spl. 109 * 110 * newpil can be %o0 (not other regs used here) or a constant with 111 * the new PIL in the PSR_PIL field of the level arg. 112 */ 113 #define SETPRI(level) \ 114 rdpr %pil, %o1; /* get current PIL */ \ 115 wrpr %g0, PIL_MAX, %pil; /* freeze CPU_BASE_SPL */ \ 116 ldn [THREAD_REG + T_CPU], %o2; \ 117 ld [%o2 + CPU_BASE_SPL], %o2; \ 118 cmp %o2, level; /* compare new to base */ \ 119 movl %xcc, level, %o2; /* use new if base lower */ \ 120 wrpr %g0, %o2, %pil; \ 121 retl; \ 122 mov %o1, %o0 /* return old PIL */ 123 124 /* 125 * Macro to set the priority to a specified level at or above LOCK_LEVEL. 126 * Doesn't require comparison to CPU->cpu_base_spl. 127 * 128 * newpil can be %o0 (not other regs used here) or a constant with 129 * the new PIL in the PSR_PIL field of the level arg. 130 */ 131 #define SETPRI_HIGH(level) \ 132 rdpr %pil, %o1; /* get current PIL */ \ 133 wrpr %g0, level, %pil; \ 134 retl; \ 135 mov %o1, %o0 /* return old PIL */ 136 137 #endif /* lint */ 138 139 /* 140 * Berkley 4.3 introduced symbolically named interrupt levels 141 * as a way deal with priority in a machine independent fashion. 142 * Numbered priorities are machine specific, and should be 143 * discouraged where possible. 144 * 145 * Note, for the machine specific priorities there are 146 * examples listed for devices that use a particular priority. 147 * It should not be construed that all devices of that 148 * type should be at that priority. It is currently were 149 * the current devices fit into the priority scheme based 150 * upon time criticalness. 151 * 152 * The underlying assumption of these assignments is that 153 * SPARC9 IPL 10 is the highest level from which a device 154 * routine can call wakeup. Devices that interrupt from higher 155 * levels are restricted in what they can do. If they need 156 * kernels services they should schedule a routine at a lower 157 * level (via software interrupt) to do the required 158 * processing. 159 * 160 * Examples of this higher usage: 161 * Level Usage 162 * 15 Asynchronous memory exceptions 163 * 14 Profiling clock (and PROM uart polling clock) 164 * 13 Audio device 165 * 12 Serial ports 166 * 11 Floppy controller 167 * 168 * The serial ports request lower level processing on level 6. 169 * Audio and floppy request lower level processing on level 4. 170 * 171 * Also, almost all splN routines (where N is a number or a 172 * mnemonic) will do a RAISE(), on the assumption that they are 173 * never used to lower our priority. 174 * The exceptions are: 175 * spl8() Because you can't be above 15 to begin with! 176 * splzs() Because this is used at boot time to lower our 177 * priority, to allow the PROM to poll the uart. 178 * spl0() Used to lower priority to 0. 179 */ 180 181 #if defined(lint) 182 183 int spl0(void) { return (0); } 184 int spl6(void) { return (0); } 185 int spl7(void) { return (0); } 186 int spl8(void) { return (0); } 187 int splhi(void) { return (0); } 188 int splhigh(void) { return (0); } 189 int splzs(void) { return (0); } 190 191 #else /* lint */ 192 193 /* locks out all interrupts, including memory errors */ 194 ENTRY(spl8) 195 SETPRI_HIGH(15) 196 SET_SIZE(spl8) 197 198 /* just below the level that profiling runs */ 199 ENTRY(spl7) 200 RAISE_HIGH(13) 201 SET_SIZE(spl7) 202 203 /* sun specific - highest priority onboard serial i/o zs ports */ 204 ENTRY(splzs) 205 SETPRI_HIGH(12) /* Can't be a RAISE, as it's used to lower us */ 206 SET_SIZE(splzs) 207 208 /* 209 * should lock out clocks and all interrupts, 210 * as you can see, there are exceptions 211 */ 212 ENTRY(splhi) 213 ALTENTRY(splhigh) 214 ALTENTRY(spl6) 215 ALTENTRY(i_ddi_splhigh) 216 RAISE_HIGH(DISP_LEVEL) 217 SET_SIZE(i_ddi_splhigh) 218 SET_SIZE(spl6) 219 SET_SIZE(splhigh) 220 SET_SIZE(splhi) 221 222 /* allow all interrupts */ 223 ENTRY(spl0) 224 SETPRI(0) 225 SET_SIZE(spl0) 226 227 #endif /* lint */ 228 229 /* 230 * splx - set PIL back to that indicated by the old %pil passed as an argument, 231 * or to the CPU's base priority, whichever is higher. 232 */ 233 234 #if defined(lint) 235 236 /* ARGSUSED */ 237 void 238 splx(int level) 239 {} 240 241 #else /* lint */ 242 243 ENTRY(splx) 244 ALTENTRY(i_ddi_splx) 245 SETPRI(%o0) /* set PIL */ 246 SET_SIZE(i_ddi_splx) 247 SET_SIZE(splx) 248 249 #endif /* level */ 250 251 /* 252 * splr() 253 * 254 * splr is like splx but will only raise the priority and never drop it 255 * Be careful not to set priority lower than CPU->cpu_base_pri, 256 * even though it seems we're raising the priority, it could be set higher 257 * at any time by an interrupt routine, so we must block interrupts and 258 * look at CPU->cpu_base_pri. 259 */ 260 261 #if defined(lint) 262 263 /* ARGSUSED */ 264 int 265 splr(int level) 266 { return (0); } 267 268 #else /* lint */ 269 ENTRY(splr) 270 RAISE(%o0) 271 SET_SIZE(splr) 272 273 #endif /* lint */ 274 275 /* 276 * on_fault() 277 * Catch lofault faults. Like setjmp except it returns one 278 * if code following causes uncorrectable fault. Turned off 279 * by calling no_fault(). 280 */ 281 282 #if defined(lint) 283 284 /* ARGSUSED */ 285 int 286 on_fault(label_t *ljb) 287 { return (0); } 288 289 #else /* lint */ 290 291 ENTRY(on_fault) 292 membar #Sync ! sync error barrier (see copy.s) 293 stn %o0, [THREAD_REG + T_ONFAULT] 294 set catch_fault, %o1 295 b setjmp ! let setjmp do the rest 296 stn %o1, [THREAD_REG + T_LOFAULT] ! put catch_fault in t_lofault 297 298 catch_fault: 299 save %sp, -SA(WINDOWSIZE), %sp ! goto next window so that we can rtn 300 ldn [THREAD_REG + T_ONFAULT], %o0 301 membar #Sync ! sync error barrier 302 stn %g0, [THREAD_REG + T_ONFAULT] ! turn off onfault 303 b longjmp ! let longjmp do the rest 304 stn %g0, [THREAD_REG + T_LOFAULT] ! turn off lofault 305 SET_SIZE(on_fault) 306 307 #endif /* lint */ 308 309 /* 310 * no_fault() 311 * turn off fault catching. 312 */ 313 314 #if defined(lint) 315 316 void 317 no_fault(void) 318 {} 319 320 #else /* lint */ 321 322 ENTRY(no_fault) 323 membar #Sync ! sync error barrier 324 stn %g0, [THREAD_REG + T_ONFAULT] 325 retl 326 stn %g0, [THREAD_REG + T_LOFAULT] ! turn off lofault 327 SET_SIZE(no_fault) 328 329 #endif /* lint */ 330 331 /* 332 * Default trampoline code for on_trap() (see <sys/ontrap.h>). On sparcv9, 333 * the trap code will complete trap processing but reset the return %pc to 334 * ot_trampoline, which will by default be set to the address of this code. 335 * We longjmp(&curthread->t_ontrap->ot_jmpbuf) to return back to on_trap(). 336 */ 337 #if defined(lint) 338 339 void 340 on_trap_trampoline(void) 341 {} 342 343 #else /* lint */ 344 345 ENTRY(on_trap_trampoline) 346 ldn [THREAD_REG + T_ONTRAP], %o0 347 b longjmp 348 add %o0, OT_JMPBUF, %o0 349 SET_SIZE(on_trap_trampoline) 350 351 #endif /* lint */ 352 353 /* 354 * Push a new element on to the t_ontrap stack. Refer to <sys/ontrap.h> for 355 * more information about the on_trap() mechanism. If the on_trap_data is the 356 * same as the topmost stack element, we just modify that element. 357 * On UltraSPARC, we need to issue a membar #Sync before modifying t_ontrap. 358 * The issue barrier is defined to force all deferred errors to complete before 359 * we go any further. We want these errors to be processed before we modify 360 * our current error protection. 361 */ 362 #if defined(lint) 363 364 /*ARGSUSED*/ 365 int 366 on_trap(on_trap_data_t *otp, uint_t prot) 367 { return (0); } 368 369 #else /* lint */ 370 371 ENTRY(on_trap) 372 membar #Sync ! force error barrier 373 sth %o1, [%o0 + OT_PROT] ! ot_prot = prot 374 sth %g0, [%o0 + OT_TRAP] ! ot_trap = 0 375 set on_trap_trampoline, %o2 ! %o2 = &on_trap_trampoline 376 stn %o2, [%o0 + OT_TRAMPOLINE] ! ot_trampoline = %o2 377 stn %g0, [%o0 + OT_HANDLE] ! ot_handle = NULL 378 ldn [THREAD_REG + T_ONTRAP], %o2 ! %o2 = curthread->t_ontrap 379 cmp %o0, %o2 ! if (otp == %o2) 380 be 0f ! don't modify t_ontrap 381 stn %g0, [%o0 + OT_PAD1] ! delay - ot_pad1 = NULL 382 383 stn %o2, [%o0 + OT_PREV] ! ot_prev = t_ontrap 384 membar #Sync ! force error barrier 385 stn %o0, [THREAD_REG + T_ONTRAP] ! t_ontrap = otp 386 387 0: b setjmp ! let setjmp do the rest 388 add %o0, OT_JMPBUF, %o0 ! %o0 = &ot_jmpbuf 389 SET_SIZE(on_trap) 390 391 #endif /* lint */ 392 393 /* 394 * Setjmp and longjmp implement non-local gotos using state vectors 395 * type label_t. 396 */ 397 398 #if defined(lint) 399 400 /* ARGSUSED */ 401 int 402 setjmp(label_t *lp) 403 { return (0); } 404 405 #else /* lint */ 406 407 ENTRY(setjmp) 408 stn %o7, [%o0 + L_PC] ! save return address 409 stn %sp, [%o0 + L_SP] ! save stack ptr 410 retl 411 clr %o0 ! return 0 412 SET_SIZE(setjmp) 413 414 #endif /* lint */ 415 416 417 #if defined(lint) 418 419 /* ARGSUSED */ 420 void 421 longjmp(label_t *lp) 422 {} 423 424 #else /* lint */ 425 426 ENTRY(longjmp) 427 ! 428 ! The following save is required so that an extra register 429 ! window is flushed. Flushw flushes nwindows-2 430 ! register windows. If setjmp and longjmp are called from 431 ! within the same window, that window will not get pushed 432 ! out onto the stack without the extra save below. Tail call 433 ! optimization can lead to callers of longjmp executing 434 ! from a window that could be the same as the setjmp, 435 ! thus the need for the following save. 436 ! 437 save %sp, -SA(MINFRAME), %sp 438 flushw ! flush all but this window 439 ldn [%i0 + L_PC], %i7 ! restore return addr 440 ldn [%i0 + L_SP], %fp ! restore sp for dest on foreign stack 441 ret ! return 1 442 restore %g0, 1, %o0 ! takes underflow, switches stacks 443 SET_SIZE(longjmp) 444 445 #endif /* lint */ 446 447 /* 448 * movtuc(length, from, to, table) 449 * 450 * VAX movtuc instruction (sort of). 451 */ 452 453 #if defined(lint) 454 455 /*ARGSUSED*/ 456 int 457 movtuc(size_t length, u_char *from, u_char *to, u_char table[]) 458 { return (0); } 459 460 #else /* lint */ 461 462 ENTRY(movtuc) 463 tst %o0 464 ble,pn %ncc, 2f ! check length 465 clr %o4 466 467 ldub [%o1 + %o4], %g1 ! get next byte in string 468 0: 469 ldub [%o3 + %g1], %g1 ! get corresponding table entry 470 tst %g1 ! escape char? 471 bnz 1f 472 stb %g1, [%o2 + %o4] ! delay slot, store it 473 474 retl ! return (bytes moved) 475 mov %o4, %o0 476 1: 477 inc %o4 ! increment index 478 cmp %o4, %o0 ! index < length ? 479 bl,a,pt %ncc, 0b 480 ldub [%o1 + %o4], %g1 ! delay slot, get next byte in string 481 2: 482 retl ! return (bytes moved) 483 mov %o4, %o0 484 SET_SIZE(movtuc) 485 486 #endif /* lint */ 487 488 /* 489 * scanc(length, string, table, mask) 490 * 491 * VAX scanc instruction. 492 */ 493 494 #if defined(lint) 495 496 /*ARGSUSED*/ 497 int 498 scanc(size_t length, u_char *string, u_char table[], u_char mask) 499 { return (0); } 500 501 #else /* lint */ 502 503 ENTRY(scanc) 504 tst %o0 505 ble,pn %ncc, 1f ! check length 506 clr %o4 507 0: 508 ldub [%o1 + %o4], %g1 ! get next byte in string 509 cmp %o4, %o0 ! interlock slot, index < length ? 510 ldub [%o2 + %g1], %g1 ! get corresponding table entry 511 bge,pn %ncc, 1f ! interlock slot 512 btst %o3, %g1 ! apply the mask 513 bz,a 0b 514 inc %o4 ! delay slot, increment index 515 1: 516 retl ! return(length - index) 517 sub %o0, %o4, %o0 518 SET_SIZE(scanc) 519 520 #endif /* lint */ 521 522 /* 523 * if a() calls b() calls caller(), 524 * caller() returns return address in a(). 525 */ 526 527 #if defined(lint) 528 529 caddr_t 530 caller(void) 531 { return (0); } 532 533 #else /* lint */ 534 535 ENTRY(caller) 536 retl 537 mov %i7, %o0 538 SET_SIZE(caller) 539 540 #endif /* lint */ 541 542 /* 543 * if a() calls callee(), callee() returns the 544 * return address in a(); 545 */ 546 547 #if defined(lint) 548 549 caddr_t 550 callee(void) 551 { return (0); } 552 553 #else /* lint */ 554 555 ENTRY(callee) 556 retl 557 mov %o7, %o0 558 SET_SIZE(callee) 559 560 #endif /* lint */ 561 562 /* 563 * return the current frame pointer 564 */ 565 566 #if defined(lint) 567 568 greg_t 569 getfp(void) 570 { return (0); } 571 572 #else /* lint */ 573 574 ENTRY(getfp) 575 retl 576 mov %fp, %o0 577 SET_SIZE(getfp) 578 579 #endif /* lint */ 580 581 /* 582 * Get vector base register 583 */ 584 585 #if defined(lint) 586 587 greg_t 588 gettbr(void) 589 { return (0); } 590 591 #else /* lint */ 592 593 ENTRY(gettbr) 594 retl 595 mov %tbr, %o0 596 SET_SIZE(gettbr) 597 598 #endif /* lint */ 599 600 /* 601 * Get processor state register, V9 faked to look like V8. 602 * Note: does not provide ccr.xcc and provides FPRS.FEF instead of 603 * PSTATE.PEF, because PSTATE.PEF is always on in order to allow the 604 * libc_psr memcpy routines to run without hitting the fp_disabled trap. 605 */ 606 607 #if defined(lint) 608 609 greg_t 610 getpsr(void) 611 { return (0); } 612 613 #else /* lint */ 614 615 ENTRY(getpsr) 616 rd %ccr, %o1 ! get ccr 617 sll %o1, PSR_ICC_SHIFT, %o0 ! move icc to V8 psr.icc 618 rd %fprs, %o1 ! get fprs 619 and %o1, FPRS_FEF, %o1 ! mask out dirty upper/lower 620 sllx %o1, PSR_FPRS_FEF_SHIFT, %o1 ! shift fef to V8 psr.ef 621 or %o0, %o1, %o0 ! or into psr.ef 622 set V9_PSR_IMPLVER, %o1 ! SI assigned impl/ver: 0xef 623 retl 624 or %o0, %o1, %o0 ! or into psr.impl/ver 625 SET_SIZE(getpsr) 626 627 #endif /* lint */ 628 629 /* 630 * Get current processor interrupt level 631 */ 632 633 #if defined(lint) 634 635 u_int 636 getpil(void) 637 { return (0); } 638 639 #else /* lint */ 640 641 ENTRY(getpil) 642 retl 643 rdpr %pil, %o0 644 SET_SIZE(getpil) 645 646 #endif /* lint */ 647 648 #if defined(lint) 649 650 /*ARGSUSED*/ 651 void 652 setpil(u_int pil) 653 {} 654 655 #else /* lint */ 656 657 ENTRY(setpil) 658 retl 659 wrpr %g0, %o0, %pil 660 SET_SIZE(setpil) 661 662 #endif /* lint */ 663 664 665 /* 666 * _insque(entryp, predp) 667 * 668 * Insert entryp after predp in a doubly linked list. 669 */ 670 671 #if defined(lint) 672 673 /*ARGSUSED*/ 674 void 675 _insque(caddr_t entryp, caddr_t predp) 676 {} 677 678 #else /* lint */ 679 680 ENTRY(_insque) 681 ldn [%o1], %g1 ! predp->forw 682 stn %o1, [%o0 + CPTRSIZE] ! entryp->back = predp 683 stn %g1, [%o0] ! entryp->forw = predp->forw 684 stn %o0, [%o1] ! predp->forw = entryp 685 retl 686 stn %o0, [%g1 + CPTRSIZE] ! predp->forw->back = entryp 687 SET_SIZE(_insque) 688 689 #endif /* lint */ 690 691 /* 692 * _remque(entryp) 693 * 694 * Remove entryp from a doubly linked list 695 */ 696 697 #if defined(lint) 698 699 /*ARGSUSED*/ 700 void 701 _remque(caddr_t entryp) 702 {} 703 704 #else /* lint */ 705 706 ENTRY(_remque) 707 ldn [%o0], %g1 ! entryp->forw 708 ldn [%o0 + CPTRSIZE], %g2 ! entryp->back 709 stn %g1, [%g2] ! entryp->back->forw = entryp->forw 710 retl 711 stn %g2, [%g1 + CPTRSIZE] ! entryp->forw->back = entryp->back 712 SET_SIZE(_remque) 713 714 #endif /* lint */ 715 716 717 /* 718 * strlen(str) 719 * 720 * Returns the number of non-NULL bytes in string argument. 721 * 722 * XXX - why is this here, rather than the traditional file? 723 * why does it have local labels which don't start with a `.'? 724 */ 725 726 #if defined(lint) 727 728 /*ARGSUSED*/ 729 size_t 730 strlen(const char *str) 731 { return (0); } 732 733 #else /* lint */ 734 735 ENTRY(strlen) 736 mov %o0, %o1 737 andcc %o1, 3, %o3 ! is src word aligned 738 bz $nowalgnd 739 clr %o0 ! length of non-zero bytes 740 cmp %o3, 2 ! is src half-word aligned 741 be $s2algn 742 cmp %o3, 3 ! src is byte aligned 743 ldub [%o1], %o3 ! move 1 or 3 bytes to align it 744 inc 1, %o1 ! in either case, safe to do a byte 745 be $s3algn 746 tst %o3 747 $s1algn: 748 bnz,a $s2algn ! now go align dest 749 inc 1, %o0 750 b,a $done 751 752 $s2algn: 753 lduh [%o1], %o3 ! know src is half-byte aligned 754 inc 2, %o1 755 srl %o3, 8, %o4 756 tst %o4 ! is the first byte zero 757 bnz,a 1f 758 inc %o0 759 b,a $done 760 1: andcc %o3, 0xff, %o3 ! is the second byte zero 761 bnz,a $nowalgnd 762 inc %o0 763 b,a $done 764 $s3algn: 765 bnz,a $nowalgnd 766 inc 1, %o0 767 b,a $done 768 769 $nowalgnd: 770 ! use trick to check if any read bytes of a word are zero 771 ! the following two constants will generate "byte carries" 772 ! and check if any bit in a byte is set, if all characters 773 ! are 7bits (unsigned) this allways works, otherwise 774 ! there is a specil case that rarely happens, see below 775 776 set 0x7efefeff, %o3 777 set 0x81010100, %o4 778 779 3: ld [%o1], %o2 ! main loop 780 inc 4, %o1 781 add %o2, %o3, %o5 ! generate byte-carries 782 xor %o5, %o2, %o5 ! see if orignal bits set 783 and %o5, %o4, %o5 784 cmp %o5, %o4 ! if ==, no zero bytes 785 be,a 3b 786 inc 4, %o0 787 788 ! check for the zero byte and increment the count appropriately 789 ! some information (the carry bit) is lost if bit 31 790 ! was set (very rare), if this is the rare condition, 791 ! return to the main loop again 792 793 sethi %hi(0xff000000), %o5 ! mask used to test for terminator 794 andcc %o2, %o5, %g0 ! check if first byte was zero 795 bnz 1f 796 srl %o5, 8, %o5 797 $done: 798 retl 799 nop 800 1: andcc %o2, %o5, %g0 ! check if second byte was zero 801 bnz 1f 802 srl %o5, 8, %o5 803 $done1: 804 retl 805 inc %o0 806 1: andcc %o2, %o5, %g0 ! check if third byte was zero 807 bnz 1f 808 andcc %o2, 0xff, %g0 ! check if last byte is zero 809 $done2: 810 retl 811 inc 2, %o0 812 1: bnz,a 3b 813 inc 4, %o0 ! count of bytes 814 $done3: 815 retl 816 inc 3, %o0 817 SET_SIZE(strlen) 818 819 #endif /* lint */ 820 821 /* 822 * Provide a C callable interface to the membar instruction. 823 */ 824 825 #if defined(lint) 826 827 void 828 membar_ldld(void) 829 {} 830 831 void 832 membar_stld(void) 833 {} 834 835 void 836 membar_ldst(void) 837 {} 838 839 void 840 membar_stst(void) 841 {} 842 843 void 844 membar_ldld_ldst(void) 845 {} 846 847 void 848 membar_ldld_stld(void) 849 {} 850 851 void 852 membar_ldld_stst(void) 853 {} 854 855 void 856 membar_stld_ldld(void) 857 {} 858 859 void 860 membar_stld_ldst(void) 861 {} 862 863 void 864 membar_stld_stst(void) 865 {} 866 867 void 868 membar_ldst_ldld(void) 869 {} 870 871 void 872 membar_ldst_stld(void) 873 {} 874 875 void 876 membar_ldst_stst(void) 877 {} 878 879 void 880 membar_stst_ldld(void) 881 {} 882 883 void 884 membar_stst_stld(void) 885 {} 886 887 void 888 membar_stst_ldst(void) 889 {} 890 891 void 892 membar_lookaside(void) 893 {} 894 895 void 896 membar_memissue(void) 897 {} 898 899 void 900 membar_sync(void) 901 {} 902 903 #else 904 ENTRY(membar_ldld) 905 retl 906 membar #LoadLoad 907 SET_SIZE(membar_ldld) 908 909 ENTRY(membar_stld) 910 retl 911 membar #StoreLoad 912 SET_SIZE(membar_stld) 913 914 ENTRY(membar_ldst) 915 retl 916 membar #LoadStore 917 SET_SIZE(membar_ldst) 918 919 ENTRY(membar_stst) 920 retl 921 membar #StoreStore 922 SET_SIZE(membar_stst) 923 924 ENTRY(membar_ldld_stld) 925 ALTENTRY(membar_stld_ldld) 926 retl 927 membar #LoadLoad|#StoreLoad 928 SET_SIZE(membar_stld_ldld) 929 SET_SIZE(membar_ldld_stld) 930 931 ENTRY(membar_ldld_ldst) 932 ALTENTRY(membar_ldst_ldld) 933 retl 934 membar #LoadLoad|#LoadStore 935 SET_SIZE(membar_ldst_ldld) 936 SET_SIZE(membar_ldld_ldst) 937 938 ENTRY(membar_ldld_stst) 939 ALTENTRY(membar_stst_ldld) 940 retl 941 membar #LoadLoad|#StoreStore 942 SET_SIZE(membar_stst_ldld) 943 SET_SIZE(membar_ldld_stst) 944 945 ENTRY(membar_stld_ldst) 946 ALTENTRY(membar_ldst_stld) 947 retl 948 membar #StoreLoad|#LoadStore 949 SET_SIZE(membar_ldst_stld) 950 SET_SIZE(membar_stld_ldst) 951 952 ENTRY(membar_stld_stst) 953 ALTENTRY(membar_stst_stld) 954 retl 955 membar #StoreLoad|#StoreStore 956 SET_SIZE(membar_stst_stld) 957 SET_SIZE(membar_stld_stst) 958 959 ENTRY(membar_ldst_stst) 960 ALTENTRY(membar_stst_ldst) 961 retl 962 membar #LoadStore|#StoreStore 963 SET_SIZE(membar_stst_ldst) 964 SET_SIZE(membar_ldst_stst) 965 966 ENTRY(membar_lookaside) 967 retl 968 membar #Lookaside 969 SET_SIZE(membar_lookaside) 970 971 ENTRY(membar_memissue) 972 retl 973 membar #MemIssue 974 SET_SIZE(membar_memissue) 975 976 ENTRY(membar_sync) 977 retl 978 membar #Sync 979 SET_SIZE(membar_sync) 980 981 #endif /* lint */ 982 983 984 #if defined(lint) 985 986 /*ARGSUSED*/ 987 int 988 fuword64(const void *addr, uint64_t *dst) 989 { return (0); } 990 991 /*ARGSUSED*/ 992 int 993 fuword32(const void *addr, uint32_t *dst) 994 { return (0); } 995 996 /*ARGSUSED*/ 997 int 998 fuword16(const void *addr, uint16_t *dst) 999 { return (0); } 1000 1001 /*ARGSUSED*/ 1002 int 1003 fuword8(const void *addr, uint8_t *dst) 1004 { return (0); } 1005 1006 /*ARGSUSED*/ 1007 int 1008 dtrace_ft_fuword64(const void *addr, uint64_t *dst) 1009 { return (0); } 1010 1011 /*ARGSUSED*/ 1012 int 1013 dtrace_ft_fuword32(const void *addr, uint32_t *dst) 1014 { return (0); } 1015 1016 #else /* lint */ 1017 1018 /* 1019 * Since all of the fuword() variants are so similar, we have a macro to spit 1020 * them out. 1021 */ 1022 1023 #define FUWORD(NAME, LOAD, STORE, COPYOP) \ 1024 ENTRY(NAME); \ 1025 sethi %hi(1f), %o5; \ 1026 ldn [THREAD_REG + T_LOFAULT], %o3; \ 1027 or %o5, %lo(1f), %o5; \ 1028 membar #Sync; \ 1029 stn %o5, [THREAD_REG + T_LOFAULT]; \ 1030 LOAD [%o0]ASI_USER, %o2; \ 1031 membar #Sync; \ 1032 stn %o3, [THREAD_REG + T_LOFAULT]; \ 1033 mov 0, %o0; \ 1034 retl; \ 1035 STORE %o2, [%o1]; \ 1036 1: \ 1037 membar #Sync; \ 1038 stn %o3, [THREAD_REG + T_LOFAULT]; \ 1039 ldn [THREAD_REG + T_COPYOPS], %o2; \ 1040 brz %o2, 2f; \ 1041 nop; \ 1042 ldn [%o2 + COPYOP], %g1; \ 1043 jmp %g1; \ 1044 nop; \ 1045 2: \ 1046 retl; \ 1047 mov -1, %o0; \ 1048 SET_SIZE(NAME) 1049 1050 FUWORD(fuword64, ldxa, stx, CP_FUWORD64) 1051 FUWORD(fuword32, lda, st, CP_FUWORD32) 1052 FUWORD(fuword16, lduha, sth, CP_FUWORD16) 1053 FUWORD(fuword8, lduba, stb, CP_FUWORD8) 1054 1055 #endif /* lint */ 1056 1057 1058 #if defined(lint) 1059 1060 /*ARGSUSED*/ 1061 int 1062 suword64(void *addr, uint64_t value) 1063 { return (0); } 1064 1065 /*ARGSUSED*/ 1066 int 1067 suword32(void *addr, uint32_t value) 1068 { return (0); } 1069 1070 /*ARGSUSED*/ 1071 int 1072 suword16(void *addr, uint16_t value) 1073 { return (0); } 1074 1075 /*ARGSUSED*/ 1076 int 1077 suword8(void *addr, uint8_t value) 1078 { return (0); } 1079 1080 #else /* lint */ 1081 1082 /* 1083 * Since all of the suword() variants are so similar, we have a macro to spit 1084 * them out. 1085 */ 1086 1087 #define SUWORD(NAME, STORE, COPYOP) \ 1088 ENTRY(NAME) \ 1089 sethi %hi(1f), %o5; \ 1090 ldn [THREAD_REG + T_LOFAULT], %o3; \ 1091 or %o5, %lo(1f), %o5; \ 1092 membar #Sync; \ 1093 stn %o5, [THREAD_REG + T_LOFAULT]; \ 1094 STORE %o1, [%o0]ASI_USER; \ 1095 membar #Sync; \ 1096 stn %o3, [THREAD_REG + T_LOFAULT]; \ 1097 retl; \ 1098 clr %o0; \ 1099 1: \ 1100 membar #Sync; \ 1101 stn %o3, [THREAD_REG + T_LOFAULT]; \ 1102 ldn [THREAD_REG + T_COPYOPS], %o2; \ 1103 brz %o2, 2f; \ 1104 nop; \ 1105 ldn [%o2 + COPYOP], %g1; \ 1106 jmp %g1; \ 1107 nop; \ 1108 2: \ 1109 retl; \ 1110 mov -1, %o0; \ 1111 SET_SIZE(NAME) 1112 1113 SUWORD(suword64, stxa, CP_SUWORD64) 1114 SUWORD(suword32, sta, CP_SUWORD32) 1115 SUWORD(suword16, stha, CP_SUWORD16) 1116 SUWORD(suword8, stba, CP_SUWORD8) 1117 1118 #endif /* lint */ 1119 1120 #if defined(lint) 1121 1122 /*ARGSUSED*/ 1123 void 1124 fuword8_noerr(const void *addr, uint8_t *dst) 1125 {} 1126 1127 /*ARGSUSED*/ 1128 void 1129 fuword16_noerr(const void *addr, uint16_t *dst) 1130 {} 1131 1132 /*ARGSUSED*/ 1133 void 1134 fuword32_noerr(const void *addr, uint32_t *dst) 1135 {} 1136 1137 /*ARGSUSED*/ 1138 void 1139 fuword64_noerr(const void *addr, uint64_t *dst) 1140 {} 1141 1142 #else /* lint */ 1143 1144 ENTRY(fuword8_noerr) 1145 lduba [%o0]ASI_USER, %o0 1146 retl 1147 stb %o0, [%o1] 1148 SET_SIZE(fuword8_noerr) 1149 1150 ENTRY(fuword16_noerr) 1151 lduha [%o0]ASI_USER, %o0 1152 retl 1153 sth %o0, [%o1] 1154 SET_SIZE(fuword16_noerr) 1155 1156 ENTRY(fuword32_noerr) 1157 lda [%o0]ASI_USER, %o0 1158 retl 1159 st %o0, [%o1] 1160 SET_SIZE(fuword32_noerr) 1161 1162 ENTRY(fuword64_noerr) 1163 ldxa [%o0]ASI_USER, %o0 1164 retl 1165 stx %o0, [%o1] 1166 SET_SIZE(fuword64_noerr) 1167 1168 #endif /* lint */ 1169 1170 #if defined(lint) 1171 1172 /*ARGSUSED*/ 1173 void 1174 suword8_noerr(void *addr, uint8_t value) 1175 {} 1176 1177 /*ARGSUSED*/ 1178 void 1179 suword16_noerr(void *addr, uint16_t value) 1180 {} 1181 1182 /*ARGSUSED*/ 1183 void 1184 suword32_noerr(void *addr, uint32_t value) 1185 {} 1186 1187 /*ARGSUSED*/ 1188 void 1189 suword64_noerr(void *addr, uint64_t value) 1190 {} 1191 1192 #else /* lint */ 1193 1194 ENTRY(suword8_noerr) 1195 retl 1196 stba %o1, [%o0]ASI_USER 1197 SET_SIZE(suword8_noerr) 1198 1199 ENTRY(suword16_noerr) 1200 retl 1201 stha %o1, [%o0]ASI_USER 1202 SET_SIZE(suword16_noerr) 1203 1204 ENTRY(suword32_noerr) 1205 retl 1206 sta %o1, [%o0]ASI_USER 1207 SET_SIZE(suword32_noerr) 1208 1209 ENTRY(suword64_noerr) 1210 retl 1211 stxa %o1, [%o0]ASI_USER 1212 SET_SIZE(suword64_noerr) 1213 1214 #endif /* lint */ 1215 1216 #if defined(__lint) 1217 1218 /*ARGSUSED*/ 1219 int 1220 subyte(void *addr, uchar_t value) 1221 { return (0); } 1222 1223 /*ARGSUSED*/ 1224 void 1225 subyte_noerr(void *addr, uchar_t value) 1226 {} 1227 1228 /*ARGSUSED*/ 1229 int 1230 fulword(const void *addr, ulong_t *valuep) 1231 { return (0); } 1232 1233 /*ARGSUSED*/ 1234 void 1235 fulword_noerr(const void *addr, ulong_t *valuep) 1236 {} 1237 1238 /*ARGSUSED*/ 1239 int 1240 sulword(void *addr, ulong_t valuep) 1241 { return (0); } 1242 1243 /*ARGSUSED*/ 1244 void 1245 sulword_noerr(void *addr, ulong_t valuep) 1246 {} 1247 1248 #else 1249 1250 .weak subyte 1251 subyte=suword8 1252 .weak subyte_noerr 1253 subyte_noerr=suword8_noerr 1254 #ifdef _LP64 1255 .weak fulword 1256 fulword=fuword64 1257 .weak fulword_noerr 1258 fulword_noerr=fuword64_noerr 1259 .weak sulword 1260 sulword=suword64 1261 .weak sulword_noerr 1262 sulword_noerr=suword64_noerr 1263 #else 1264 .weak fulword 1265 fulword=fuword32 1266 .weak fulword_noerr 1267 fulword_noerr=fuword32_noerr 1268 .weak sulword 1269 sulword=suword32 1270 .weak sulword_noerr 1271 sulword_noerr=suword32_noerr 1272 #endif /* LP64 */ 1273 1274 #endif /* lint */ 1275 1276 /* 1277 * We define rdtick here, but not for sun4v. On sun4v systems, the %tick 1278 * and %stick should not be read directly without considering the tick 1279 * and stick offset kernel variables introduced to support sun4v OS 1280 * suspension. 1281 */ 1282 #if !defined (sun4v) 1283 1284 #if defined (lint) 1285 1286 hrtime_t 1287 rdtick() 1288 { return (0); } 1289 1290 #else /* lint */ 1291 1292 ENTRY(rdtick) 1293 retl 1294 rd %tick, %o0 1295 SET_SIZE(rdtick) 1296 1297 #endif /* lint */ 1298 1299 #endif /* !sun4v */ 1300 1301 /* 1302 * Set tba to given address, no side effects. 1303 */ 1304 #if defined (lint) 1305 1306 /*ARGSUSED*/ 1307 void * 1308 set_tba(void *new_tba) 1309 { return (0); } 1310 1311 #else /* lint */ 1312 1313 ENTRY(set_tba) 1314 mov %o0, %o1 1315 rdpr %tba, %o0 1316 wrpr %o1, %tba 1317 retl 1318 nop 1319 SET_SIZE(set_tba) 1320 1321 #endif /* lint */ 1322 1323 #if defined (lint) 1324 1325 /*ARGSUSED*/ 1326 void * 1327 get_tba() 1328 { return (0); } 1329 1330 #else /* lint */ 1331 1332 ENTRY(get_tba) 1333 retl 1334 rdpr %tba, %o0 1335 SET_SIZE(get_tba) 1336 1337 #endif /* lint */ 1338 1339 #if defined(lint) || defined(__lint) 1340 1341 /* ARGSUSED */ 1342 void 1343 setpstate(u_int pstate) 1344 {} 1345 1346 #else /* lint */ 1347 1348 ENTRY_NP(setpstate) 1349 retl 1350 wrpr %g0, %o0, %pstate 1351 SET_SIZE(setpstate) 1352 1353 #endif /* lint */ 1354 1355 #if defined(lint) || defined(__lint) 1356 1357 u_int 1358 getpstate(void) 1359 { return(0); } 1360 1361 #else /* lint */ 1362 1363 ENTRY_NP(getpstate) 1364 retl 1365 rdpr %pstate, %o0 1366 SET_SIZE(getpstate) 1367 1368 #endif /* lint */ 1369 1370 #if defined(lint) || defined(__lint) 1371 1372 dtrace_icookie_t 1373 dtrace_interrupt_disable(void) 1374 { return (0); } 1375 1376 #else /* lint */ 1377 1378 ENTRY_NP(dtrace_interrupt_disable) 1379 rdpr %pstate, %o0 1380 andn %o0, PSTATE_IE, %o1 1381 retl 1382 wrpr %g0, %o1, %pstate 1383 SET_SIZE(dtrace_interrupt_disable) 1384 1385 #endif /* lint */ 1386 1387 #if defined(lint) || defined(__lint) 1388 1389 /*ARGSUSED*/ 1390 void 1391 dtrace_interrupt_enable(dtrace_icookie_t cookie) 1392 {} 1393 1394 #else 1395 1396 ENTRY_NP(dtrace_interrupt_enable) 1397 retl 1398 wrpr %g0, %o0, %pstate 1399 SET_SIZE(dtrace_interrupt_enable) 1400 1401 #endif /* lint*/ 1402 1403 #if defined(lint) 1404 1405 void 1406 dtrace_membar_producer(void) 1407 {} 1408 1409 void 1410 dtrace_membar_consumer(void) 1411 {} 1412 1413 #else /* lint */ 1414 1415 #ifdef SF_ERRATA_51 1416 .align 32 1417 ENTRY(dtrace_membar_return) 1418 retl 1419 nop 1420 SET_SIZE(dtrace_membar_return) 1421 #define DTRACE_MEMBAR_RETURN ba,pt %icc, dtrace_membar_return 1422 #else 1423 #define DTRACE_MEMBAR_RETURN retl 1424 #endif 1425 1426 ENTRY(dtrace_membar_producer) 1427 DTRACE_MEMBAR_RETURN 1428 membar #StoreStore 1429 SET_SIZE(dtrace_membar_producer) 1430 1431 ENTRY(dtrace_membar_consumer) 1432 DTRACE_MEMBAR_RETURN 1433 membar #LoadLoad 1434 SET_SIZE(dtrace_membar_consumer) 1435 1436 #endif /* lint */ 1437 1438 #if defined(lint) || defined(__lint) 1439 1440 void 1441 dtrace_flush_windows(void) 1442 {} 1443 1444 #else 1445 1446 ENTRY_NP(dtrace_flush_windows) 1447 retl 1448 flushw 1449 SET_SIZE(dtrace_flush_windows) 1450 1451 #endif /* lint */ 1452 1453 #if defined(lint) 1454 1455 /*ARGSUSED*/ 1456 int 1457 getpcstack_top(pc_t *pcstack, int limit, uintptr_t *lastfp, pc_t *lastpc) 1458 { 1459 return (0); 1460 } 1461 1462 #else /* lint */ 1463 1464 /* 1465 * %g1 pcstack 1466 * %g2 iteration count 1467 * %g3 final %fp 1468 * %g4 final %i7 1469 * %g5 saved %cwp (so we can get back to the original window) 1470 * 1471 * %o0 pcstack / return value (iteration count) 1472 * %o1 limit / saved %cansave 1473 * %o2 lastfp 1474 * %o3 lastpc 1475 * %o4 saved %canrestore 1476 * %o5 saved %pstate (to restore interrupts) 1477 * 1478 * Note: The frame pointer returned via lastfp is safe to use as 1479 * long as getpcstack_top() returns either (0) or a value less 1480 * than (limit). 1481 */ 1482 ENTRY_NP(getpcstack_top) 1483 1484 rdpr %pstate, %o5 1485 andn %o5, PSTATE_IE, %g1 1486 wrpr %g0, %g1, %pstate ! disable interrupts 1487 1488 mov %o0, %g1 ! we need the pcstack pointer while 1489 ! we're visiting other windows 1490 1491 rdpr %canrestore, %g2 ! number of available windows 1492 sub %g2, 1, %g2 ! account for skipped frame 1493 cmp %g2, %o1 ! compare with limit 1494 movg %icc, %o1, %g2 ! %g2 = min(%canrestore-1, limit) 1495 1496 brlez,a,pn %g2, 3f ! Use slow path if count <= 0 -- 1497 clr %o0 ! return zero. 1498 1499 mov %g2, %o0 ! set up return value 1500 1501 rdpr %cwp, %g5 ! remember the register window state 1502 rdpr %cansave, %o1 ! 'restore' changes, so we can undo 1503 rdpr %canrestore, %o4 ! its effects when we finish. 1504 1505 restore ! skip caller's frame 1506 1: 1507 st %i7, [%g1] ! stash return address in pcstack 1508 restore ! go to the next frame 1509 subcc %g2, 1, %g2 ! decrement the count 1510 bnz,pt %icc, 1b ! loop until count reaches 0 1511 add %g1, 4, %g1 ! increment pcstack 1512 1513 mov %i6, %g3 ! copy the final %fp and return PC 1514 mov %i7, %g4 ! aside so we can return them to our 1515 ! caller 1516 1517 wrpr %g0, %g5, %cwp ! jump back to the original window 1518 wrpr %g0, %o1, %cansave ! and restore the original register 1519 wrpr %g0, %o4, %canrestore ! window state. 1520 2: 1521 stn %g3, [%o2] ! store the frame pointer and pc 1522 st %g4, [%o3] ! so our caller can continue the trace 1523 1524 retl ! return to caller 1525 wrpr %g0, %o5, %pstate ! restore interrupts 1526 1527 3: 1528 flushw ! flush register windows, then 1529 ldn [%fp + STACK_BIAS + 14*CLONGSIZE], %g3 ! load initial fp 1530 ba 2b 1531 ldn [%fp + STACK_BIAS + 15*CLONGSIZE], %g4 ! and pc 1532 SET_SIZE(getpcstack_top) 1533 1534 #endif /* lint */ 1535 1536 #if defined(lint) || defined(__lint) 1537 1538 /* ARGSUSED */ 1539 void 1540 setwstate(u_int wstate) 1541 {} 1542 1543 #else /* lint */ 1544 1545 ENTRY_NP(setwstate) 1546 retl 1547 wrpr %g0, %o0, %wstate 1548 SET_SIZE(setwstate) 1549 1550 #endif /* lint */ 1551 1552 1553 #if defined(lint) || defined(__lint) 1554 1555 u_int 1556 getwstate(void) 1557 { return(0); } 1558 1559 #else /* lint */ 1560 1561 ENTRY_NP(getwstate) 1562 retl 1563 rdpr %wstate, %o0 1564 SET_SIZE(getwstate) 1565 1566 #endif /* lint */ 1567 1568 1569 /* 1570 * int panic_trigger(int *tp) 1571 * 1572 * A panic trigger is a word which is updated atomically and can only be set 1573 * once. We atomically store 0xFF into the high byte and load the old value. 1574 * If the byte was 0xFF, the trigger has already been activated and we fail. 1575 * If the previous value was 0 or not 0xFF, we succeed. This allows a 1576 * partially corrupt trigger to still trigger correctly. DTrace has its own 1577 * version of this function to allow it to panic correctly from probe context. 1578 */ 1579 #if defined(lint) 1580 1581 /*ARGSUSED*/ 1582 int panic_trigger(int *tp) { return (0); } 1583 1584 /*ARGSUSED*/ 1585 int dtrace_panic_trigger(int *tp) { return (0); } 1586 1587 #else /* lint */ 1588 1589 ENTRY_NP(panic_trigger) 1590 ldstub [%o0], %o0 ! store 0xFF, load byte into %o0 1591 cmp %o0, 0xFF ! compare %o0 to 0xFF 1592 set 1, %o1 ! %o1 = 1 1593 be,a 0f ! if (%o0 == 0xFF) goto 0f (else annul) 1594 set 0, %o1 ! delay - %o1 = 0 1595 0: retl 1596 mov %o1, %o0 ! return (%o1); 1597 SET_SIZE(panic_trigger) 1598 1599 ENTRY_NP(dtrace_panic_trigger) 1600 ldstub [%o0], %o0 ! store 0xFF, load byte into %o0 1601 cmp %o0, 0xFF ! compare %o0 to 0xFF 1602 set 1, %o1 ! %o1 = 1 1603 be,a 0f ! if (%o0 == 0xFF) goto 0f (else annul) 1604 set 0, %o1 ! delay - %o1 = 0 1605 0: retl 1606 mov %o1, %o0 ! return (%o1); 1607 SET_SIZE(dtrace_panic_trigger) 1608 1609 #endif /* lint */ 1610 1611 /* 1612 * void vpanic(const char *format, va_list alist) 1613 * 1614 * The panic() and cmn_err() functions invoke vpanic() as a common entry point 1615 * into the panic code implemented in panicsys(). vpanic() is responsible 1616 * for passing through the format string and arguments, and constructing a 1617 * regs structure on the stack into which it saves the current register 1618 * values. If we are not dying due to a fatal trap, these registers will 1619 * then be preserved in panicbuf as the current processor state. Before 1620 * invoking panicsys(), vpanic() activates the first panic trigger (see 1621 * common/os/panic.c) and switches to the panic_stack if successful. Note that 1622 * DTrace takes a slightly different panic path if it must panic from probe 1623 * context. Instead of calling panic, it calls into dtrace_vpanic(), which 1624 * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and 1625 * branches back into vpanic(). 1626 */ 1627 #if defined(lint) 1628 1629 /*ARGSUSED*/ 1630 void vpanic(const char *format, va_list alist) {} 1631 1632 /*ARGSUSED*/ 1633 void dtrace_vpanic(const char *format, va_list alist) {} 1634 1635 #else /* lint */ 1636 1637 ENTRY_NP(vpanic) 1638 1639 save %sp, -SA(MINFRAME + REGSIZE), %sp ! save and allocate regs 1640 1641 ! 1642 ! The v9 struct regs has a 64-bit r_tstate field, which we use here 1643 ! to store the %ccr, %asi, %pstate, and %cwp as they would appear 1644 ! in %tstate if a trap occurred. We leave it up to the debugger to 1645 ! realize what happened and extract the register values. 1646 ! 1647 rd %ccr, %l0 ! %l0 = %ccr 1648 sllx %l0, TSTATE_CCR_SHIFT, %l0 ! %l0 <<= CCR_SHIFT 1649 rd %asi, %l1 ! %l1 = %asi 1650 sllx %l1, TSTATE_ASI_SHIFT, %l1 ! %l1 <<= ASI_SHIFT 1651 or %l0, %l1, %l0 ! %l0 |= %l1 1652 rdpr %pstate, %l1 ! %l1 = %pstate 1653 sllx %l1, TSTATE_PSTATE_SHIFT, %l1 ! %l1 <<= PSTATE_SHIFT 1654 or %l0, %l1, %l0 ! %l0 |= %l1 1655 rdpr %cwp, %l1 ! %l1 = %cwp 1656 sllx %l1, TSTATE_CWP_SHIFT, %l1 ! %l1 <<= CWP_SHIFT 1657 or %l0, %l1, %l0 ! %l0 |= %l1 1658 1659 set vpanic, %l1 ! %l1 = %pc (vpanic) 1660 add %l1, 4, %l2 ! %l2 = %npc (vpanic+4) 1661 rd %y, %l3 ! %l3 = %y 1662 ! 1663 ! Flush register windows before panic_trigger() in order to avoid a 1664 ! problem that a dump hangs if flush_windows() causes another panic. 1665 ! 1666 call flush_windows 1667 nop 1668 1669 sethi %hi(panic_quiesce), %o0 1670 call panic_trigger 1671 or %o0, %lo(panic_quiesce), %o0 ! if (!panic_trigger( 1672 1673 vpanic_common: 1674 tst %o0 ! &panic_quiesce)) 1675 be 0f ! goto 0f; 1676 mov %o0, %l4 ! delay - %l4 = %o0 1677 1678 ! 1679 ! If panic_trigger() was successful, we are the first to initiate a 1680 ! panic: switch to the panic_stack. 1681 ! 1682 set panic_stack, %o0 ! %o0 = panic_stack 1683 set PANICSTKSIZE, %o1 ! %o1 = size of stack 1684 add %o0, %o1, %o0 ! %o0 = top of stack 1685 1686 sub %o0, SA(MINFRAME + REGSIZE) + STACK_BIAS, %sp 1687 1688 ! 1689 ! Now that we've got everything set up, store each register to its 1690 ! designated location in the regs structure allocated on the stack. 1691 ! The register set we store is the equivalent of the registers at 1692 ! the time the %pc was pointing to vpanic, thus the %i's now contain 1693 ! what the %o's contained prior to the save instruction. 1694 ! 1695 0: stx %l0, [%sp + STACK_BIAS + SA(MINFRAME) + TSTATE_OFF] 1696 stx %g1, [%sp + STACK_BIAS + SA(MINFRAME) + G1_OFF] 1697 stx %g2, [%sp + STACK_BIAS + SA(MINFRAME) + G2_OFF] 1698 stx %g3, [%sp + STACK_BIAS + SA(MINFRAME) + G3_OFF] 1699 stx %g4, [%sp + STACK_BIAS + SA(MINFRAME) + G4_OFF] 1700 stx %g5, [%sp + STACK_BIAS + SA(MINFRAME) + G5_OFF] 1701 stx %g6, [%sp + STACK_BIAS + SA(MINFRAME) + G6_OFF] 1702 stx %g7, [%sp + STACK_BIAS + SA(MINFRAME) + G7_OFF] 1703 stx %i0, [%sp + STACK_BIAS + SA(MINFRAME) + O0_OFF] 1704 stx %i1, [%sp + STACK_BIAS + SA(MINFRAME) + O1_OFF] 1705 stx %i2, [%sp + STACK_BIAS + SA(MINFRAME) + O2_OFF] 1706 stx %i3, [%sp + STACK_BIAS + SA(MINFRAME) + O3_OFF] 1707 stx %i4, [%sp + STACK_BIAS + SA(MINFRAME) + O4_OFF] 1708 stx %i5, [%sp + STACK_BIAS + SA(MINFRAME) + O5_OFF] 1709 stx %i6, [%sp + STACK_BIAS + SA(MINFRAME) + O6_OFF] 1710 stx %i7, [%sp + STACK_BIAS + SA(MINFRAME) + O7_OFF] 1711 stn %l1, [%sp + STACK_BIAS + SA(MINFRAME) + PC_OFF] 1712 stn %l2, [%sp + STACK_BIAS + SA(MINFRAME) + NPC_OFF] 1713 st %l3, [%sp + STACK_BIAS + SA(MINFRAME) + Y_OFF] 1714 1715 mov %l4, %o3 ! %o3 = on_panic_stack 1716 add %sp, STACK_BIAS + SA(MINFRAME), %o2 ! %o2 = ®s 1717 mov %i1, %o1 ! %o1 = alist 1718 call panicsys ! panicsys(); 1719 mov %i0, %o0 ! %o0 = format 1720 ret 1721 restore 1722 1723 SET_SIZE(vpanic) 1724 1725 ENTRY_NP(dtrace_vpanic) 1726 1727 save %sp, -SA(MINFRAME + REGSIZE), %sp ! save and allocate regs 1728 1729 ! 1730 ! The v9 struct regs has a 64-bit r_tstate field, which we use here 1731 ! to store the %ccr, %asi, %pstate, and %cwp as they would appear 1732 ! in %tstate if a trap occurred. We leave it up to the debugger to 1733 ! realize what happened and extract the register values. 1734 ! 1735 rd %ccr, %l0 ! %l0 = %ccr 1736 sllx %l0, TSTATE_CCR_SHIFT, %l0 ! %l0 <<= CCR_SHIFT 1737 rd %asi, %l1 ! %l1 = %asi 1738 sllx %l1, TSTATE_ASI_SHIFT, %l1 ! %l1 <<= ASI_SHIFT 1739 or %l0, %l1, %l0 ! %l0 |= %l1 1740 rdpr %pstate, %l1 ! %l1 = %pstate 1741 sllx %l1, TSTATE_PSTATE_SHIFT, %l1 ! %l1 <<= PSTATE_SHIFT 1742 or %l0, %l1, %l0 ! %l0 |= %l1 1743 rdpr %cwp, %l1 ! %l1 = %cwp 1744 sllx %l1, TSTATE_CWP_SHIFT, %l1 ! %l1 <<= CWP_SHIFT 1745 or %l0, %l1, %l0 ! %l0 |= %l1 1746 1747 set dtrace_vpanic, %l1 ! %l1 = %pc (vpanic) 1748 add %l1, 4, %l2 ! %l2 = %npc (vpanic+4) 1749 rd %y, %l3 ! %l3 = %y 1750 ! 1751 ! Flush register windows before panic_trigger() in order to avoid a 1752 ! problem that a dump hangs if flush_windows() causes another panic. 1753 ! 1754 call dtrace_flush_windows 1755 nop 1756 1757 sethi %hi(panic_quiesce), %o0 1758 call dtrace_panic_trigger 1759 or %o0, %lo(panic_quiesce), %o0 ! if (!panic_trigger( 1760 1761 ba,a vpanic_common 1762 SET_SIZE(dtrace_vpanic) 1763 1764 #endif /* lint */ 1765 1766 #if defined(lint) 1767 1768 /*ARGSUSED*/ 1769 1770 uint_t 1771 get_subcc_ccr( uint64_t addrl, uint64_t addrr) 1772 { return (0); } 1773 1774 #else /* lint */ 1775 1776 ENTRY(get_subcc_ccr) 1777 wr %g0, %ccr ! clear condition codes 1778 subcc %o0, %o1, %g0 1779 retl 1780 rd %ccr, %o0 ! return condition codes 1781 SET_SIZE(get_subcc_ccr) 1782 1783 #endif /* lint */ 1784 1785 #if defined(lint) || defined(__lint) 1786 1787 ftrace_icookie_t 1788 ftrace_interrupt_disable(void) 1789 { return (0); } 1790 1791 #else /* lint */ 1792 1793 ENTRY_NP(ftrace_interrupt_disable) 1794 rdpr %pstate, %o0 1795 andn %o0, PSTATE_IE, %o1 1796 retl 1797 wrpr %g0, %o1, %pstate 1798 SET_SIZE(ftrace_interrupt_disable) 1799 1800 #endif /* lint */ 1801 1802 #if defined(lint) || defined(__lint) 1803 1804 /*ARGSUSED*/ 1805 void 1806 ftrace_interrupt_enable(ftrace_icookie_t cookie) 1807 {} 1808 1809 #else 1810 1811 ENTRY_NP(ftrace_interrupt_enable) 1812 retl 1813 wrpr %g0, %o0, %pstate 1814 SET_SIZE(ftrace_interrupt_enable) 1815 1816 #endif /* lint*/