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; \ 861: \ 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 */ \ 1021: \ 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 183int spl0(void) { return (0); } 184int spl6(void) { return (0); } 185int spl7(void) { return (0); } 186int spl8(void) { return (0); } 187int splhi(void) { return (0); } 188int splhigh(void) { return (0); } 189int 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 */ 237void 238splx(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 */ 264int 265splr(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 */ 285int 286on_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 298catch_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 316void 317no_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 339void 340on_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*/ 365int 366on_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 3870: 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 */ 401int 402setjmp(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 */ 420void 421longjmp(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*/ 456int 457movtuc(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 4680: 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 4761: 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 4812: 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*/ 497int 498scanc(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 5070: 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 5151: 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 529caddr_t 530caller(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 549caddr_t 550callee(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 568greg_t 569getfp(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 587greg_t 588gettbr(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 609greg_t 610getpsr(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 635u_int 636getpil(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*/ 651void 652setpil(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*/ 674void 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*/ 700void 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*/ 729size_t 730strlen(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 7601: 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 7793: 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 8001: 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 8061: 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 8121: 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 827void 828membar_ldld(void) 829{} 830 831void 832membar_stld(void) 833{} 834 835void 836membar_ldst(void) 837{} 838 839void 840membar_stst(void) 841{} 842 843void 844membar_ldld_ldst(void) 845{} 846 847void 848membar_ldld_stld(void) 849{} 850 851void 852membar_ldld_stst(void) 853{} 854 855void 856membar_stld_ldld(void) 857{} 858 859void 860membar_stld_ldst(void) 861{} 862 863void 864membar_stld_stst(void) 865{} 866 867void 868membar_ldst_ldld(void) 869{} 870 871void 872membar_ldst_stld(void) 873{} 874 875void 876membar_ldst_stst(void) 877{} 878 879void 880membar_stst_ldld(void) 881{} 882 883void 884membar_stst_stld(void) 885{} 886 887void 888membar_stst_ldst(void) 889{} 890 891void 892membar_lookaside(void) 893{} 894 895void 896membar_memissue(void) 897{} 898 899void 900membar_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*/ 987int 988fuword64(const void *addr, uint64_t *dst) 989{ return (0); } 990 991/*ARGSUSED*/ 992int 993fuword32(const void *addr, uint32_t *dst) 994{ return (0); } 995 996/*ARGSUSED*/ 997int 998fuword16(const void *addr, uint16_t *dst) 999{ return (0); } 1000 1001/*ARGSUSED*/ 1002int 1003fuword8(const void *addr, uint8_t *dst) 1004{ return (0); } 1005 1006/*ARGSUSED*/ 1007int 1008dtrace_ft_fuword64(const void *addr, uint64_t *dst) 1009{ return (0); } 1010 1011/*ARGSUSED*/ 1012int 1013dtrace_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]; \ 10361: \ 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; \ 10452: \ 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*/ 1061int 1062suword64(void *addr, uint64_t value) 1063{ return (0); } 1064 1065/*ARGSUSED*/ 1066int 1067suword32(void *addr, uint32_t value) 1068{ return (0); } 1069 1070/*ARGSUSED*/ 1071int 1072suword16(void *addr, uint16_t value) 1073{ return (0); } 1074 1075/*ARGSUSED*/ 1076int 1077suword8(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; \ 10991: \ 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; \ 11082: \ 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*/ 1123void 1124fuword8_noerr(const void *addr, uint8_t *dst) 1125{} 1126 1127/*ARGSUSED*/ 1128void 1129fuword16_noerr(const void *addr, uint16_t *dst) 1130{} 1131 1132/*ARGSUSED*/ 1133void 1134fuword32_noerr(const void *addr, uint32_t *dst) 1135{} 1136 1137/*ARGSUSED*/ 1138void 1139fuword64_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*/ 1173void 1174suword8_noerr(void *addr, uint8_t value) 1175{} 1176 1177/*ARGSUSED*/ 1178void 1179suword16_noerr(void *addr, uint16_t value) 1180{} 1181 1182/*ARGSUSED*/ 1183void 1184suword32_noerr(void *addr, uint32_t value) 1185{} 1186 1187/*ARGSUSED*/ 1188void 1189suword64_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*/ 1219int 1220subyte(void *addr, uchar_t value) 1221{ return (0); } 1222 1223/*ARGSUSED*/ 1224void 1225subyte_noerr(void *addr, uchar_t value) 1226{} 1227 1228/*ARGSUSED*/ 1229int 1230fulword(const void *addr, ulong_t *valuep) 1231{ return (0); } 1232 1233/*ARGSUSED*/ 1234void 1235fulword_noerr(const void *addr, ulong_t *valuep) 1236{} 1237 1238/*ARGSUSED*/ 1239int 1240sulword(void *addr, ulong_t valuep) 1241{ return (0); } 1242 1243/*ARGSUSED*/ 1244void 1245sulword_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 1286hrtime_t 1287rdtick() 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*/ 1307void * 1308set_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*/ 1326void * 1327get_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 */ 1342void 1343setpstate(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 1357u_int 1358getpstate(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 1372dtrace_icookie_t 1373dtrace_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*/ 1390void 1391dtrace_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 1405void 1406dtrace_membar_producer(void) 1407{} 1408 1409void 1410dtrace_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 1440void 1441dtrace_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*/ 1456int 1457getpcstack_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 15061: 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. 15202: 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 15273: 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 */ 1539void 1540setwstate(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 1555u_int 1556getwstate(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*/ 1582int panic_trigger(int *tp) { return (0); } 1583 1584/*ARGSUSED*/ 1585int 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 15950: 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 16050: 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*/ 1630void vpanic(const char *format, va_list alist) {} 1631 1632/*ARGSUSED*/ 1633void 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 1673vpanic_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 ! 16950: 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 1770uint_t 1771get_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 1787ftrace_icookie_t 1788ftrace_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*/ 1805void 1806ftrace_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*/ 1817