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