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/* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27/* 28 * Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. 29 * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T 30 * All Rights Reserved 31 */ 32 33#pragma ident "%Z%%M% %I% %E% SMI" 34 35/* 36 * General assembly language routines. 37 * It is the intent of this file to contain routines that are 38 * independent of the specific kernel architecture, and those that are 39 * common across kernel architectures. 40 * As architectures diverge, and implementations of specific 41 * architecture-dependent routines change, the routines should be moved 42 * from this file into the respective ../`arch -k`/subr.s file. 43 */ 44 45#include <sys/asm_linkage.h> 46#include <sys/asm_misc.h> 47#include <sys/panic.h> 48#include <sys/ontrap.h> 49#include <sys/regset.h> 50#include <sys/privregs.h> 51#include <sys/reboot.h> 52#include <sys/psw.h> 53#include <sys/x86_archext.h> 54 55#if defined(__lint) 56#include <sys/types.h> 57#include <sys/systm.h> 58#include <sys/thread.h> 59#include <sys/archsystm.h> 60#include <sys/byteorder.h> 61#include <sys/dtrace.h> 62#include <sys/ftrace.h> 63#else /* __lint */ 64#include "assym.h" 65#endif /* __lint */ 66#include <sys/dditypes.h> 67 68/* 69 * on_fault() 70 * Catch lofault faults. Like setjmp except it returns one 71 * if code following causes uncorrectable fault. Turned off 72 * by calling no_fault(). 73 */ 74 75#if defined(__lint) 76 77/* ARGSUSED */ 78int 79on_fault(label_t *ljb) 80{ return (0); } 81 82void 83no_fault(void) 84{} 85 86#else /* __lint */ 87 88#if defined(__amd64) 89 90 ENTRY(on_fault) 91 movq %gs:CPU_THREAD, %rsi 92 leaq catch_fault(%rip), %rdx 93 movq %rdi, T_ONFAULT(%rsi) /* jumpbuf in t_onfault */ 94 movq %rdx, T_LOFAULT(%rsi) /* catch_fault in t_lofault */ 95 jmp setjmp /* let setjmp do the rest */ 96 97catch_fault: 98 movq %gs:CPU_THREAD, %rsi 99 movq T_ONFAULT(%rsi), %rdi /* address of save area */ 100 xorl %eax, %eax 101 movq %rax, T_ONFAULT(%rsi) /* turn off onfault */ 102 movq %rax, T_LOFAULT(%rsi) /* turn off lofault */ 103 jmp longjmp /* let longjmp do the rest */ 104 SET_SIZE(on_fault) 105 106 ENTRY(no_fault) 107 movq %gs:CPU_THREAD, %rsi 108 xorl %eax, %eax 109 movq %rax, T_ONFAULT(%rsi) /* turn off onfault */ 110 movq %rax, T_LOFAULT(%rsi) /* turn off lofault */ 111 ret 112 SET_SIZE(no_fault) 113 114#elif defined(__i386) 115 116 ENTRY(on_fault) 117 movl %gs:CPU_THREAD, %edx 118 movl 4(%esp), %eax /* jumpbuf address */ 119 leal catch_fault, %ecx 120 movl %eax, T_ONFAULT(%edx) /* jumpbuf in t_onfault */ 121 movl %ecx, T_LOFAULT(%edx) /* catch_fault in t_lofault */ 122 jmp setjmp /* let setjmp do the rest */ 123 124catch_fault: 125 movl %gs:CPU_THREAD, %edx 126 xorl %eax, %eax 127 movl T_ONFAULT(%edx), %ecx /* address of save area */ 128 movl %eax, T_ONFAULT(%edx) /* turn off onfault */ 129 movl %eax, T_LOFAULT(%edx) /* turn off lofault */ 130 pushl %ecx 131 call longjmp /* let longjmp do the rest */ 132 SET_SIZE(on_fault) 133 134 ENTRY(no_fault) 135 movl %gs:CPU_THREAD, %edx 136 xorl %eax, %eax 137 movl %eax, T_ONFAULT(%edx) /* turn off onfault */ 138 movl %eax, T_LOFAULT(%edx) /* turn off lofault */ 139 ret 140 SET_SIZE(no_fault) 141 142#endif /* __i386 */ 143#endif /* __lint */ 144 145/* 146 * Default trampoline code for on_trap() (see <sys/ontrap.h>). We just 147 * do a longjmp(&curthread->t_ontrap->ot_jmpbuf) if this is ever called. 148 */ 149 150#if defined(lint) 151 152void 153on_trap_trampoline(void) 154{} 155 156#else /* __lint */ 157 158#if defined(__amd64) 159 160 ENTRY(on_trap_trampoline) 161 movq %gs:CPU_THREAD, %rsi 162 movq T_ONTRAP(%rsi), %rdi 163 addq $OT_JMPBUF, %rdi 164 jmp longjmp 165 SET_SIZE(on_trap_trampoline) 166 167#elif defined(__i386) 168 169 ENTRY(on_trap_trampoline) 170 movl %gs:CPU_THREAD, %eax 171 movl T_ONTRAP(%eax), %eax 172 addl $OT_JMPBUF, %eax 173 pushl %eax 174 call longjmp 175 SET_SIZE(on_trap_trampoline) 176 177#endif /* __i386 */ 178#endif /* __lint */ 179 180/* 181 * Push a new element on to the t_ontrap stack. Refer to <sys/ontrap.h> for 182 * more information about the on_trap() mechanism. If the on_trap_data is the 183 * same as the topmost stack element, we just modify that element. 184 */ 185#if defined(lint) 186 187/*ARGSUSED*/ 188int 189on_trap(on_trap_data_t *otp, uint_t prot) 190{ return (0); } 191 192#else /* __lint */ 193 194#if defined(__amd64) 195 196 ENTRY(on_trap) 197 movw %si, OT_PROT(%rdi) /* ot_prot = prot */ 198 movw $0, OT_TRAP(%rdi) /* ot_trap = 0 */ 199 leaq on_trap_trampoline(%rip), %rdx /* rdx = &on_trap_trampoline */ 200 movq %rdx, OT_TRAMPOLINE(%rdi) /* ot_trampoline = rdx */ 201 xorl %ecx, %ecx 202 movq %rcx, OT_HANDLE(%rdi) /* ot_handle = NULL */ 203 movq %rcx, OT_PAD1(%rdi) /* ot_pad1 = NULL */ 204 movq %gs:CPU_THREAD, %rdx /* rdx = curthread */ 205 movq T_ONTRAP(%rdx), %rcx /* rcx = curthread->t_ontrap */ 206 cmpq %rdi, %rcx /* if (otp == %rcx) */ 207 je 0f /* don't modify t_ontrap */ 208 209 movq %rcx, OT_PREV(%rdi) /* ot_prev = t_ontrap */ 210 movq %rdi, T_ONTRAP(%rdx) /* curthread->t_ontrap = otp */ 211 2120: addq $OT_JMPBUF, %rdi /* &ot_jmpbuf */ 213 jmp setjmp 214 SET_SIZE(on_trap) 215 216#elif defined(__i386) 217 218 ENTRY(on_trap) 219 movl 4(%esp), %eax /* %eax = otp */ 220 movl 8(%esp), %edx /* %edx = prot */ 221 222 movw %dx, OT_PROT(%eax) /* ot_prot = prot */ 223 movw $0, OT_TRAP(%eax) /* ot_trap = 0 */ 224 leal on_trap_trampoline, %edx /* %edx = &on_trap_trampoline */ 225 movl %edx, OT_TRAMPOLINE(%eax) /* ot_trampoline = %edx */ 226 movl $0, OT_HANDLE(%eax) /* ot_handle = NULL */ 227 movl $0, OT_PAD1(%eax) /* ot_pad1 = NULL */ 228 movl %gs:CPU_THREAD, %edx /* %edx = curthread */ 229 movl T_ONTRAP(%edx), %ecx /* %ecx = curthread->t_ontrap */ 230 cmpl %eax, %ecx /* if (otp == %ecx) */ 231 je 0f /* don't modify t_ontrap */ 232 233 movl %ecx, OT_PREV(%eax) /* ot_prev = t_ontrap */ 234 movl %eax, T_ONTRAP(%edx) /* curthread->t_ontrap = otp */ 235 2360: addl $OT_JMPBUF, %eax /* %eax = &ot_jmpbuf */ 237 movl %eax, 4(%esp) /* put %eax back on the stack */ 238 jmp setjmp /* let setjmp do the rest */ 239 SET_SIZE(on_trap) 240 241#endif /* __i386 */ 242#endif /* __lint */ 243 244/* 245 * Setjmp and longjmp implement non-local gotos using state vectors 246 * type label_t. 247 */ 248 249#if defined(__lint) 250 251/* ARGSUSED */ 252int 253setjmp(label_t *lp) 254{ return (0); } 255 256/* ARGSUSED */ 257void 258longjmp(label_t *lp) 259{} 260 261#else /* __lint */ 262 263#if LABEL_PC != 0 264#error LABEL_PC MUST be defined as 0 for setjmp/longjmp to work as coded 265#endif /* LABEL_PC != 0 */ 266 267#if defined(__amd64) 268 269 ENTRY(setjmp) 270 movq %rsp, LABEL_SP(%rdi) 271 movq %rbp, LABEL_RBP(%rdi) 272 movq %rbx, LABEL_RBX(%rdi) 273 movq %r12, LABEL_R12(%rdi) 274 movq %r13, LABEL_R13(%rdi) 275 movq %r14, LABEL_R14(%rdi) 276 movq %r15, LABEL_R15(%rdi) 277 movq (%rsp), %rdx /* return address */ 278 movq %rdx, (%rdi) /* LABEL_PC is 0 */ 279 xorl %eax, %eax /* return 0 */ 280 ret 281 SET_SIZE(setjmp) 282 283 ENTRY(longjmp) 284 movq LABEL_SP(%rdi), %rsp 285 movq LABEL_RBP(%rdi), %rbp 286 movq LABEL_RBX(%rdi), %rbx 287 movq LABEL_R12(%rdi), %r12 288 movq LABEL_R13(%rdi), %r13 289 movq LABEL_R14(%rdi), %r14 290 movq LABEL_R15(%rdi), %r15 291 movq (%rdi), %rdx /* return address; LABEL_PC is 0 */ 292 movq %rdx, (%rsp) 293 xorl %eax, %eax 294 incl %eax /* return 1 */ 295 ret 296 SET_SIZE(longjmp) 297 298#elif defined(__i386) 299 300 ENTRY(setjmp) 301 movl 4(%esp), %edx /* address of save area */ 302 movl %ebp, LABEL_EBP(%edx) 303 movl %ebx, LABEL_EBX(%edx) 304 movl %esi, LABEL_ESI(%edx) 305 movl %edi, LABEL_EDI(%edx) 306 movl %esp, 4(%edx) 307 movl (%esp), %ecx /* %eip (return address) */ 308 movl %ecx, (%edx) /* LABEL_PC is 0 */ 309 subl %eax, %eax /* return 0 */ 310 ret 311 SET_SIZE(setjmp) 312 313 ENTRY(longjmp) 314 movl 4(%esp), %edx /* address of save area */ 315 movl LABEL_EBP(%edx), %ebp 316 movl LABEL_EBX(%edx), %ebx 317 movl LABEL_ESI(%edx), %esi 318 movl LABEL_EDI(%edx), %edi 319 movl 4(%edx), %esp 320 movl (%edx), %ecx /* %eip (return addr); LABEL_PC is 0 */ 321 movl $1, %eax 322 addl $4, %esp /* pop ret adr */ 323 jmp *%ecx /* indirect */ 324 SET_SIZE(longjmp) 325 326#endif /* __i386 */ 327#endif /* __lint */ 328 329/* 330 * if a() calls b() calls caller(), 331 * caller() returns return address in a(). 332 * (Note: We assume a() and b() are C routines which do the normal entry/exit 333 * sequence.) 334 */ 335 336#if defined(__lint) 337 338caddr_t 339caller(void) 340{ return (0); } 341 342#else /* __lint */ 343 344#if defined(__amd64) 345 346 ENTRY(caller) 347 movq 8(%rbp), %rax /* b()'s return pc, in a() */ 348 ret 349 SET_SIZE(caller) 350 351#elif defined(__i386) 352 353 ENTRY(caller) 354 movl 4(%ebp), %eax /* b()'s return pc, in a() */ 355 ret 356 SET_SIZE(caller) 357 358#endif /* __i386 */ 359#endif /* __lint */ 360 361/* 362 * if a() calls callee(), callee() returns the 363 * return address in a(); 364 */ 365 366#if defined(__lint) 367 368caddr_t 369callee(void) 370{ return (0); } 371 372#else /* __lint */ 373 374#if defined(__amd64) 375 376 ENTRY(callee) 377 movq (%rsp), %rax /* callee()'s return pc, in a() */ 378 ret 379 SET_SIZE(callee) 380 381#elif defined(__i386) 382 383 ENTRY(callee) 384 movl (%esp), %eax /* callee()'s return pc, in a() */ 385 ret 386 SET_SIZE(callee) 387 388#endif /* __i386 */ 389#endif /* __lint */ 390 391/* 392 * return the current frame pointer 393 */ 394 395#if defined(__lint) 396 397greg_t 398getfp(void) 399{ return (0); } 400 401#else /* __lint */ 402 403#if defined(__amd64) 404 405 ENTRY(getfp) 406 movq %rbp, %rax 407 ret 408 SET_SIZE(getfp) 409 410#elif defined(__i386) 411 412 ENTRY(getfp) 413 movl %ebp, %eax 414 ret 415 SET_SIZE(getfp) 416 417#endif /* __i386 */ 418#endif /* __lint */ 419 420/* 421 * Invalidate a single page table entry in the TLB 422 */ 423 424#if defined(__lint) 425 426/* ARGSUSED */ 427void 428mmu_tlbflush_entry(caddr_t m) 429{} 430 431#else /* __lint */ 432 433#if defined(__amd64) 434 435 ENTRY(mmu_tlbflush_entry) 436 invlpg (%rdi) 437 ret 438 SET_SIZE(mmu_tlbflush_entry) 439 440#elif defined(__i386) 441 442 ENTRY(mmu_tlbflush_entry) 443 movl 4(%esp), %eax 444 invlpg (%eax) 445 ret 446 SET_SIZE(mmu_tlbflush_entry) 447 448#endif /* __i386 */ 449#endif /* __lint */ 450 451 452/* 453 * Get/Set the value of various control registers 454 */ 455 456#if defined(__lint) 457 458ulong_t 459getcr0(void) 460{ return (0); } 461 462/* ARGSUSED */ 463void 464setcr0(ulong_t value) 465{} 466 467ulong_t 468getcr2(void) 469{ return (0); } 470 471ulong_t 472getcr3(void) 473{ return (0); } 474 475/* ARGSUSED */ 476void 477setcr3(ulong_t val) 478{} 479 480void 481reload_cr3(void) 482{} 483 484ulong_t 485getcr4(void) 486{ return (0); } 487 488/* ARGSUSED */ 489void 490setcr4(ulong_t val) 491{} 492 493#if defined(__amd64) 494 495ulong_t 496getcr8(void) 497{ return (0); } 498 499/* ARGSUSED */ 500void 501setcr8(ulong_t val) 502{} 503 504#endif /* __amd64 */ 505 506#else /* __lint */ 507 508#if defined(__amd64) 509 510 ENTRY(getcr0) 511 movq %cr0, %rax 512 ret 513 SET_SIZE(getcr0) 514 515 ENTRY(setcr0) 516 movq %rdi, %cr0 517 ret 518 SET_SIZE(setcr0) 519 520 ENTRY(getcr2) 521 movq %cr2, %rax 522 ret 523 SET_SIZE(getcr2) 524 525 ENTRY(getcr3) 526 movq %cr3, %rax 527 ret 528 SET_SIZE(getcr3) 529 530 ENTRY(setcr3) 531 movq %rdi, %cr3 532 ret 533 SET_SIZE(setcr3) 534 535 ENTRY(reload_cr3) 536 movq %cr3, %rdi 537 movq %rdi, %cr3 538 ret 539 SET_SIZE(reload_cr3) 540 541 ENTRY(getcr4) 542 movq %cr4, %rax 543 ret 544 SET_SIZE(getcr4) 545 546 ENTRY(setcr4) 547 movq %rdi, %cr4 548 ret 549 SET_SIZE(setcr4) 550 551 ENTRY(getcr8) 552 movq %cr8, %rax 553 ret 554 SET_SIZE(getcr8) 555 556 ENTRY(setcr8) 557 movq %rdi, %cr8 558 ret 559 SET_SIZE(setcr8) 560 561#elif defined(__i386) 562 563 ENTRY(getcr0) 564 movl %cr0, %eax 565 ret 566 SET_SIZE(getcr0) 567 568 ENTRY(setcr0) 569 movl 4(%esp), %eax 570 movl %eax, %cr0 571 ret 572 SET_SIZE(setcr0) 573 574 ENTRY(getcr2) 575 movl %cr2, %eax 576 ret 577 SET_SIZE(getcr2) 578 579 ENTRY(getcr3) 580 movl %cr3, %eax 581 ret 582 SET_SIZE(getcr3) 583 584 ENTRY(setcr3) 585 movl 4(%esp), %eax 586 movl %eax, %cr3 587 ret 588 SET_SIZE(setcr3) 589 590 ENTRY(reload_cr3) 591 movl %cr3, %eax 592 movl %eax, %cr3 593 ret 594 SET_SIZE(reload_cr3) 595 596 ENTRY(getcr4) 597 movl %cr4, %eax 598 ret 599 SET_SIZE(getcr4) 600 601 ENTRY(setcr4) 602 movl 4(%esp), %eax 603 movl %eax, %cr4 604 ret 605 SET_SIZE(setcr4) 606 607#endif /* __i386 */ 608#endif /* __lint */ 609 610#if defined(__lint) 611 612/*ARGSUSED*/ 613uint32_t 614__cpuid_insn(struct cpuid_regs *regs) 615{ return (0); } 616 617#else /* __lint */ 618 619#if defined(__amd64) 620 621 ENTRY(__cpuid_insn) 622 movq %rbx, %r8 623 movq %rcx, %r9 624 movq %rdx, %r11 625 movl (%rdi), %eax /* %eax = regs->cp_eax */ 626 movl 0x4(%rdi), %ebx /* %ebx = regs->cp_ebx */ 627 movl 0x8(%rdi), %ecx /* %ecx = regs->cp_ecx */ 628 movl 0xc(%rdi), %edx /* %edx = regs->cp_edx */ 629 cpuid 630 movl %eax, (%rdi) /* regs->cp_eax = %eax */ 631 movl %ebx, 0x4(%rdi) /* regs->cp_ebx = %ebx */ 632 movl %ecx, 0x8(%rdi) /* regs->cp_ecx = %ecx */ 633 movl %edx, 0xc(%rdi) /* regs->cp_edx = %edx */ 634 movq %r8, %rbx 635 movq %r9, %rcx 636 movq %r11, %rdx 637 ret 638 SET_SIZE(__cpuid_insn) 639 640#elif defined(__i386) 641 642 ENTRY(__cpuid_insn) 643 pushl %ebp 644 movl 0x8(%esp), %ebp /* %ebp = regs */ 645 pushl %ebx 646 pushl %ecx 647 pushl %edx 648 movl (%ebp), %eax /* %eax = regs->cp_eax */ 649 movl 0x4(%ebp), %ebx /* %ebx = regs->cp_ebx */ 650 movl 0x8(%ebp), %ecx /* %ecx = regs->cp_ecx */ 651 movl 0xc(%ebp), %edx /* %edx = regs->cp_edx */ 652 cpuid 653 movl %eax, (%ebp) /* regs->cp_eax = %eax */ 654 movl %ebx, 0x4(%ebp) /* regs->cp_ebx = %ebx */ 655 movl %ecx, 0x8(%ebp) /* regs->cp_ecx = %ecx */ 656 movl %edx, 0xc(%ebp) /* regs->cp_edx = %edx */ 657 popl %edx 658 popl %ecx 659 popl %ebx 660 popl %ebp 661 ret 662 SET_SIZE(__cpuid_insn) 663 664#endif /* __i386 */ 665#endif /* __lint */ 666 667#if defined(__lint) 668 669/*ARGSUSED*/ 670void 671i86_monitor(volatile uint32_t *addr, uint32_t extensions, uint32_t hints) 672{ return; } 673 674#else /* __lint */ 675 676#if defined(__amd64) 677 678 ENTRY_NP(i86_monitor) 679 pushq %rbp 680 movq %rsp, %rbp 681 movq %rdi, %rax /* addr */ 682 movq %rsi, %rcx /* extensions */ 683 /* rdx contains input arg3: hints */ 684 .byte 0x0f, 0x01, 0xc8 /* monitor */ 685 leave 686 ret 687 SET_SIZE(i86_monitor) 688 689#elif defined(__i386) 690 691ENTRY_NP(i86_monitor) 692 pushl %ebp 693 movl %esp, %ebp 694 movl 0x4(%esp),%eax /* addr */ 695 movl 0x8(%esp),%ecx /* extensions */ 696 movl 0xc(%esp),%edx /* hints */ 697 .byte 0x0f, 0x01, 0xc8 /* monitor */ 698 leave 699 ret 700 SET_SIZE(i86_monitor) 701 702#endif /* __i386 */ 703#endif /* __lint */ 704 705#if defined(__lint) 706 707/*ARGSUSED*/ 708void 709i86_mwait(uint32_t data, uint32_t extensions) 710{ return; } 711 712#else /* __lint */ 713 714#if defined(__amd64) 715 716 ENTRY_NP(i86_mwait) 717 pushq %rbp 718 movq %rsp, %rbp 719 movq %rdi, %rax /* data */ 720 movq %rsi, %rcx /* extensions */ 721 .byte 0x0f, 0x01, 0xc9 /* mwait */ 722 leave 723 ret 724 SET_SIZE(i86_mwait) 725 726#elif defined(__i386) 727 728 ENTRY_NP(i86_mwait) 729 pushl %ebp 730 movl %esp, %ebp 731 movl 0x4(%esp),%eax /* data */ 732 movl 0x8(%esp),%ecx /* extensions */ 733 .byte 0x0f, 0x01, 0xc9 /* mwait */ 734 leave 735 ret 736 SET_SIZE(i86_mwait) 737 738#endif /* __i386 */ 739#endif /* __lint */ 740 741#if defined(__lint) 742 743hrtime_t 744tsc_read(void) 745{ 746 return (0); 747} 748 749#else /* __lint */ 750 751 ENTRY_NP(tsc_read) 752 rdtsc 753#if defined(__amd64) 754 shlq $32, %rdx 755 orq %rdx, %rax 756#endif 757 ret 758 SET_SIZE(tsc_read) 759 760#endif /* __lint */ 761 762/* 763 * Insert entryp after predp in a doubly linked list. 764 */ 765 766#if defined(__lint) 767 768/*ARGSUSED*/ 769void 770_insque(caddr_t entryp, caddr_t predp) 771{} 772 773#else /* __lint */ 774 775#if defined(__amd64) 776 777 ENTRY(_insque) 778 movq (%rsi), %rax /* predp->forw */ 779 movq %rsi, CPTRSIZE(%rdi) /* entryp->back = predp */ 780 movq %rax, (%rdi) /* entryp->forw = predp->forw */ 781 movq %rdi, (%rsi) /* predp->forw = entryp */ 782 movq %rdi, CPTRSIZE(%rax) /* predp->forw->back = entryp */ 783 ret 784 SET_SIZE(_insque) 785 786#elif defined(__i386) 787 788 ENTRY(_insque) 789 movl 8(%esp), %edx 790 movl 4(%esp), %ecx 791 movl (%edx), %eax /* predp->forw */ 792 movl %edx, CPTRSIZE(%ecx) /* entryp->back = predp */ 793 movl %eax, (%ecx) /* entryp->forw = predp->forw */ 794 movl %ecx, (%edx) /* predp->forw = entryp */ 795 movl %ecx, CPTRSIZE(%eax) /* predp->forw->back = entryp */ 796 ret 797 SET_SIZE(_insque) 798 799#endif /* __i386 */ 800#endif /* __lint */ 801 802/* 803 * Remove entryp from a doubly linked list 804 */ 805 806#if defined(__lint) 807 808/*ARGSUSED*/ 809void 810_remque(caddr_t entryp) 811{} 812 813#else /* __lint */ 814 815#if defined(__amd64) 816 817 ENTRY(_remque) 818 movq (%rdi), %rax /* entry->forw */ 819 movq CPTRSIZE(%rdi), %rdx /* entry->back */ 820 movq %rax, (%rdx) /* entry->back->forw = entry->forw */ 821 movq %rdx, CPTRSIZE(%rax) /* entry->forw->back = entry->back */ 822 ret 823 SET_SIZE(_remque) 824 825#elif defined(__i386) 826 827 ENTRY(_remque) 828 movl 4(%esp), %ecx 829 movl (%ecx), %eax /* entry->forw */ 830 movl CPTRSIZE(%ecx), %edx /* entry->back */ 831 movl %eax, (%edx) /* entry->back->forw = entry->forw */ 832 movl %edx, CPTRSIZE(%eax) /* entry->forw->back = entry->back */ 833 ret 834 SET_SIZE(_remque) 835 836#endif /* __i386 */ 837#endif /* __lint */ 838 839/* 840 * Returns the number of 841 * non-NULL bytes in string argument. 842 */ 843 844#if defined(__lint) 845 846/* ARGSUSED */ 847size_t 848strlen(const char *str) 849{ return (0); } 850 851#else /* __lint */ 852 853#if defined(__amd64) 854 855/* 856 * This is close to a simple transliteration of a C version of this 857 * routine. We should either just -make- this be a C version, or 858 * justify having it in assembler by making it significantly faster. 859 * 860 * size_t 861 * strlen(const char *s) 862 * { 863 * const char *s0; 864 * #if defined(DEBUG) 865 * if ((uintptr_t)s < KERNELBASE) 866 * panic(.str_panic_msg); 867 * #endif 868 * for (s0 = s; *s; s++) 869 * ; 870 * return (s - s0); 871 * } 872 */ 873 874 ENTRY(strlen) 875#ifdef DEBUG 876 movq postbootkernelbase(%rip), %rax 877 cmpq %rax, %rdi 878 jae str_valid 879 pushq %rbp 880 movq %rsp, %rbp 881 leaq .str_panic_msg(%rip), %rdi 882 xorl %eax, %eax 883 call panic 884#endif /* DEBUG */ 885str_valid: 886 cmpb $0, (%rdi) 887 movq %rdi, %rax 888 je .null_found 889 .align 4 890.strlen_loop: 891 incq %rdi 892 cmpb $0, (%rdi) 893 jne .strlen_loop 894.null_found: 895 subq %rax, %rdi 896 movq %rdi, %rax 897 ret 898 SET_SIZE(strlen) 899 900#elif defined(__i386) 901 902 ENTRY(strlen) 903#ifdef DEBUG 904 movl postbootkernelbase, %eax 905 cmpl %eax, 4(%esp) 906 jae str_valid 907 pushl %ebp 908 movl %esp, %ebp 909 pushl $.str_panic_msg 910 call panic 911#endif /* DEBUG */ 912 913str_valid: 914 movl 4(%esp), %eax /* %eax = string address */ 915 testl $3, %eax /* if %eax not word aligned */ 916 jnz .not_word_aligned /* goto .not_word_aligned */ 917 .align 4 918.word_aligned: 919 movl (%eax), %edx /* move 1 word from (%eax) to %edx */ 920 movl $0x7f7f7f7f, %ecx 921 andl %edx, %ecx /* %ecx = %edx & 0x7f7f7f7f */ 922 addl $4, %eax /* next word */ 923 addl $0x7f7f7f7f, %ecx /* %ecx += 0x7f7f7f7f */ 924 orl %edx, %ecx /* %ecx |= %edx */ 925 andl $0x80808080, %ecx /* %ecx &= 0x80808080 */ 926 cmpl $0x80808080, %ecx /* if no null byte in this word */ 927 je .word_aligned /* goto .word_aligned */ 928 subl $4, %eax /* post-incremented */ 929.not_word_aligned: 930 cmpb $0, (%eax) /* if a byte in (%eax) is null */ 931 je .null_found /* goto .null_found */ 932 incl %eax /* next byte */ 933 testl $3, %eax /* if %eax not word aligned */ 934 jnz .not_word_aligned /* goto .not_word_aligned */ 935 jmp .word_aligned /* goto .word_aligned */ 936 .align 4 937.null_found: 938 subl 4(%esp), %eax /* %eax -= string address */ 939 ret 940 SET_SIZE(strlen) 941 942#endif /* __i386 */ 943 944#ifdef DEBUG 945 .text 946.str_panic_msg: 947 .string "strlen: argument below kernelbase" 948#endif /* DEBUG */ 949 950#endif /* __lint */ 951 952 /* 953 * Berkley 4.3 introduced symbolically named interrupt levels 954 * as a way deal with priority in a machine independent fashion. 955 * Numbered priorities are machine specific, and should be 956 * discouraged where possible. 957 * 958 * Note, for the machine specific priorities there are 959 * examples listed for devices that use a particular priority. 960 * It should not be construed that all devices of that 961 * type should be at that priority. It is currently were 962 * the current devices fit into the priority scheme based 963 * upon time criticalness. 964 * 965 * The underlying assumption of these assignments is that 966 * IPL 10 is the highest level from which a device 967 * routine can call wakeup. Devices that interrupt from higher 968 * levels are restricted in what they can do. If they need 969 * kernels services they should schedule a routine at a lower 970 * level (via software interrupt) to do the required 971 * processing. 972 * 973 * Examples of this higher usage: 974 * Level Usage 975 * 14 Profiling clock (and PROM uart polling clock) 976 * 12 Serial ports 977 * 978 * The serial ports request lower level processing on level 6. 979 * 980 * Also, almost all splN routines (where N is a number or a 981 * mnemonic) will do a RAISE(), on the assumption that they are 982 * never used to lower our priority. 983 * The exceptions are: 984 * spl8() Because you can't be above 15 to begin with! 985 * splzs() Because this is used at boot time to lower our 986 * priority, to allow the PROM to poll the uart. 987 * spl0() Used to lower priority to 0. 988 */ 989 990#if defined(__lint) 991 992int spl0(void) { return (0); } 993int spl6(void) { return (0); } 994int spl7(void) { return (0); } 995int spl8(void) { return (0); } 996int splhigh(void) { return (0); } 997int splhi(void) { return (0); } 998int splzs(void) { return (0); } 999 1000/* ARGSUSED */ 1001void 1002splx(int level) 1003{} 1004 1005#else /* __lint */ 1006 1007#if defined(__amd64) 1008 1009#define SETPRI(level) \ 1010 movl $/**/level, %edi; /* new priority */ \ 1011 jmp do_splx /* redirect to do_splx */ 1012 1013#define RAISE(level) \ 1014 movl $/**/level, %edi; /* new priority */ \ 1015 jmp splr /* redirect to splr */ 1016 1017#elif defined(__i386) 1018 1019#define SETPRI(level) \ 1020 pushl $/**/level; /* new priority */ \ 1021 call do_splx; /* invoke common splx code */ \ 1022 addl $4, %esp; /* unstack arg */ \ 1023 ret 1024 1025#define RAISE(level) \ 1026 pushl $/**/level; /* new priority */ \ 1027 call splr; /* invoke common splr code */ \ 1028 addl $4, %esp; /* unstack args */ \ 1029 ret 1030 1031#endif /* __i386 */ 1032 1033 /* locks out all interrupts, including memory errors */ 1034 ENTRY(spl8) 1035 SETPRI(15) 1036 SET_SIZE(spl8) 1037 1038 /* just below the level that profiling runs */ 1039 ENTRY(spl7) 1040 RAISE(13) 1041 SET_SIZE(spl7) 1042 1043 /* sun specific - highest priority onboard serial i/o asy ports */ 1044 ENTRY(splzs) 1045 SETPRI(12) /* Can't be a RAISE, as it's used to lower us */ 1046 SET_SIZE(splzs) 1047 1048 ENTRY(splhi) 1049 ALTENTRY(splhigh) 1050 ALTENTRY(spl6) 1051 ALTENTRY(i_ddi_splhigh) 1052 1053 RAISE(DISP_LEVEL) 1054 1055 SET_SIZE(i_ddi_splhigh) 1056 SET_SIZE(spl6) 1057 SET_SIZE(splhigh) 1058 SET_SIZE(splhi) 1059 1060 /* allow all interrupts */ 1061 ENTRY(spl0) 1062 SETPRI(0) 1063 SET_SIZE(spl0) 1064 1065 1066 /* splx implentation */ 1067 ENTRY(splx) 1068 jmp do_splx /* redirect to common splx code */ 1069 SET_SIZE(splx) 1070 1071#endif /* __lint */ 1072 1073#if defined(__i386) 1074 1075/* 1076 * Read and write the %gs register 1077 */ 1078 1079#if defined(__lint) 1080 1081/*ARGSUSED*/ 1082uint16_t 1083getgs(void) 1084{ return (0); } 1085 1086/*ARGSUSED*/ 1087void 1088setgs(uint16_t sel) 1089{} 1090 1091#else /* __lint */ 1092 1093 ENTRY(getgs) 1094 clr %eax 1095 movw %gs, %ax 1096 ret 1097 SET_SIZE(getgs) 1098 1099 ENTRY(setgs) 1100 movw 4(%esp), %gs 1101 ret 1102 SET_SIZE(setgs) 1103 1104#endif /* __lint */ 1105#endif /* __i386 */ 1106 1107#if defined(__lint) 1108 1109void 1110pc_reset(void) 1111{} 1112 1113void 1114efi_reset(void) 1115{} 1116 1117#else /* __lint */ 1118 1119 ENTRY(wait_500ms) 1120 push %ebx 1121 movl $50000, %ebx 11221: 1123 call tenmicrosec 1124 decl %ebx 1125 jnz 1b 1126 pop %ebx 1127 ret 1128 SET_SIZE(wait_500ms) 1129 1130#define RESET_METHOD_KBC 1 1131#define RESET_METHOD_PORT92 2 1132#define RESET_METHOD_PCI 4 1133 1134 DGDEF3(pc_reset_methods, 4, 8) 1135 .long RESET_METHOD_KBC|RESET_METHOD_PORT92|RESET_METHOD_PCI; 1136 1137 ENTRY(pc_reset) 1138 1139#if defined(__i386) 1140 testl $RESET_METHOD_KBC, pc_reset_methods 1141#elif defined(__amd64) 1142 testl $RESET_METHOD_KBC, pc_reset_methods(%rip) 1143#endif 1144 jz 1f 1145 1146 / 1147 / Try the classic keyboard controller-triggered reset. 1148 / 1149 movw $0x64, %dx 1150 movb $0xfe, %al 1151 outb (%dx) 1152 1153 / Wait up to 500 milliseconds here for the keyboard controller 1154 / to pull the reset line. On some systems where the keyboard 1155 / controller is slow to pull the reset line, the next reset method 1156 / may be executed (which may be bad if those systems hang when the 1157 / next reset method is used, e.g. Ferrari 3400 (doesn't like port 92), 1158 / and Ferrari 4000 (doesn't like the cf9 reset method)) 1159 1160 call wait_500ms 1161 11621: 1163#if defined(__i386) 1164 testl $RESET_METHOD_PORT92, pc_reset_methods 1165#elif defined(__amd64) 1166 testl $RESET_METHOD_PORT92, pc_reset_methods(%rip) 1167#endif 1168 jz 3f 1169 1170 / 1171 / Try port 0x92 fast reset 1172 / 1173 movw $0x92, %dx 1174 inb (%dx) 1175 cmpb $0xff, %al / If port's not there, we should get back 0xFF 1176 je 1f 1177 testb $1, %al / If bit 0 1178 jz 2f / is clear, jump to perform the reset 1179 andb $0xfe, %al / otherwise, 1180 outb (%dx) / clear bit 0 first, then 11812: 1182 orb $1, %al / Set bit 0 1183 outb (%dx) / and reset the system 11841: 1185 1186 call wait_500ms 1187 11883: 1189#if defined(__i386) 1190 testl $RESET_METHOD_PCI, pc_reset_methods 1191#elif defined(__amd64) 1192 testl $RESET_METHOD_PCI, pc_reset_methods(%rip) 1193#endif 1194 jz 4f 1195 1196 / Try the PCI (soft) reset vector (should work on all modern systems, 1197 / but has been shown to cause problems on 450NX systems, and some newer 1198 / systems (e.g. ATI IXP400-equipped systems)) 1199 / When resetting via this method, 2 writes are required. The first 1200 / targets bit 1 (0=hard reset without power cycle, 1=hard reset with 1201 / power cycle). 1202 / The reset occurs on the second write, during bit 2's transition from 1203 / 0->1. 1204 movw $0xcf9, %dx 1205 movb $0x2, %al / Reset mode = hard, no power cycle 1206 outb (%dx) 1207 movb $0x6, %al 1208 outb (%dx) 1209 1210 call wait_500ms 1211 12124: 1213 / 1214 / port 0xcf9 failed also. Last-ditch effort is to 1215 / triple-fault the CPU. 1216 / Also, use triple fault for EFI firmware 1217 / 1218 ENTRY(efi_reset) 1219#if defined(__amd64) 1220 pushq $0x0 1221 pushq $0x0 / IDT base of 0, limit of 0 + 2 unused bytes 1222 lidt (%rsp) 1223#elif defined(__i386) 1224 pushl $0x0 1225 pushl $0x0 / IDT base of 0, limit of 0 + 2 unused bytes 1226 lidt (%esp) 1227#endif 1228 int $0x0 / Trigger interrupt, generate triple-fault 1229 1230 cli 1231 hlt / Wait forever 1232 /*NOTREACHED*/ 1233 SET_SIZE(efi_reset) 1234 SET_SIZE(pc_reset) 1235 1236#endif /* __lint */ 1237 1238/* 1239 * C callable in and out routines 1240 */ 1241 1242#if defined(__lint) 1243 1244/* ARGSUSED */ 1245void 1246outl(int port_address, uint32_t val) 1247{} 1248 1249#else /* __lint */ 1250 1251#if defined(__amd64) 1252 1253 ENTRY(outl) 1254 movw %di, %dx 1255 movl %esi, %eax 1256 outl (%dx) 1257 ret 1258 SET_SIZE(outl) 1259 1260#elif defined(__i386) 1261 1262 .set PORT, 4 1263 .set VAL, 8 1264 1265 ENTRY(outl) 1266 movw PORT(%esp), %dx 1267 movl VAL(%esp), %eax 1268 outl (%dx) 1269 ret 1270 SET_SIZE(outl) 1271 1272#endif /* __i386 */ 1273#endif /* __lint */ 1274 1275#if defined(__lint) 1276 1277/* ARGSUSED */ 1278void 1279outw(int port_address, uint16_t val) 1280{} 1281 1282#else /* __lint */ 1283 1284#if defined(__amd64) 1285 1286 ENTRY(outw) 1287 movw %di, %dx 1288 movw %si, %ax 1289 D16 outl (%dx) /* XX64 why not outw? */ 1290 ret 1291 SET_SIZE(outw) 1292 1293#elif defined(__i386) 1294 1295 ENTRY(outw) 1296 movw PORT(%esp), %dx 1297 movw VAL(%esp), %ax 1298 D16 outl (%dx) 1299 ret 1300 SET_SIZE(outw) 1301 1302#endif /* __i386 */ 1303#endif /* __lint */ 1304 1305#if defined(__lint) 1306 1307/* ARGSUSED */ 1308void 1309outb(int port_address, uint8_t val) 1310{} 1311 1312#else /* __lint */ 1313 1314#if defined(__amd64) 1315 1316 ENTRY(outb) 1317 movw %di, %dx 1318 movb %sil, %al 1319 outb (%dx) 1320 ret 1321 SET_SIZE(outb) 1322 1323#elif defined(__i386) 1324 1325 ENTRY(outb) 1326 movw PORT(%esp), %dx 1327 movb VAL(%esp), %al 1328 outb (%dx) 1329 ret 1330 SET_SIZE(outb) 1331 1332#endif /* __i386 */ 1333#endif /* __lint */ 1334 1335#if defined(__lint) 1336 1337/* ARGSUSED */ 1338uint32_t 1339inl(int port_address) 1340{ return (0); } 1341 1342#else /* __lint */ 1343 1344#if defined(__amd64) 1345 1346 ENTRY(inl) 1347 xorl %eax, %eax 1348 movw %di, %dx 1349 inl (%dx) 1350 ret 1351 SET_SIZE(inl) 1352 1353#elif defined(__i386) 1354 1355 ENTRY(inl) 1356 movw PORT(%esp), %dx 1357 inl (%dx) 1358 ret 1359 SET_SIZE(inl) 1360 1361#endif /* __i386 */ 1362#endif /* __lint */ 1363 1364#if defined(__lint) 1365 1366/* ARGSUSED */ 1367uint16_t 1368inw(int port_address) 1369{ return (0); } 1370 1371#else /* __lint */ 1372 1373#if defined(__amd64) 1374 1375 ENTRY(inw) 1376 xorl %eax, %eax 1377 movw %di, %dx 1378 D16 inl (%dx) 1379 ret 1380 SET_SIZE(inw) 1381 1382#elif defined(__i386) 1383 1384 ENTRY(inw) 1385 subl %eax, %eax 1386 movw PORT(%esp), %dx 1387 D16 inl (%dx) 1388 ret 1389 SET_SIZE(inw) 1390 1391#endif /* __i386 */ 1392#endif /* __lint */ 1393 1394 1395#if defined(__lint) 1396 1397/* ARGSUSED */ 1398uint8_t 1399inb(int port_address) 1400{ return (0); } 1401 1402#else /* __lint */ 1403 1404#if defined(__amd64) 1405 1406 ENTRY(inb) 1407 xorl %eax, %eax 1408 movw %di, %dx 1409 inb (%dx) 1410 ret 1411 SET_SIZE(inb) 1412 1413#elif defined(__i386) 1414 1415 ENTRY(inb) 1416 subl %eax, %eax 1417 movw PORT(%esp), %dx 1418 inb (%dx) 1419 ret 1420 SET_SIZE(inb) 1421 1422#endif /* __i386 */ 1423#endif /* __lint */ 1424 1425 1426#if defined(__lint) 1427 1428/* ARGSUSED */ 1429void 1430repoutsw(int port, uint16_t *addr, int cnt) 1431{} 1432 1433#else /* __lint */ 1434 1435#if defined(__amd64) 1436 1437 ENTRY(repoutsw) 1438 movl %edx, %ecx 1439 movw %di, %dx 1440 rep 1441 D16 outsl 1442 ret 1443 SET_SIZE(repoutsw) 1444 1445#elif defined(__i386) 1446 1447 /* 1448 * The arguments and saved registers are on the stack in the 1449 * following order: 1450 * | cnt | +16 1451 * | *addr | +12 1452 * | port | +8 1453 * | eip | +4 1454 * | esi | <-- %esp 1455 * If additional values are pushed onto the stack, make sure 1456 * to adjust the following constants accordingly. 1457 */ 1458 .set PORT, 8 1459 .set ADDR, 12 1460 .set COUNT, 16 1461 1462 ENTRY(repoutsw) 1463 pushl %esi 1464 movl PORT(%esp), %edx 1465 movl ADDR(%esp), %esi 1466 movl COUNT(%esp), %ecx 1467 rep 1468 D16 outsl 1469 popl %esi 1470 ret 1471 SET_SIZE(repoutsw) 1472 1473#endif /* __i386 */ 1474#endif /* __lint */ 1475 1476 1477#if defined(__lint) 1478 1479/* ARGSUSED */ 1480void 1481repinsw(int port_addr, uint16_t *addr, int cnt) 1482{} 1483 1484#else /* __lint */ 1485 1486#if defined(__amd64) 1487 1488 ENTRY(repinsw) 1489 movl %edx, %ecx 1490 movw %di, %dx 1491 rep 1492 D16 insl 1493 ret 1494 SET_SIZE(repinsw) 1495 1496#elif defined(__i386) 1497 1498 ENTRY(repinsw) 1499 pushl %edi 1500 movl PORT(%esp), %edx 1501 movl ADDR(%esp), %edi 1502 movl COUNT(%esp), %ecx 1503 rep 1504 D16 insl 1505 popl %edi 1506 ret 1507 SET_SIZE(repinsw) 1508 1509#endif /* __i386 */ 1510#endif /* __lint */ 1511 1512 1513#if defined(__lint) 1514 1515/* ARGSUSED */ 1516void 1517repinsb(int port, uint8_t *addr, int count) 1518{} 1519 1520#else /* __lint */ 1521 1522#if defined(__amd64) 1523 1524 ENTRY(repinsb) 1525 movl %edx, %ecx 1526 movw %di, %dx 1527 movq %rsi, %rdi 1528 rep 1529 insb 1530 ret 1531 SET_SIZE(repinsb) 1532 1533#elif defined(__i386) 1534 1535 /* 1536 * The arguments and saved registers are on the stack in the 1537 * following order: 1538 * | cnt | +16 1539 * | *addr | +12 1540 * | port | +8 1541 * | eip | +4 1542 * | esi | <-- %esp 1543 * If additional values are pushed onto the stack, make sure 1544 * to adjust the following constants accordingly. 1545 */ 1546 .set IO_PORT, 8 1547 .set IO_ADDR, 12 1548 .set IO_COUNT, 16 1549 1550 ENTRY(repinsb) 1551 pushl %edi 1552 movl IO_ADDR(%esp), %edi 1553 movl IO_COUNT(%esp), %ecx 1554 movl IO_PORT(%esp), %edx 1555 rep 1556 insb 1557 popl %edi 1558 ret 1559 SET_SIZE(repinsb) 1560 1561#endif /* __i386 */ 1562#endif /* __lint */ 1563 1564 1565/* 1566 * Input a stream of 32-bit words. 1567 * NOTE: count is a DWORD count. 1568 */ 1569#if defined(__lint) 1570 1571/* ARGSUSED */ 1572void 1573repinsd(int port, uint32_t *addr, int count) 1574{} 1575 1576#else /* __lint */ 1577 1578#if defined(__amd64) 1579 1580 ENTRY(repinsd) 1581 movl %edx, %ecx 1582 movw %di, %dx 1583 movq %rsi, %rdi 1584 rep 1585 insl 1586 ret 1587 SET_SIZE(repinsd) 1588 1589#elif defined(__i386) 1590 1591 ENTRY(repinsd) 1592 pushl %edi 1593 movl IO_ADDR(%esp), %edi 1594 movl IO_COUNT(%esp), %ecx 1595 movl IO_PORT(%esp), %edx 1596 rep 1597 insl 1598 popl %edi 1599 ret 1600 SET_SIZE(repinsd) 1601 1602#endif /* __i386 */ 1603#endif /* __lint */ 1604 1605/* 1606 * Output a stream of bytes 1607 * NOTE: count is a byte count 1608 */ 1609#if defined(__lint) 1610 1611/* ARGSUSED */ 1612void 1613repoutsb(int port, uint8_t *addr, int count) 1614{} 1615 1616#else /* __lint */ 1617 1618#if defined(__amd64) 1619 1620 ENTRY(repoutsb) 1621 movl %edx, %ecx 1622 movw %di, %dx 1623 rep 1624 outsb 1625 ret 1626 SET_SIZE(repoutsb) 1627 1628#elif defined(__i386) 1629 1630 ENTRY(repoutsb) 1631 pushl %esi 1632 movl IO_ADDR(%esp), %esi 1633 movl IO_COUNT(%esp), %ecx 1634 movl IO_PORT(%esp), %edx 1635 rep 1636 outsb 1637 popl %esi 1638 ret 1639 SET_SIZE(repoutsb) 1640 1641#endif /* __i386 */ 1642#endif /* __lint */ 1643 1644/* 1645 * Output a stream of 32-bit words 1646 * NOTE: count is a DWORD count 1647 */ 1648#if defined(__lint) 1649 1650/* ARGSUSED */ 1651void 1652repoutsd(int port, uint32_t *addr, int count) 1653{} 1654 1655#else /* __lint */ 1656 1657#if defined(__amd64) 1658 1659 ENTRY(repoutsd) 1660 movl %edx, %ecx 1661 movw %di, %dx 1662 rep 1663 outsl 1664 ret 1665 SET_SIZE(repoutsd) 1666 1667#elif defined(__i386) 1668 1669 ENTRY(repoutsd) 1670 pushl %esi 1671 movl IO_ADDR(%esp), %esi 1672 movl IO_COUNT(%esp), %ecx 1673 movl IO_PORT(%esp), %edx 1674 rep 1675 outsl 1676 popl %esi 1677 ret 1678 SET_SIZE(repoutsd) 1679 1680#endif /* __i386 */ 1681#endif /* __lint */ 1682 1683/* 1684 * void int3(void) 1685 * void int18(void) 1686 * void int20(void) 1687 */ 1688 1689#if defined(__lint) 1690 1691void 1692int3(void) 1693{} 1694 1695void 1696int18(void) 1697{} 1698 1699void 1700int20(void) 1701{} 1702 1703#else /* __lint */ 1704 1705 ENTRY(int3) 1706 int $T_BPTFLT 1707 ret 1708 SET_SIZE(int3) 1709 1710 ENTRY(int18) 1711 int $T_MCE 1712 ret 1713 SET_SIZE(int18) 1714 1715 ENTRY(int20) 1716 movl boothowto, %eax 1717 andl $RB_DEBUG, %eax 1718 jz 1f 1719 1720 int $T_DBGENTR 17211: 1722 rep; ret /* use 2 byte return instruction when branch target */ 1723 /* AMD Software Optimization Guide - Section 6.2 */ 1724 SET_SIZE(int20) 1725 1726#endif /* __lint */ 1727 1728#if defined(__lint) 1729 1730/* ARGSUSED */ 1731int 1732scanc(size_t size, uchar_t *cp, uchar_t *table, uchar_t mask) 1733{ return (0); } 1734 1735#else /* __lint */ 1736 1737#if defined(__amd64) 1738 1739 ENTRY(scanc) 1740 /* rdi == size */ 1741 /* rsi == cp */ 1742 /* rdx == table */ 1743 /* rcx == mask */ 1744 addq %rsi, %rdi /* end = &cp[size] */ 1745.scanloop: 1746 cmpq %rdi, %rsi /* while (cp < end */ 1747 jnb .scandone 1748 movzbq (%rsi), %r8 /* %r8 = *cp */ 1749 incq %rsi /* cp++ */ 1750 testb %cl, (%r8, %rdx) 1751 jz .scanloop /* && (table[*cp] & mask) == 0) */ 1752 decq %rsi /* (fix post-increment) */ 1753.scandone: 1754 movl %edi, %eax 1755 subl %esi, %eax /* return (end - cp) */ 1756 ret 1757 SET_SIZE(scanc) 1758 1759#elif defined(__i386) 1760 1761 ENTRY(scanc) 1762 pushl %edi 1763 pushl %esi 1764 movb 24(%esp), %cl /* mask = %cl */ 1765 movl 16(%esp), %esi /* cp = %esi */ 1766 movl 20(%esp), %edx /* table = %edx */ 1767 movl %esi, %edi 1768 addl 12(%esp), %edi /* end = &cp[size]; */ 1769.scanloop: 1770 cmpl %edi, %esi /* while (cp < end */ 1771 jnb .scandone 1772 movzbl (%esi), %eax /* %al = *cp */ 1773 incl %esi /* cp++ */ 1774 movb (%edx, %eax), %al /* %al = table[*cp] */ 1775 testb %al, %cl 1776 jz .scanloop /* && (table[*cp] & mask) == 0) */ 1777 dec %esi /* post-incremented */ 1778.scandone: 1779 movl %edi, %eax 1780 subl %esi, %eax /* return (end - cp) */ 1781 popl %esi 1782 popl %edi 1783 ret 1784 SET_SIZE(scanc) 1785 1786#endif /* __i386 */ 1787#endif /* __lint */ 1788 1789/* 1790 * Replacement functions for ones that are normally inlined. 1791 * In addition to the copy in i86.il, they are defined here just in case. 1792 */ 1793 1794#if defined(__lint) 1795 1796ulong_t 1797intr_clear(void) 1798{ return (0); } 1799 1800ulong_t 1801clear_int_flag(void) 1802{ return (0); } 1803 1804#else /* __lint */ 1805 1806#if defined(__amd64) 1807 1808 ENTRY(intr_clear) 1809 ENTRY(clear_int_flag) 1810 pushfq 1811 popq %rax 1812 CLI(%rdi) 1813 ret 1814 SET_SIZE(clear_int_flag) 1815 SET_SIZE(intr_clear) 1816 1817#elif defined(__i386) 1818 1819 ENTRY(intr_clear) 1820 ENTRY(clear_int_flag) 1821 pushfl 1822 popl %eax 1823 CLI(%edx) 1824 ret 1825 SET_SIZE(clear_int_flag) 1826 SET_SIZE(intr_clear) 1827 1828#endif /* __i386 */ 1829#endif /* __lint */ 1830 1831#if defined(__lint) 1832 1833struct cpu * 1834curcpup(void) 1835{ return 0; } 1836 1837#else /* __lint */ 1838 1839#if defined(__amd64) 1840 1841 ENTRY(curcpup) 1842 movq %gs:CPU_SELF, %rax 1843 ret 1844 SET_SIZE(curcpup) 1845 1846#elif defined(__i386) 1847 1848 ENTRY(curcpup) 1849 movl %gs:CPU_SELF, %eax 1850 ret 1851 SET_SIZE(curcpup) 1852 1853#endif /* __i386 */ 1854#endif /* __lint */ 1855 1856#if defined(__lint) 1857 1858/* ARGSUSED */ 1859uint32_t 1860htonl(uint32_t i) 1861{ return (0); } 1862 1863/* ARGSUSED */ 1864uint32_t 1865ntohl(uint32_t i) 1866{ return (0); } 1867 1868#else /* __lint */ 1869 1870#if defined(__amd64) 1871 1872 /* XX64 there must be shorter sequences for this */ 1873 ENTRY(htonl) 1874 ALTENTRY(ntohl) 1875 movl %edi, %eax 1876 bswap %eax 1877 ret 1878 SET_SIZE(ntohl) 1879 SET_SIZE(htonl) 1880 1881#elif defined(__i386) 1882 1883 ENTRY(htonl) 1884 ALTENTRY(ntohl) 1885 movl 4(%esp), %eax 1886 bswap %eax 1887 ret 1888 SET_SIZE(ntohl) 1889 SET_SIZE(htonl) 1890 1891#endif /* __i386 */ 1892#endif /* __lint */ 1893 1894#if defined(__lint) 1895 1896/* ARGSUSED */ 1897uint16_t 1898htons(uint16_t i) 1899{ return (0); } 1900 1901/* ARGSUSED */ 1902uint16_t 1903ntohs(uint16_t i) 1904{ return (0); } 1905 1906 1907#else /* __lint */ 1908 1909#if defined(__amd64) 1910 1911 /* XX64 there must be better sequences for this */ 1912 ENTRY(htons) 1913 ALTENTRY(ntohs) 1914 movl %edi, %eax 1915 bswap %eax 1916 shrl $16, %eax 1917 ret 1918 SET_SIZE(ntohs) 1919 SET_SIZE(htons) 1920 1921#elif defined(__i386) 1922 1923 ENTRY(htons) 1924 ALTENTRY(ntohs) 1925 movl 4(%esp), %eax 1926 bswap %eax 1927 shrl $16, %eax 1928 ret 1929 SET_SIZE(ntohs) 1930 SET_SIZE(htons) 1931 1932#endif /* __i386 */ 1933#endif /* __lint */ 1934 1935 1936#if defined(__lint) 1937 1938/* ARGSUSED */ 1939void 1940intr_restore(ulong_t i) 1941{ return; } 1942 1943/* ARGSUSED */ 1944void 1945restore_int_flag(ulong_t i) 1946{ return; } 1947 1948#else /* __lint */ 1949 1950#if defined(__amd64) 1951 1952 ENTRY(intr_restore) 1953 ENTRY(restore_int_flag) 1954 pushq %rdi 1955 popfq 1956 ret 1957 SET_SIZE(restore_int_flag) 1958 SET_SIZE(intr_restore) 1959 1960#elif defined(__i386) 1961 1962 ENTRY(intr_restore) 1963 ENTRY(restore_int_flag) 1964 movl 4(%esp), %eax 1965 pushl %eax 1966 popfl 1967 ret 1968 SET_SIZE(restore_int_flag) 1969 SET_SIZE(intr_restore) 1970 1971#endif /* __i386 */ 1972#endif /* __lint */ 1973 1974#if defined(__lint) 1975 1976void 1977sti(void) 1978{} 1979 1980void 1981cli(void) 1982{} 1983 1984#else /* __lint */ 1985 1986 ENTRY(sti) 1987 STI 1988 ret 1989 SET_SIZE(sti) 1990 1991 ENTRY(cli) 1992#if defined(__amd64) 1993 CLI(%rax) 1994#elif defined(__i386) 1995 CLI(%eax) 1996#endif /* __i386 */ 1997 ret 1998 SET_SIZE(cli) 1999 2000#endif /* __lint */ 2001 2002#if defined(__lint) 2003 2004dtrace_icookie_t 2005dtrace_interrupt_disable(void) 2006{ return (0); } 2007 2008#else /* __lint */ 2009 2010#if defined(__amd64) 2011 2012 ENTRY(dtrace_interrupt_disable) 2013 pushfq 2014 popq %rax 2015 CLI(%rdx) 2016 ret 2017 SET_SIZE(dtrace_interrupt_disable) 2018 2019#elif defined(__i386) 2020 2021 ENTRY(dtrace_interrupt_disable) 2022 pushfl 2023 popl %eax 2024 CLI(%edx) 2025 ret 2026 SET_SIZE(dtrace_interrupt_disable) 2027 2028#endif /* __i386 */ 2029#endif /* __lint */ 2030 2031#if defined(__lint) 2032 2033/*ARGSUSED*/ 2034void 2035dtrace_interrupt_enable(dtrace_icookie_t cookie) 2036{} 2037 2038#else /* __lint */ 2039 2040#if defined(__amd64) 2041 2042 ENTRY(dtrace_interrupt_enable) 2043 pushq %rdi 2044 popfq 2045 ret 2046 SET_SIZE(dtrace_interrupt_enable) 2047 2048#elif defined(__i386) 2049 2050 ENTRY(dtrace_interrupt_enable) 2051 movl 4(%esp), %eax 2052 pushl %eax 2053 popfl 2054 ret 2055 SET_SIZE(dtrace_interrupt_enable) 2056 2057#endif /* __i386 */ 2058#endif /* __lint */ 2059 2060 2061#if defined(lint) 2062 2063void 2064dtrace_membar_producer(void) 2065{} 2066 2067void 2068dtrace_membar_consumer(void) 2069{} 2070 2071#else /* __lint */ 2072 2073 ENTRY(dtrace_membar_producer) 2074 rep; ret /* use 2 byte return instruction when branch target */ 2075 /* AMD Software Optimization Guide - Section 6.2 */ 2076 SET_SIZE(dtrace_membar_producer) 2077 2078 ENTRY(dtrace_membar_consumer) 2079 rep; ret /* use 2 byte return instruction when branch target */ 2080 /* AMD Software Optimization Guide - Section 6.2 */ 2081 SET_SIZE(dtrace_membar_consumer) 2082 2083#endif /* __lint */ 2084 2085#if defined(__lint) 2086 2087kthread_id_t 2088threadp(void) 2089{ return ((kthread_id_t)0); } 2090 2091#else /* __lint */ 2092 2093#if defined(__amd64) 2094 2095 ENTRY(threadp) 2096 movq %gs:CPU_THREAD, %rax 2097 ret 2098 SET_SIZE(threadp) 2099 2100#elif defined(__i386) 2101 2102 ENTRY(threadp) 2103 movl %gs:CPU_THREAD, %eax 2104 ret 2105 SET_SIZE(threadp) 2106 2107#endif /* __i386 */ 2108#endif /* __lint */ 2109 2110/* 2111 * Checksum routine for Internet Protocol Headers 2112 */ 2113 2114#if defined(__lint) 2115 2116/* ARGSUSED */ 2117unsigned int 2118ip_ocsum( 2119 ushort_t *address, /* ptr to 1st message buffer */ 2120 int halfword_count, /* length of data */ 2121 unsigned int sum) /* partial checksum */ 2122{ 2123 int i; 2124 unsigned int psum = 0; /* partial sum */ 2125 2126 for (i = 0; i < halfword_count; i++, address++) { 2127 psum += *address; 2128 } 2129 2130 while ((psum >> 16) != 0) { 2131 psum = (psum & 0xffff) + (psum >> 16); 2132 } 2133 2134 psum += sum; 2135 2136 while ((psum >> 16) != 0) { 2137 psum = (psum & 0xffff) + (psum >> 16); 2138 } 2139 2140 return (psum); 2141} 2142 2143#else /* __lint */ 2144 2145#if defined(__amd64) 2146 2147 ENTRY(ip_ocsum) 2148 pushq %rbp 2149 movq %rsp, %rbp 2150#ifdef DEBUG 2151 movq postbootkernelbase(%rip), %rax 2152 cmpq %rax, %rdi 2153 jnb 1f 2154 xorl %eax, %eax 2155 movq %rdi, %rsi 2156 leaq .ip_ocsum_panic_msg(%rip), %rdi 2157 call panic 2158 /*NOTREACHED*/ 2159.ip_ocsum_panic_msg: 2160 .string "ip_ocsum: address 0x%p below kernelbase\n" 21611: 2162#endif 2163 movl %esi, %ecx /* halfword_count */ 2164 movq %rdi, %rsi /* address */ 2165 /* partial sum in %edx */ 2166 xorl %eax, %eax 2167 testl %ecx, %ecx 2168 jz .ip_ocsum_done 2169 testq $3, %rsi 2170 jnz .ip_csum_notaligned 2171.ip_csum_aligned: /* XX64 opportunities for 8-byte operations? */ 2172.next_iter: 2173 /* XX64 opportunities for prefetch? */ 2174 /* XX64 compute csum with 64 bit quantities? */ 2175 subl $32, %ecx 2176 jl .less_than_32 2177 2178 addl 0(%rsi), %edx 2179.only60: 2180 adcl 4(%rsi), %eax 2181.only56: 2182 adcl 8(%rsi), %edx 2183.only52: 2184 adcl 12(%rsi), %eax 2185.only48: 2186 adcl 16(%rsi), %edx 2187.only44: 2188 adcl 20(%rsi), %eax 2189.only40: 2190 adcl 24(%rsi), %edx 2191.only36: 2192 adcl 28(%rsi), %eax 2193.only32: 2194 adcl 32(%rsi), %edx 2195.only28: 2196 adcl 36(%rsi), %eax 2197.only24: 2198 adcl 40(%rsi), %edx 2199.only20: 2200 adcl 44(%rsi), %eax 2201.only16: 2202 adcl 48(%rsi), %edx 2203.only12: 2204 adcl 52(%rsi), %eax 2205.only8: 2206 adcl 56(%rsi), %edx 2207.only4: 2208 adcl 60(%rsi), %eax /* could be adding -1 and -1 with a carry */ 2209.only0: 2210 adcl $0, %eax /* could be adding -1 in eax with a carry */ 2211 adcl $0, %eax 2212 2213 addq $64, %rsi 2214 testl %ecx, %ecx 2215 jnz .next_iter 2216 2217.ip_ocsum_done: 2218 addl %eax, %edx 2219 adcl $0, %edx 2220 movl %edx, %eax /* form a 16 bit checksum by */ 2221 shrl $16, %eax /* adding two halves of 32 bit checksum */ 2222 addw %dx, %ax 2223 adcw $0, %ax 2224 andl $0xffff, %eax 2225 leave 2226 ret 2227 2228.ip_csum_notaligned: 2229 xorl %edi, %edi 2230 movw (%rsi), %di 2231 addl %edi, %edx 2232 adcl $0, %edx 2233 addq $2, %rsi 2234 decl %ecx 2235 jmp .ip_csum_aligned 2236 2237.less_than_32: 2238 addl $32, %ecx 2239 testl $1, %ecx 2240 jz .size_aligned 2241 andl $0xfe, %ecx 2242 movzwl (%rsi, %rcx, 2), %edi 2243 addl %edi, %edx 2244 adcl $0, %edx 2245.size_aligned: 2246 movl %ecx, %edi 2247 shrl $1, %ecx 2248 shl $1, %edi 2249 subq $64, %rdi 2250 addq %rdi, %rsi 2251 leaq .ip_ocsum_jmptbl(%rip), %rdi 2252 leaq (%rdi, %rcx, 8), %rdi 2253 xorl %ecx, %ecx 2254 clc 2255 jmp *(%rdi) 2256 2257 .align 8 2258.ip_ocsum_jmptbl: 2259 .quad .only0, .only4, .only8, .only12, .only16, .only20 2260 .quad .only24, .only28, .only32, .only36, .only40, .only44 2261 .quad .only48, .only52, .only56, .only60 2262 SET_SIZE(ip_ocsum) 2263 2264#elif defined(__i386) 2265 2266 ENTRY(ip_ocsum) 2267 pushl %ebp 2268 movl %esp, %ebp 2269 pushl %ebx 2270 pushl %esi 2271 pushl %edi 2272 movl 12(%ebp), %ecx /* count of half words */ 2273 movl 16(%ebp), %edx /* partial checksum */ 2274 movl 8(%ebp), %esi 2275 xorl %eax, %eax 2276 testl %ecx, %ecx 2277 jz .ip_ocsum_done 2278 2279 testl $3, %esi 2280 jnz .ip_csum_notaligned 2281.ip_csum_aligned: 2282.next_iter: 2283 subl $32, %ecx 2284 jl .less_than_32 2285 2286 addl 0(%esi), %edx 2287.only60: 2288 adcl 4(%esi), %eax 2289.only56: 2290 adcl 8(%esi), %edx 2291.only52: 2292 adcl 12(%esi), %eax 2293.only48: 2294 adcl 16(%esi), %edx 2295.only44: 2296 adcl 20(%esi), %eax 2297.only40: 2298 adcl 24(%esi), %edx 2299.only36: 2300 adcl 28(%esi), %eax 2301.only32: 2302 adcl 32(%esi), %edx 2303.only28: 2304 adcl 36(%esi), %eax 2305.only24: 2306 adcl 40(%esi), %edx 2307.only20: 2308 adcl 44(%esi), %eax 2309.only16: 2310 adcl 48(%esi), %edx 2311.only12: 2312 adcl 52(%esi), %eax 2313.only8: 2314 adcl 56(%esi), %edx 2315.only4: 2316 adcl 60(%esi), %eax /* We could be adding -1 and -1 with a carry */ 2317.only0: 2318 adcl $0, %eax /* we could be adding -1 in eax with a carry */ 2319 adcl $0, %eax 2320 2321 addl $64, %esi 2322 andl %ecx, %ecx 2323 jnz .next_iter 2324 2325.ip_ocsum_done: 2326 addl %eax, %edx 2327 adcl $0, %edx 2328 movl %edx, %eax /* form a 16 bit checksum by */ 2329 shrl $16, %eax /* adding two halves of 32 bit checksum */ 2330 addw %dx, %ax 2331 adcw $0, %ax 2332 andl $0xffff, %eax 2333 popl %edi /* restore registers */ 2334 popl %esi 2335 popl %ebx 2336 leave 2337 ret 2338 2339.ip_csum_notaligned: 2340 xorl %edi, %edi 2341 movw (%esi), %di 2342 addl %edi, %edx 2343 adcl $0, %edx 2344 addl $2, %esi 2345 decl %ecx 2346 jmp .ip_csum_aligned 2347 2348.less_than_32: 2349 addl $32, %ecx 2350 testl $1, %ecx 2351 jz .size_aligned 2352 andl $0xfe, %ecx 2353 movzwl (%esi, %ecx, 2), %edi 2354 addl %edi, %edx 2355 adcl $0, %edx 2356.size_aligned: 2357 movl %ecx, %edi 2358 shrl $1, %ecx 2359 shl $1, %edi 2360 subl $64, %edi 2361 addl %edi, %esi 2362 movl $.ip_ocsum_jmptbl, %edi 2363 lea (%edi, %ecx, 4), %edi 2364 xorl %ecx, %ecx 2365 clc 2366 jmp *(%edi) 2367 SET_SIZE(ip_ocsum) 2368 2369 .data 2370 .align 4 2371 2372.ip_ocsum_jmptbl: 2373 .long .only0, .only4, .only8, .only12, .only16, .only20 2374 .long .only24, .only28, .only32, .only36, .only40, .only44 2375 .long .only48, .only52, .only56, .only60 2376 2377 2378#endif /* __i386 */ 2379#endif /* __lint */ 2380 2381/* 2382 * multiply two long numbers and yield a u_longlong_t result, callable from C. 2383 * Provided to manipulate hrtime_t values. 2384 */ 2385#if defined(__lint) 2386 2387/* result = a * b; */ 2388 2389/* ARGSUSED */ 2390unsigned long long 2391mul32(uint_t a, uint_t b) 2392{ return (0); } 2393 2394#else /* __lint */ 2395 2396#if defined(__amd64) 2397 2398 ENTRY(mul32) 2399 xorl %edx, %edx /* XX64 joe, paranoia? */ 2400 movl %edi, %eax 2401 mull %esi 2402 shlq $32, %rdx 2403 orq %rdx, %rax 2404 ret 2405 SET_SIZE(mul32) 2406 2407#elif defined(__i386) 2408 2409 ENTRY(mul32) 2410 movl 8(%esp), %eax 2411 movl 4(%esp), %ecx 2412 mull %ecx 2413 ret 2414 SET_SIZE(mul32) 2415 2416#endif /* __i386 */ 2417#endif /* __lint */ 2418 2419#if defined(notused) 2420#if defined(__lint) 2421/* ARGSUSED */ 2422void 2423load_pte64(uint64_t *pte, uint64_t pte_value) 2424{} 2425#else /* __lint */ 2426 .globl load_pte64 2427load_pte64: 2428 movl 4(%esp), %eax 2429 movl 8(%esp), %ecx 2430 movl 12(%esp), %edx 2431 movl %edx, 4(%eax) 2432 movl %ecx, (%eax) 2433 ret 2434#endif /* __lint */ 2435#endif /* notused */ 2436 2437#if defined(__lint) 2438 2439/*ARGSUSED*/ 2440void 2441scan_memory(caddr_t addr, size_t size) 2442{} 2443 2444#else /* __lint */ 2445 2446#if defined(__amd64) 2447 2448 ENTRY(scan_memory) 2449 shrq $3, %rsi /* convert %rsi from byte to quadword count */ 2450 jz .scanm_done 2451 movq %rsi, %rcx /* move count into rep control register */ 2452 movq %rdi, %rsi /* move addr into lodsq control reg. */ 2453 rep lodsq /* scan the memory range */ 2454.scanm_done: 2455 rep; ret /* use 2 byte return instruction when branch target */ 2456 /* AMD Software Optimization Guide - Section 6.2 */ 2457 SET_SIZE(scan_memory) 2458 2459#elif defined(__i386) 2460 2461 ENTRY(scan_memory) 2462 pushl %ecx 2463 pushl %esi 2464 movl 16(%esp), %ecx /* move 2nd arg into rep control register */ 2465 shrl $2, %ecx /* convert from byte count to word count */ 2466 jz .scanm_done 2467 movl 12(%esp), %esi /* move 1st arg into lodsw control register */ 2468 .byte 0xf3 /* rep prefix. lame assembler. sigh. */ 2469 lodsl 2470.scanm_done: 2471 popl %esi 2472 popl %ecx 2473 ret 2474 SET_SIZE(scan_memory) 2475 2476#endif /* __i386 */ 2477#endif /* __lint */ 2478 2479 2480#if defined(__lint) 2481 2482/*ARGSUSED */ 2483int 2484lowbit(ulong_t i) 2485{ return (0); } 2486 2487#else /* __lint */ 2488 2489#if defined(__amd64) 2490 2491 ENTRY(lowbit) 2492 movl $-1, %eax 2493 bsfq %rdi, %rax 2494 incl %eax 2495 ret 2496 SET_SIZE(lowbit) 2497 2498#elif defined(__i386) 2499 2500 ENTRY(lowbit) 2501 movl $-1, %eax 2502 bsfl 4(%esp), %eax 2503 incl %eax 2504 ret 2505 SET_SIZE(lowbit) 2506 2507#endif /* __i386 */ 2508#endif /* __lint */ 2509 2510#if defined(__lint) 2511 2512/*ARGSUSED*/ 2513int 2514highbit(ulong_t i) 2515{ return (0); } 2516 2517#else /* __lint */ 2518 2519#if defined(__amd64) 2520 2521 ENTRY(highbit) 2522 movl $-1, %eax 2523 bsrq %rdi, %rax 2524 incl %eax 2525 ret 2526 SET_SIZE(highbit) 2527 2528#elif defined(__i386) 2529 2530 ENTRY(highbit) 2531 movl $-1, %eax 2532 bsrl 4(%esp), %eax 2533 incl %eax 2534 ret 2535 SET_SIZE(highbit) 2536 2537#endif /* __i386 */ 2538#endif /* __lint */ 2539 2540#if defined(__lint) 2541 2542/*ARGSUSED*/ 2543uint64_t 2544rdmsr(uint_t r) 2545{ return (0); } 2546 2547/*ARGSUSED*/ 2548void 2549wrmsr(uint_t r, const uint64_t val) 2550{} 2551 2552/*ARGSUSED*/ 2553uint64_t 2554xrdmsr(uint_t r) 2555{ return (0); } 2556 2557/*ARGSUSED*/ 2558void 2559xwrmsr(uint_t r, const uint64_t val) 2560{} 2561 2562void 2563invalidate_cache(void) 2564{} 2565 2566#else /* __lint */ 2567 2568#define XMSR_ACCESS_VAL $0x9c5a203a 2569 2570#if defined(__amd64) 2571 2572 ENTRY(rdmsr) 2573 movl %edi, %ecx 2574 rdmsr 2575 shlq $32, %rdx 2576 orq %rdx, %rax 2577 ret 2578 SET_SIZE(rdmsr) 2579 2580 ENTRY(wrmsr) 2581 movq %rsi, %rdx 2582 shrq $32, %rdx 2583 movl %esi, %eax 2584 movl %edi, %ecx 2585 wrmsr 2586 ret 2587 SET_SIZE(wrmsr) 2588 2589 ENTRY(xrdmsr) 2590 pushq %rbp 2591 movq %rsp, %rbp 2592 movl %edi, %ecx 2593 movl XMSR_ACCESS_VAL, %edi /* this value is needed to access MSR */ 2594 rdmsr 2595 shlq $32, %rdx 2596 orq %rdx, %rax 2597 leave 2598 ret 2599 SET_SIZE(xrdmsr) 2600 2601 ENTRY(xwrmsr) 2602 pushq %rbp 2603 movq %rsp, %rbp 2604 movl %edi, %ecx 2605 movl XMSR_ACCESS_VAL, %edi /* this value is needed to access MSR */ 2606 movq %rsi, %rdx 2607 shrq $32, %rdx 2608 movl %esi, %eax 2609 wrmsr 2610 leave 2611 ret 2612 SET_SIZE(xwrmsr) 2613 2614#elif defined(__i386) 2615 2616 ENTRY(rdmsr) 2617 movl 4(%esp), %ecx 2618 rdmsr 2619 ret 2620 SET_SIZE(rdmsr) 2621 2622 ENTRY(wrmsr) 2623 movl 4(%esp), %ecx 2624 movl 8(%esp), %eax 2625 movl 12(%esp), %edx 2626 wrmsr 2627 ret 2628 SET_SIZE(wrmsr) 2629 2630 ENTRY(xrdmsr) 2631 pushl %ebp 2632 movl %esp, %ebp 2633 movl 8(%esp), %ecx 2634 pushl %edi 2635 movl XMSR_ACCESS_VAL, %edi /* this value is needed to access MSR */ 2636 rdmsr 2637 popl %edi 2638 leave 2639 ret 2640 SET_SIZE(xrdmsr) 2641 2642 ENTRY(xwrmsr) 2643 pushl %ebp 2644 movl %esp, %ebp 2645 movl 8(%esp), %ecx 2646 movl 12(%esp), %eax 2647 movl 16(%esp), %edx 2648 pushl %edi 2649 movl XMSR_ACCESS_VAL, %edi /* this value is needed to access MSR */ 2650 wrmsr 2651 popl %edi 2652 leave 2653 ret 2654 SET_SIZE(xwrmsr) 2655 2656#endif /* __i386 */ 2657 2658 ENTRY(invalidate_cache) 2659 wbinvd 2660 ret 2661 SET_SIZE(invalidate_cache) 2662 2663#endif /* __lint */ 2664 2665#if defined(__lint) 2666 2667/*ARGSUSED*/ 2668void 2669getcregs(struct cregs *crp) 2670{} 2671 2672#else /* __lint */ 2673 2674#if defined(__amd64) 2675 2676 ENTRY_NP(getcregs) 2677 2678#define GETMSR(r, off, d) \ 2679 movl $r, %ecx; \ 2680 rdmsr; \ 2681 movl %eax, off(d); \ 2682 movl %edx, off+4(d) 2683 2684 xorl %eax, %eax 2685 movq %rax, CREG_GDT+8(%rdi) 2686 sgdt CREG_GDT(%rdi) /* 10 bytes */ 2687 movq %rax, CREG_IDT+8(%rdi) 2688 sidt CREG_IDT(%rdi) /* 10 bytes */ 2689 movq %rax, CREG_LDT(%rdi) 2690 sldt CREG_LDT(%rdi) /* 2 bytes */ 2691 movq %rax, CREG_TASKR(%rdi) 2692 str CREG_TASKR(%rdi) /* 2 bytes */ 2693 movq %cr0, %rax 2694 movq %rax, CREG_CR0(%rdi) /* cr0 */ 2695 movq %cr2, %rax 2696 movq %rax, CREG_CR2(%rdi) /* cr2 */ 2697 movq %cr3, %rax 2698 movq %rax, CREG_CR3(%rdi) /* cr3 */ 2699 movq %cr4, %rax 2700 movq %rax, CREG_CR4(%rdi) /* cr4 */ 2701 movq %cr8, %rax 2702 movq %rax, CREG_CR8(%rdi) /* cr8 */ 2703 GETMSR(MSR_AMD_KGSBASE, CREG_KGSBASE, %rdi) 2704 GETMSR(MSR_AMD_EFER, CREG_EFER, %rdi) 2705 ret 2706 SET_SIZE(getcregs) 2707 2708#undef GETMSR 2709 2710#elif defined(__i386) 2711 2712 ENTRY_NP(getcregs) 2713 movl 4(%esp), %edx 2714 movw $0, CREG_GDT+6(%edx) 2715 movw $0, CREG_IDT+6(%edx) 2716 sgdt CREG_GDT(%edx) /* gdt */ 2717 sidt CREG_IDT(%edx) /* idt */ 2718 sldt CREG_LDT(%edx) /* ldt */ 2719 str CREG_TASKR(%edx) /* task */ 2720 movl %cr0, %eax 2721 movl %eax, CREG_CR0(%edx) /* cr0 */ 2722 movl %cr2, %eax 2723 movl %eax, CREG_CR2(%edx) /* cr2 */ 2724 movl %cr3, %eax 2725 movl %eax, CREG_CR3(%edx) /* cr3 */ 2726 testl $X86_LARGEPAGE, x86_feature 2727 jz .nocr4 2728 movl %cr4, %eax 2729 movl %eax, CREG_CR4(%edx) /* cr4 */ 2730 jmp .skip 2731.nocr4: 2732 movl $0, CREG_CR4(%edx) 2733.skip: 2734 ret 2735 SET_SIZE(getcregs) 2736 2737#endif /* __i386 */ 2738#endif /* __lint */ 2739 2740 2741/* 2742 * A panic trigger is a word which is updated atomically and can only be set 2743 * once. We atomically store 0xDEFACEDD and load the old value. If the 2744 * previous value was 0, we succeed and return 1; otherwise return 0. 2745 * This allows a partially corrupt trigger to still trigger correctly. DTrace 2746 * has its own version of this function to allow it to panic correctly from 2747 * probe context. 2748 */ 2749#if defined(__lint) 2750 2751/*ARGSUSED*/ 2752int 2753panic_trigger(int *tp) 2754{ return (0); } 2755 2756/*ARGSUSED*/ 2757int 2758dtrace_panic_trigger(int *tp) 2759{ return (0); } 2760 2761#else /* __lint */ 2762 2763#if defined(__amd64) 2764 2765 ENTRY_NP(panic_trigger) 2766 xorl %eax, %eax 2767 movl $0xdefacedd, %edx 2768 lock 2769 xchgl %edx, (%rdi) 2770 cmpl $0, %edx 2771 je 0f 2772 movl $0, %eax 2773 ret 27740: movl $1, %eax 2775 ret 2776 SET_SIZE(panic_trigger) 2777 2778 ENTRY_NP(dtrace_panic_trigger) 2779 xorl %eax, %eax 2780 movl $0xdefacedd, %edx 2781 lock 2782 xchgl %edx, (%rdi) 2783 cmpl $0, %edx 2784 je 0f 2785 movl $0, %eax 2786 ret 27870: movl $1, %eax 2788 ret 2789 SET_SIZE(dtrace_panic_trigger) 2790 2791#elif defined(__i386) 2792 2793 ENTRY_NP(panic_trigger) 2794 movl 4(%esp), %edx / %edx = address of trigger 2795 movl $0xdefacedd, %eax / %eax = 0xdefacedd 2796 lock / assert lock 2797 xchgl %eax, (%edx) / exchange %eax and the trigger 2798 cmpl $0, %eax / if (%eax == 0x0) 2799 je 0f / return (1); 2800 movl $0, %eax / else 2801 ret / return (0); 28020: movl $1, %eax 2803 ret 2804 SET_SIZE(panic_trigger) 2805 2806 ENTRY_NP(dtrace_panic_trigger) 2807 movl 4(%esp), %edx / %edx = address of trigger 2808 movl $0xdefacedd, %eax / %eax = 0xdefacedd 2809 lock / assert lock 2810 xchgl %eax, (%edx) / exchange %eax and the trigger 2811 cmpl $0, %eax / if (%eax == 0x0) 2812 je 0f / return (1); 2813 movl $0, %eax / else 2814 ret / return (0); 28150: movl $1, %eax 2816 ret 2817 SET_SIZE(dtrace_panic_trigger) 2818 2819#endif /* __i386 */ 2820#endif /* __lint */ 2821 2822/* 2823 * The panic() and cmn_err() functions invoke vpanic() as a common entry point 2824 * into the panic code implemented in panicsys(). vpanic() is responsible 2825 * for passing through the format string and arguments, and constructing a 2826 * regs structure on the stack into which it saves the current register 2827 * values. If we are not dying due to a fatal trap, these registers will 2828 * then be preserved in panicbuf as the current processor state. Before 2829 * invoking panicsys(), vpanic() activates the first panic trigger (see 2830 * common/os/panic.c) and switches to the panic_stack if successful. Note that 2831 * DTrace takes a slightly different panic path if it must panic from probe 2832 * context. Instead of calling panic, it calls into dtrace_vpanic(), which 2833 * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and 2834 * branches back into vpanic(). 2835 */ 2836#if defined(__lint) 2837 2838/*ARGSUSED*/ 2839void 2840vpanic(const char *format, va_list alist) 2841{} 2842 2843/*ARGSUSED*/ 2844void 2845dtrace_vpanic(const char *format, va_list alist) 2846{} 2847 2848#else /* __lint */ 2849 2850#if defined(__amd64) 2851 2852 ENTRY_NP(vpanic) /* Initial stack layout: */ 2853 2854 pushq %rbp /* | %rip | 0x60 */ 2855 movq %rsp, %rbp /* | %rbp | 0x58 */ 2856 pushfq /* | rfl | 0x50 */ 2857 pushq %r11 /* | %r11 | 0x48 */ 2858 pushq %r10 /* | %r10 | 0x40 */ 2859 pushq %rbx /* | %rbx | 0x38 */ 2860 pushq %rax /* | %rax | 0x30 */ 2861 pushq %r9 /* | %r9 | 0x28 */ 2862 pushq %r8 /* | %r8 | 0x20 */ 2863 pushq %rcx /* | %rcx | 0x18 */ 2864 pushq %rdx /* | %rdx | 0x10 */ 2865 pushq %rsi /* | %rsi | 0x8 alist */ 2866 pushq %rdi /* | %rdi | 0x0 format */ 2867 2868 movq %rsp, %rbx /* %rbx = current %rsp */ 2869 2870 leaq panic_quiesce(%rip), %rdi /* %rdi = &panic_quiesce */ 2871 call panic_trigger /* %eax = panic_trigger() */ 2872 2873vpanic_common: 2874 /* 2875 * The panic_trigger result is in %eax from the call above, and 2876 * dtrace_panic places it in %eax before branching here. 2877 * The rdmsr instructions that follow below will clobber %eax so 2878 * we stash the panic_trigger result in %r11d. 2879 */ 2880 movl %eax, %r11d 2881 cmpl $0, %r11d 2882 je 0f 2883 2884 /* 2885 * If panic_trigger() was successful, we are the first to initiate a 2886 * panic: we now switch to the reserved panic_stack before continuing. 2887 */ 2888 leaq panic_stack(%rip), %rsp 2889 addq $PANICSTKSIZE, %rsp 28900: subq $REGSIZE, %rsp 2891 /* 2892 * Now that we've got everything set up, store the register values as 2893 * they were when we entered vpanic() to the designated location in 2894 * the regs structure we allocated on the stack. 2895 */ 2896 movq 0x0(%rbx), %rcx 2897 movq %rcx, REGOFF_RDI(%rsp) 2898 movq 0x8(%rbx), %rcx 2899 movq %rcx, REGOFF_RSI(%rsp) 2900 movq 0x10(%rbx), %rcx 2901 movq %rcx, REGOFF_RDX(%rsp) 2902 movq 0x18(%rbx), %rcx 2903 movq %rcx, REGOFF_RCX(%rsp) 2904 movq 0x20(%rbx), %rcx 2905 2906 movq %rcx, REGOFF_R8(%rsp) 2907 movq 0x28(%rbx), %rcx 2908 movq %rcx, REGOFF_R9(%rsp) 2909 movq 0x30(%rbx), %rcx 2910 movq %rcx, REGOFF_RAX(%rsp) 2911 movq 0x38(%rbx), %rcx 2912 movq %rcx, REGOFF_RBX(%rsp) 2913 movq 0x58(%rbx), %rcx 2914 2915 movq %rcx, REGOFF_RBP(%rsp) 2916 movq 0x40(%rbx), %rcx 2917 movq %rcx, REGOFF_R10(%rsp) 2918 movq 0x48(%rbx), %rcx 2919 movq %rcx, REGOFF_R11(%rsp) 2920 movq %r12, REGOFF_R12(%rsp) 2921 2922 movq %r13, REGOFF_R13(%rsp) 2923 movq %r14, REGOFF_R14(%rsp) 2924 movq %r15, REGOFF_R15(%rsp) 2925 2926 xorl %ecx, %ecx 2927 movw %ds, %cx 2928 movq %rcx, REGOFF_DS(%rsp) 2929 movw %es, %cx 2930 movq %rcx, REGOFF_ES(%rsp) 2931 movw %fs, %cx 2932 movq %rcx, REGOFF_FS(%rsp) 2933 movw %gs, %cx 2934 movq %rcx, REGOFF_GS(%rsp) 2935 2936 movq $0, REGOFF_TRAPNO(%rsp) 2937 2938 movq $0, REGOFF_ERR(%rsp) 2939 leaq vpanic(%rip), %rcx 2940 movq %rcx, REGOFF_RIP(%rsp) 2941 movw %cs, %cx 2942 movzwq %cx, %rcx 2943 movq %rcx, REGOFF_CS(%rsp) 2944 movq 0x50(%rbx), %rcx 2945 movq %rcx, REGOFF_RFL(%rsp) 2946 movq %rbx, %rcx 2947 addq $0x60, %rcx 2948 movq %rcx, REGOFF_RSP(%rsp) 2949 movw %ss, %cx 2950 movzwq %cx, %rcx 2951 movq %rcx, REGOFF_SS(%rsp) 2952 2953 /* 2954 * panicsys(format, alist, rp, on_panic_stack) 2955 */ 2956 movq REGOFF_RDI(%rsp), %rdi /* format */ 2957 movq REGOFF_RSI(%rsp), %rsi /* alist */ 2958 movq %rsp, %rdx /* struct regs */ 2959 movl %r11d, %ecx /* on_panic_stack */ 2960 call panicsys 2961 addq $REGSIZE, %rsp 2962 popq %rdi 2963 popq %rsi 2964 popq %rdx 2965 popq %rcx 2966 popq %r8 2967 popq %r9 2968 popq %rax 2969 popq %rbx 2970 popq %r10 2971 popq %r11 2972 popfq 2973 leave 2974 ret 2975 SET_SIZE(vpanic) 2976 2977 ENTRY_NP(dtrace_vpanic) /* Initial stack layout: */ 2978 2979 pushq %rbp /* | %rip | 0x60 */ 2980 movq %rsp, %rbp /* | %rbp | 0x58 */ 2981 pushfq /* | rfl | 0x50 */ 2982 pushq %r11 /* | %r11 | 0x48 */ 2983 pushq %r10 /* | %r10 | 0x40 */ 2984 pushq %rbx /* | %rbx | 0x38 */ 2985 pushq %rax /* | %rax | 0x30 */ 2986 pushq %r9 /* | %r9 | 0x28 */ 2987 pushq %r8 /* | %r8 | 0x20 */ 2988 pushq %rcx /* | %rcx | 0x18 */ 2989 pushq %rdx /* | %rdx | 0x10 */ 2990 pushq %rsi /* | %rsi | 0x8 alist */ 2991 pushq %rdi /* | %rdi | 0x0 format */ 2992 2993 movq %rsp, %rbx /* %rbx = current %rsp */ 2994 2995 leaq panic_quiesce(%rip), %rdi /* %rdi = &panic_quiesce */ 2996 call dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */ 2997 jmp vpanic_common 2998 2999 SET_SIZE(dtrace_vpanic) 3000 3001#elif defined(__i386) 3002 3003 ENTRY_NP(vpanic) / Initial stack layout: 3004 3005 pushl %ebp / | %eip | 20 3006 movl %esp, %ebp / | %ebp | 16 3007 pushl %eax / | %eax | 12 3008 pushl %ebx / | %ebx | 8 3009 pushl %ecx / | %ecx | 4 3010 pushl %edx / | %edx | 0 3011 3012 movl %esp, %ebx / %ebx = current stack pointer 3013 3014 lea panic_quiesce, %eax / %eax = &panic_quiesce 3015 pushl %eax / push &panic_quiesce 3016 call panic_trigger / %eax = panic_trigger() 3017 addl $4, %esp / reset stack pointer 3018 3019vpanic_common: 3020 cmpl $0, %eax / if (%eax == 0) 3021 je 0f / goto 0f; 3022 3023 /* 3024 * If panic_trigger() was successful, we are the first to initiate a 3025 * panic: we now switch to the reserved panic_stack before continuing. 3026 */ 3027 lea panic_stack, %esp / %esp = panic_stack 3028 addl $PANICSTKSIZE, %esp / %esp += PANICSTKSIZE 3029 30300: subl $REGSIZE, %esp / allocate struct regs 3031 3032 /* 3033 * Now that we've got everything set up, store the register values as 3034 * they were when we entered vpanic() to the designated location in 3035 * the regs structure we allocated on the stack. 3036 */ 3037#if !defined(__GNUC_AS__) 3038 movw %gs, %edx 3039 movl %edx, REGOFF_GS(%esp) 3040 movw %fs, %edx 3041 movl %edx, REGOFF_FS(%esp) 3042 movw %es, %edx 3043 movl %edx, REGOFF_ES(%esp) 3044 movw %ds, %edx 3045 movl %edx, REGOFF_DS(%esp) 3046#else /* __GNUC_AS__ */ 3047 mov %gs, %edx 3048 mov %edx, REGOFF_GS(%esp) 3049 mov %fs, %edx 3050 mov %edx, REGOFF_FS(%esp) 3051 mov %es, %edx 3052 mov %edx, REGOFF_ES(%esp) 3053 mov %ds, %edx 3054 mov %edx, REGOFF_DS(%esp) 3055#endif /* __GNUC_AS__ */ 3056 movl %edi, REGOFF_EDI(%esp) 3057 movl %esi, REGOFF_ESI(%esp) 3058 movl 16(%ebx), %ecx 3059 movl %ecx, REGOFF_EBP(%esp) 3060 movl %ebx, %ecx 3061 addl $20, %ecx 3062 movl %ecx, REGOFF_ESP(%esp) 3063 movl 8(%ebx), %ecx 3064 movl %ecx, REGOFF_EBX(%esp) 3065 movl 0(%ebx), %ecx 3066 movl %ecx, REGOFF_EDX(%esp) 3067 movl 4(%ebx), %ecx 3068 movl %ecx, REGOFF_ECX(%esp) 3069 movl 12(%ebx), %ecx 3070 movl %ecx, REGOFF_EAX(%esp) 3071 movl $0, REGOFF_TRAPNO(%esp) 3072 movl $0, REGOFF_ERR(%esp) 3073 lea vpanic, %ecx 3074 movl %ecx, REGOFF_EIP(%esp) 3075#if !defined(__GNUC_AS__) 3076 movw %cs, %edx 3077#else /* __GNUC_AS__ */ 3078 mov %cs, %edx 3079#endif /* __GNUC_AS__ */ 3080 movl %edx, REGOFF_CS(%esp) 3081 pushfl 3082 popl %ecx 3083 movl %ecx, REGOFF_EFL(%esp) 3084 movl $0, REGOFF_UESP(%esp) 3085#if !defined(__GNUC_AS__) 3086 movw %ss, %edx 3087#else /* __GNUC_AS__ */ 3088 mov %ss, %edx 3089#endif /* __GNUC_AS__ */ 3090 movl %edx, REGOFF_SS(%esp) 3091 3092 movl %esp, %ecx / %ecx = ®s 3093 pushl %eax / push on_panic_stack 3094 pushl %ecx / push ®s 3095 movl 12(%ebp), %ecx / %ecx = alist 3096 pushl %ecx / push alist 3097 movl 8(%ebp), %ecx / %ecx = format 3098 pushl %ecx / push format 3099 call panicsys / panicsys(); 3100 addl $16, %esp / pop arguments 3101 3102 addl $REGSIZE, %esp 3103 popl %edx 3104 popl %ecx 3105 popl %ebx 3106 popl %eax 3107 leave 3108 ret 3109 SET_SIZE(vpanic) 3110 3111 ENTRY_NP(dtrace_vpanic) / Initial stack layout: 3112 3113 pushl %ebp / | %eip | 20 3114 movl %esp, %ebp / | %ebp | 16 3115 pushl %eax / | %eax | 12 3116 pushl %ebx / | %ebx | 8 3117 pushl %ecx / | %ecx | 4 3118 pushl %edx / | %edx | 0 3119 3120 movl %esp, %ebx / %ebx = current stack pointer 3121 3122 lea panic_quiesce, %eax / %eax = &panic_quiesce 3123 pushl %eax / push &panic_quiesce 3124 call dtrace_panic_trigger / %eax = dtrace_panic_trigger() 3125 addl $4, %esp / reset stack pointer 3126 jmp vpanic_common / jump back to common code 3127 3128 SET_SIZE(dtrace_vpanic) 3129 3130#endif /* __i386 */ 3131#endif /* __lint */ 3132 3133#if defined(__lint) 3134 3135void 3136hres_tick(void) 3137{} 3138 3139int64_t timedelta; 3140hrtime_t hres_last_tick; 3141timestruc_t hrestime; 3142int64_t hrestime_adj; 3143volatile int hres_lock; 3144hrtime_t hrtime_base; 3145 3146#else /* __lint */ 3147 3148 DGDEF3(hrestime, _MUL(2, CLONGSIZE), 8) 3149 .NWORD 0, 0 3150 3151 DGDEF3(hrestime_adj, 8, 8) 3152 .long 0, 0 3153 3154 DGDEF3(hres_last_tick, 8, 8) 3155 .long 0, 0 3156 3157 DGDEF3(timedelta, 8, 8) 3158 .long 0, 0 3159 3160 DGDEF3(hres_lock, 4, 8) 3161 .long 0 3162 3163 /* 3164 * initialized to a non zero value to make pc_gethrtime() 3165 * work correctly even before clock is initialized 3166 */ 3167 DGDEF3(hrtime_base, 8, 8) 3168 .long _MUL(NSEC_PER_CLOCK_TICK, 6), 0 3169 3170 DGDEF3(adj_shift, 4, 4) 3171 .long ADJ_SHIFT 3172 3173#if defined(__amd64) 3174 3175 ENTRY_NP(hres_tick) 3176 pushq %rbp 3177 movq %rsp, %rbp 3178 3179 /* 3180 * We need to call *gethrtimef before picking up CLOCK_LOCK (obviously, 3181 * hres_last_tick can only be modified while holding CLOCK_LOCK). 3182 * At worst, performing this now instead of under CLOCK_LOCK may 3183 * introduce some jitter in pc_gethrestime(). 3184 */ 3185 call *gethrtimef(%rip) 3186 movq %rax, %r8 3187 3188 leaq hres_lock(%rip), %rax 3189 movb $-1, %dl 3190.CL1: 3191 xchgb %dl, (%rax) 3192 testb %dl, %dl 3193 jz .CL3 /* got it */ 3194.CL2: 3195 cmpb $0, (%rax) /* possible to get lock? */ 3196 pause 3197 jne .CL2 3198 jmp .CL1 /* yes, try again */ 3199.CL3: 3200 /* 3201 * compute the interval since last time hres_tick was called 3202 * and adjust hrtime_base and hrestime accordingly 3203 * hrtime_base is an 8 byte value (in nsec), hrestime is 3204 * a timestruc_t (sec, nsec) 3205 */ 3206 leaq hres_last_tick(%rip), %rax 3207 movq %r8, %r11 3208 subq (%rax), %r8 3209 addq %r8, hrtime_base(%rip) /* add interval to hrtime_base */ 3210 addq %r8, hrestime+8(%rip) /* add interval to hrestime.tv_nsec */ 3211 /* 3212 * Now that we have CLOCK_LOCK, we can update hres_last_tick 3213 */ 3214 movq %r11, (%rax) 3215 3216 call __adj_hrestime 3217 3218 /* 3219 * release the hres_lock 3220 */ 3221 incl hres_lock(%rip) 3222 leave 3223 ret 3224 SET_SIZE(hres_tick) 3225 3226#elif defined(__i386) 3227 3228 ENTRY_NP(hres_tick) 3229 pushl %ebp 3230 movl %esp, %ebp 3231 pushl %esi 3232 pushl %ebx 3233 3234 /* 3235 * We need to call *gethrtimef before picking up CLOCK_LOCK (obviously, 3236 * hres_last_tick can only be modified while holding CLOCK_LOCK). 3237 * At worst, performing this now instead of under CLOCK_LOCK may 3238 * introduce some jitter in pc_gethrestime(). 3239 */ 3240 call *gethrtimef 3241 movl %eax, %ebx 3242 movl %edx, %esi 3243 3244 movl $hres_lock, %eax 3245 movl $-1, %edx 3246.CL1: 3247 xchgb %dl, (%eax) 3248 testb %dl, %dl 3249 jz .CL3 / got it 3250.CL2: 3251 cmpb $0, (%eax) / possible to get lock? 3252 pause 3253 jne .CL2 3254 jmp .CL1 / yes, try again 3255.CL3: 3256 /* 3257 * compute the interval since last time hres_tick was called 3258 * and adjust hrtime_base and hrestime accordingly 3259 * hrtime_base is an 8 byte value (in nsec), hrestime is 3260 * timestruc_t (sec, nsec) 3261 */ 3262 3263 lea hres_last_tick, %eax 3264 3265 movl %ebx, %edx 3266 movl %esi, %ecx 3267 3268 subl (%eax), %edx 3269 sbbl 4(%eax), %ecx 3270 3271 addl %edx, hrtime_base / add interval to hrtime_base 3272 adcl %ecx, hrtime_base+4 3273 3274 addl %edx, hrestime+4 / add interval to hrestime.tv_nsec 3275 3276 / 3277 / Now that we have CLOCK_LOCK, we can update hres_last_tick. 3278 / 3279 movl %ebx, (%eax) 3280 movl %esi, 4(%eax) 3281 3282 / get hrestime at this moment. used as base for pc_gethrestime 3283 / 3284 / Apply adjustment, if any 3285 / 3286 / #define HRES_ADJ (NSEC_PER_CLOCK_TICK >> ADJ_SHIFT) 3287 / (max_hres_adj) 3288 / 3289 / void 3290 / adj_hrestime() 3291 / { 3292 / long long adj; 3293 / 3294 / if (hrestime_adj == 0) 3295 / adj = 0; 3296 / else if (hrestime_adj > 0) { 3297 / if (hrestime_adj < HRES_ADJ) 3298 / adj = hrestime_adj; 3299 / else 3300 / adj = HRES_ADJ; 3301 / } 3302 / else { 3303 / if (hrestime_adj < -(HRES_ADJ)) 3304 / adj = -(HRES_ADJ); 3305 / else 3306 / adj = hrestime_adj; 3307 / } 3308 / 3309 / timedelta -= adj; 3310 / hrestime_adj = timedelta; 3311 / hrestime.tv_nsec += adj; 3312 / 3313 / while (hrestime.tv_nsec >= NANOSEC) { 3314 / one_sec++; 3315 / hrestime.tv_sec++; 3316 / hrestime.tv_nsec -= NANOSEC; 3317 / } 3318 / } 3319__adj_hrestime: 3320 movl hrestime_adj, %esi / if (hrestime_adj == 0) 3321 movl hrestime_adj+4, %edx 3322 andl %esi, %esi 3323 jne .CL4 / no 3324 andl %edx, %edx 3325 jne .CL4 / no 3326 subl %ecx, %ecx / yes, adj = 0; 3327 subl %edx, %edx 3328 jmp .CL5 3329.CL4: 3330 subl %ecx, %ecx 3331 subl %eax, %eax 3332 subl %esi, %ecx 3333 sbbl %edx, %eax 3334 andl %eax, %eax / if (hrestime_adj > 0) 3335 jge .CL6 3336 3337 / In the following comments, HRES_ADJ is used, while in the code 3338 / max_hres_adj is used. 3339 / 3340 / The test for "hrestime_adj < HRES_ADJ" is complicated because 3341 / hrestime_adj is 64-bits, while HRES_ADJ is 32-bits. We rely 3342 / on the logical equivalence of: 3343 / 3344 / !(hrestime_adj < HRES_ADJ) 3345 / 3346 / and the two step sequence: 3347 / 3348 / (HRES_ADJ - lsw(hrestime_adj)) generates a Borrow/Carry 3349 / 3350 / which computes whether or not the least significant 32-bits 3351 / of hrestime_adj is greater than HRES_ADJ, followed by: 3352 / 3353 / Previous Borrow/Carry + -1 + msw(hrestime_adj) generates a Carry 3354 / 3355 / which generates a carry whenever step 1 is true or the most 3356 / significant long of the longlong hrestime_adj is non-zero. 3357 3358 movl max_hres_adj, %ecx / hrestime_adj is positive 3359 subl %esi, %ecx 3360 movl %edx, %eax 3361 adcl $-1, %eax 3362 jnc .CL7 3363 movl max_hres_adj, %ecx / adj = HRES_ADJ; 3364 subl %edx, %edx 3365 jmp .CL5 3366 3367 / The following computation is similar to the one above. 3368 / 3369 / The test for "hrestime_adj < -(HRES_ADJ)" is complicated because 3370 / hrestime_adj is 64-bits, while HRES_ADJ is 32-bits. We rely 3371 / on the logical equivalence of: 3372 / 3373 / (hrestime_adj > -HRES_ADJ) 3374 / 3375 / and the two step sequence: 3376 / 3377 / (HRES_ADJ + lsw(hrestime_adj)) generates a Carry 3378 / 3379 / which means the least significant 32-bits of hrestime_adj is 3380 / greater than -HRES_ADJ, followed by: 3381 / 3382 / Previous Carry + 0 + msw(hrestime_adj) generates a Carry 3383 / 3384 / which generates a carry only when step 1 is true and the most 3385 / significant long of the longlong hrestime_adj is -1. 3386 3387.CL6: / hrestime_adj is negative 3388 movl %esi, %ecx 3389 addl max_hres_adj, %ecx 3390 movl %edx, %eax 3391 adcl $0, %eax 3392 jc .CL7 3393 xor %ecx, %ecx 3394 subl max_hres_adj, %ecx / adj = -(HRES_ADJ); 3395 movl $-1, %edx 3396 jmp .CL5 3397.CL7: 3398 movl %esi, %ecx / adj = hrestime_adj; 3399.CL5: 3400 movl timedelta, %esi 3401 subl %ecx, %esi 3402 movl timedelta+4, %eax 3403 sbbl %edx, %eax 3404 movl %esi, timedelta 3405 movl %eax, timedelta+4 / timedelta -= adj; 3406 movl %esi, hrestime_adj 3407 movl %eax, hrestime_adj+4 / hrestime_adj = timedelta; 3408 addl hrestime+4, %ecx 3409 3410 movl %ecx, %eax / eax = tv_nsec 34111: 3412 cmpl $NANOSEC, %eax / if ((unsigned long)tv_nsec >= NANOSEC) 3413 jb .CL8 / no 3414 incl one_sec / yes, one_sec++; 3415 incl hrestime / hrestime.tv_sec++; 3416 addl $-NANOSEC, %eax / tv_nsec -= NANOSEC 3417 jmp 1b / check for more seconds 3418 3419.CL8: 3420 movl %eax, hrestime+4 / store final into hrestime.tv_nsec 3421 incl hres_lock / release the hres_lock 3422 3423 popl %ebx 3424 popl %esi 3425 leave 3426 ret 3427 SET_SIZE(hres_tick) 3428 3429#endif /* __i386 */ 3430#endif /* __lint */ 3431 3432/* 3433 * void prefetch_smap_w(void *) 3434 * 3435 * Prefetch ahead within a linear list of smap structures. 3436 * Not implemented for ia32. Stub for compatibility. 3437 */ 3438 3439#if defined(__lint) 3440 3441/*ARGSUSED*/ 3442void prefetch_smap_w(void *smp) 3443{} 3444 3445#else /* __lint */ 3446 3447 ENTRY(prefetch_smap_w) 3448 rep; ret /* use 2 byte return instruction when branch target */ 3449 /* AMD Software Optimization Guide - Section 6.2 */ 3450 SET_SIZE(prefetch_smap_w) 3451 3452#endif /* __lint */ 3453 3454/* 3455 * prefetch_page_r(page_t *) 3456 * issue prefetch instructions for a page_t 3457 */ 3458#if defined(__lint) 3459 3460/*ARGSUSED*/ 3461void 3462prefetch_page_r(void *pp) 3463{} 3464 3465#else /* __lint */ 3466 3467 ENTRY(prefetch_page_r) 3468 rep; ret /* use 2 byte return instruction when branch target */ 3469 /* AMD Software Optimization Guide - Section 6.2 */ 3470 SET_SIZE(prefetch_page_r) 3471 3472#endif /* __lint */ 3473 3474#if defined(__lint) 3475 3476/*ARGSUSED*/ 3477int 3478bcmp(const void *s1, const void *s2, size_t count) 3479{ return (0); } 3480 3481#else /* __lint */ 3482 3483#if defined(__amd64) 3484 3485 ENTRY(bcmp) 3486 pushq %rbp 3487 movq %rsp, %rbp 3488#ifdef DEBUG 3489 movq postbootkernelbase(%rip), %r11 3490 cmpq %r11, %rdi 3491 jb 0f 3492 cmpq %r11, %rsi 3493 jnb 1f 34940: leaq .bcmp_panic_msg(%rip), %rdi 3495 xorl %eax, %eax 3496 call panic 34971: 3498#endif /* DEBUG */ 3499 call memcmp 3500 testl %eax, %eax 3501 setne %dl 3502 leave 3503 movzbl %dl, %eax 3504 ret 3505 SET_SIZE(bcmp) 3506 3507#elif defined(__i386) 3508 3509#define ARG_S1 8 3510#define ARG_S2 12 3511#define ARG_LENGTH 16 3512 3513 ENTRY(bcmp) 3514 pushl %ebp 3515 movl %esp, %ebp / create new stack frame 3516#ifdef DEBUG 3517 movl postbootkernelbase, %eax 3518 cmpl %eax, ARG_S1(%ebp) 3519 jb 0f 3520 cmpl %eax, ARG_S2(%ebp) 3521 jnb 1f 35220: pushl $.bcmp_panic_msg 3523 call panic 35241: 3525#endif /* DEBUG */ 3526 3527 pushl %edi / save register variable 3528 movl ARG_S1(%ebp), %eax / %eax = address of string 1 3529 movl ARG_S2(%ebp), %ecx / %ecx = address of string 2 3530 cmpl %eax, %ecx / if the same string 3531 je .equal / goto .equal 3532 movl ARG_LENGTH(%ebp), %edi / %edi = length in bytes 3533 cmpl $4, %edi / if %edi < 4 3534 jb .byte_check / goto .byte_check 3535 .align 4 3536.word_loop: 3537 movl (%ecx), %edx / move 1 word from (%ecx) to %edx 3538 leal -4(%edi), %edi / %edi -= 4 3539 cmpl (%eax), %edx / compare 1 word from (%eax) with %edx 3540 jne .word_not_equal / if not equal, goto .word_not_equal 3541 leal 4(%ecx), %ecx / %ecx += 4 (next word) 3542 leal 4(%eax), %eax / %eax += 4 (next word) 3543 cmpl $4, %edi / if %edi >= 4 3544 jae .word_loop / goto .word_loop 3545.byte_check: 3546 cmpl $0, %edi / if %edi == 0 3547 je .equal / goto .equal 3548 jmp .byte_loop / goto .byte_loop (checks in bytes) 3549.word_not_equal: 3550 leal 4(%edi), %edi / %edi += 4 (post-decremented) 3551 .align 4 3552.byte_loop: 3553 movb (%ecx), %dl / move 1 byte from (%ecx) to %dl 3554 cmpb %dl, (%eax) / compare %dl with 1 byte from (%eax) 3555 jne .not_equal / if not equal, goto .not_equal 3556 incl %ecx / %ecx++ (next byte) 3557 incl %eax / %eax++ (next byte) 3558 decl %edi / %edi-- 3559 jnz .byte_loop / if not zero, goto .byte_loop 3560.equal: 3561 xorl %eax, %eax / %eax = 0 3562 popl %edi / restore register variable 3563 leave / restore old stack frame 3564 ret / return (NULL) 3565 .align 4 3566.not_equal: 3567 movl $1, %eax / return 1 3568 popl %edi / restore register variable 3569 leave / restore old stack frame 3570 ret / return (NULL) 3571 SET_SIZE(bcmp) 3572 3573#endif /* __i386 */ 3574 3575#ifdef DEBUG 3576 .text 3577.bcmp_panic_msg: 3578 .string "bcmp: arguments below kernelbase" 3579#endif /* DEBUG */ 3580 3581#endif /* __lint */ 3582 3583#if defined(__lint) 3584 3585uint_t 3586bsrw_insn(uint16_t mask) 3587{ 3588 uint_t index = sizeof (mask) * NBBY - 1; 3589 3590 while ((mask & (1 << index)) == 0) 3591 index--; 3592 return (index); 3593} 3594 3595#else /* __lint */ 3596 3597#if defined(__amd64) 3598 3599 ENTRY_NP(bsrw_insn) 3600 xorl %eax, %eax 3601 bsrw %di, %ax 3602 ret 3603 SET_SIZE(bsrw_insn) 3604 3605#elif defined(__i386) 3606 3607 ENTRY_NP(bsrw_insn) 3608 movw 4(%esp), %cx 3609 xorl %eax, %eax 3610 bsrw %cx, %ax 3611 ret 3612 SET_SIZE(bsrw_insn) 3613 3614#endif /* __i386 */ 3615#endif /* __lint */ 3616 3617#if defined(__lint) 3618 3619uint_t 3620atomic_btr32(uint32_t *pending, uint_t pil) 3621{ 3622 return (*pending &= ~(1 << pil)); 3623} 3624 3625#else /* __lint */ 3626 3627#if defined(__i386) 3628 3629 ENTRY_NP(atomic_btr32) 3630 movl 4(%esp), %ecx 3631 movl 8(%esp), %edx 3632 xorl %eax, %eax 3633 lock 3634 btrl %edx, (%ecx) 3635 setc %al 3636 ret 3637 SET_SIZE(atomic_btr32) 3638 3639#endif /* __i386 */ 3640#endif /* __lint */ 3641 3642#if defined(__lint) 3643 3644/*ARGSUSED*/ 3645void 3646switch_sp_and_call(void *newsp, void (*func)(uint_t, uint_t), uint_t arg1, 3647 uint_t arg2) 3648{} 3649 3650#else /* __lint */ 3651 3652#if defined(__amd64) 3653 3654 ENTRY_NP(switch_sp_and_call) 3655 pushq %rbp 3656 movq %rsp, %rbp /* set up stack frame */ 3657 movq %rdi, %rsp /* switch stack pointer */ 3658 movq %rdx, %rdi /* pass func arg 1 */ 3659 movq %rsi, %r11 /* save function to call */ 3660 movq %rcx, %rsi /* pass func arg 2 */ 3661 call *%r11 /* call function */ 3662 leave /* restore stack */ 3663 ret 3664 SET_SIZE(switch_sp_and_call) 3665 3666#elif defined(__i386) 3667 3668 ENTRY_NP(switch_sp_and_call) 3669 pushl %ebp 3670 mov %esp, %ebp /* set up stack frame */ 3671 movl 8(%ebp), %esp /* switch stack pointer */ 3672 pushl 20(%ebp) /* push func arg 2 */ 3673 pushl 16(%ebp) /* push func arg 1 */ 3674 call *12(%ebp) /* call function */ 3675 addl $8, %esp /* pop arguments */ 3676 leave /* restore stack */ 3677 ret 3678 SET_SIZE(switch_sp_and_call) 3679 3680#endif /* __i386 */ 3681#endif /* __lint */ 3682 3683#if defined(__lint) 3684 3685void 3686kmdb_enter(void) 3687{} 3688 3689#else /* __lint */ 3690 3691#if defined(__amd64) 3692 3693 ENTRY_NP(kmdb_enter) 3694 pushq %rbp 3695 movq %rsp, %rbp 3696 3697 /* 3698 * Save flags, do a 'cli' then return the saved flags 3699 */ 3700 call intr_clear 3701 3702 int $T_DBGENTR 3703 3704 /* 3705 * Restore the saved flags 3706 */ 3707 movq %rax, %rdi 3708 call intr_restore 3709 3710 leave 3711 ret 3712 SET_SIZE(kmdb_enter) 3713 3714#elif defined(__i386) 3715 3716 ENTRY_NP(kmdb_enter) 3717 pushl %ebp 3718 movl %esp, %ebp 3719 3720 /* 3721 * Save flags, do a 'cli' then return the saved flags 3722 */ 3723 call intr_clear 3724 3725 int $T_DBGENTR 3726 3727 /* 3728 * Restore the saved flags 3729 */ 3730 pushl %eax 3731 call intr_restore 3732 addl $4, %esp 3733 3734 leave 3735 ret 3736 SET_SIZE(kmdb_enter) 3737 3738#endif /* __i386 */ 3739#endif /* __lint */ 3740 3741#if defined(__lint) 3742 3743void 3744return_instr(void) 3745{} 3746 3747#else /* __lint */ 3748 3749 ENTRY_NP(return_instr) 3750 rep; ret /* use 2 byte instruction when branch target */ 3751 /* AMD Software Optimization Guide - Section 6.2 */ 3752 SET_SIZE(return_instr) 3753 3754#endif /* __lint */ 3755 3756#if defined(__lint) 3757 3758ulong_t 3759getflags(void) 3760{ 3761 return (0); 3762} 3763 3764#else /* __lint */ 3765 3766#if defined(__amd64) 3767 3768 ENTRY(getflags) 3769 pushfq 3770 popq %rax 3771 ret 3772 SET_SIZE(getflags) 3773 3774#elif defined(__i386) 3775 3776 ENTRY(getflags) 3777 pushfl 3778 popl %eax 3779 ret 3780 SET_SIZE(getflags) 3781 3782#endif /* __i386 */ 3783 3784#endif /* __lint */ 3785 3786#if defined(__lint) 3787 3788ftrace_icookie_t 3789ftrace_interrupt_disable(void) 3790{ return (0); } 3791 3792#else /* __lint */ 3793 3794#if defined(__amd64) 3795 3796 ENTRY(ftrace_interrupt_disable) 3797 pushfq 3798 popq %rax 3799 CLI(%rdx) 3800 ret 3801 SET_SIZE(ftrace_interrupt_disable) 3802 3803#elif defined(__i386) 3804 3805 ENTRY(ftrace_interrupt_disable) 3806 pushfl 3807 popl %eax 3808 CLI(%edx) 3809 ret 3810 SET_SIZE(ftrace_interrupt_disable) 3811 3812#endif /* __i386 */ 3813#endif /* __lint */ 3814 3815#if defined(__lint) 3816 3817/*ARGSUSED*/ 3818void 3819ftrace_interrupt_enable(ftrace_icookie_t cookie) 3820{} 3821 3822#else /* __lint */ 3823 3824#if defined(__amd64) 3825 3826 ENTRY(ftrace_interrupt_enable) 3827 pushq %rdi 3828 popfq 3829 ret 3830 SET_SIZE(ftrace_interrupt_enable) 3831 3832#elif defined(__i386) 3833 3834 ENTRY(ftrace_interrupt_enable) 3835 movl 4(%esp), %eax 3836 pushl %eax 3837 popfl 3838 ret 3839 SET_SIZE(ftrace_interrupt_enable) 3840 3841#endif /* __i386 */ 3842#endif /* __lint */ 3843