4681 bcmp(NULL, NULL, 0) panics in DEBUG kernel
[unleashed.git] / usr / src / uts / intel / ia32 / ml / i86_subr.s
blob5b78115943cad0569b994a1f9e81bf57bf1993f3
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 * Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.
29 * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T
30 * All Rights Reserved
34 * Copyright (c) 2009, Intel Corporation.
35 * All rights reserved.
39 * General assembly language routines.
40 * It is the intent of this file to contain routines that are
41 * independent of the specific kernel architecture, and those that are
42 * common across kernel architectures.
43 * As architectures diverge, and implementations of specific
44 * architecture-dependent routines change, the routines should be moved
45 * from this file into the respective ../`arch -k`/subr.s file.
48 #include <sys/asm_linkage.h>
49 #include <sys/asm_misc.h>
50 #include <sys/panic.h>
51 #include <sys/ontrap.h>
52 #include <sys/regset.h>
53 #include <sys/privregs.h>
54 #include <sys/reboot.h>
55 #include <sys/psw.h>
56 #include <sys/x86_archext.h>
58 #if defined(__lint)
59 #include <sys/types.h>
60 #include <sys/systm.h>
61 #include <sys/thread.h>
62 #include <sys/archsystm.h>
63 #include <sys/byteorder.h>
64 #include <sys/dtrace.h>
65 #include <sys/ftrace.h>
66 #else /* __lint */
67 #include "assym.h"
68 #endif /* __lint */
69 #include <sys/dditypes.h>
72 * on_fault()
73 * Catch lofault faults. Like setjmp except it returns one
74 * if code following causes uncorrectable fault. Turned off
75 * by calling no_fault().
78 #if defined(__lint)
80 /* ARGSUSED */
81 int
82 on_fault(label_t *ljb)
83 { return (0); }
85 void
86 no_fault(void)
89 #else /* __lint */
91 #if defined(__amd64)
93 ENTRY(on_fault)
94 movq %gs:CPU_THREAD, %rsi
95 leaq catch_fault(%rip), %rdx
96 movq %rdi, T_ONFAULT(%rsi) /* jumpbuf in t_onfault */
97 movq %rdx, T_LOFAULT(%rsi) /* catch_fault in t_lofault */
98 jmp setjmp /* let setjmp do the rest */
100 catch_fault:
101 movq %gs:CPU_THREAD, %rsi
102 movq T_ONFAULT(%rsi), %rdi /* address of save area */
103 xorl %eax, %eax
104 movq %rax, T_ONFAULT(%rsi) /* turn off onfault */
105 movq %rax, T_LOFAULT(%rsi) /* turn off lofault */
106 jmp longjmp /* let longjmp do the rest */
107 SET_SIZE(on_fault)
109 ENTRY(no_fault)
110 movq %gs:CPU_THREAD, %rsi
111 xorl %eax, %eax
112 movq %rax, T_ONFAULT(%rsi) /* turn off onfault */
113 movq %rax, T_LOFAULT(%rsi) /* turn off lofault */
115 SET_SIZE(no_fault)
117 #elif defined(__i386)
119 ENTRY(on_fault)
120 movl %gs:CPU_THREAD, %edx
121 movl 4(%esp), %eax /* jumpbuf address */
122 leal catch_fault, %ecx
123 movl %eax, T_ONFAULT(%edx) /* jumpbuf in t_onfault */
124 movl %ecx, T_LOFAULT(%edx) /* catch_fault in t_lofault */
125 jmp setjmp /* let setjmp do the rest */
127 catch_fault:
128 movl %gs:CPU_THREAD, %edx
129 xorl %eax, %eax
130 movl T_ONFAULT(%edx), %ecx /* address of save area */
131 movl %eax, T_ONFAULT(%edx) /* turn off onfault */
132 movl %eax, T_LOFAULT(%edx) /* turn off lofault */
133 pushl %ecx
134 call longjmp /* let longjmp do the rest */
135 SET_SIZE(on_fault)
137 ENTRY(no_fault)
138 movl %gs:CPU_THREAD, %edx
139 xorl %eax, %eax
140 movl %eax, T_ONFAULT(%edx) /* turn off onfault */
141 movl %eax, T_LOFAULT(%edx) /* turn off lofault */
143 SET_SIZE(no_fault)
145 #endif /* __i386 */
146 #endif /* __lint */
149 * Default trampoline code for on_trap() (see <sys/ontrap.h>). We just
150 * do a longjmp(&curthread->t_ontrap->ot_jmpbuf) if this is ever called.
153 #if defined(lint)
155 void
156 on_trap_trampoline(void)
159 #else /* __lint */
161 #if defined(__amd64)
163 ENTRY(on_trap_trampoline)
164 movq %gs:CPU_THREAD, %rsi
165 movq T_ONTRAP(%rsi), %rdi
166 addq $OT_JMPBUF, %rdi
167 jmp longjmp
168 SET_SIZE(on_trap_trampoline)
170 #elif defined(__i386)
172 ENTRY(on_trap_trampoline)
173 movl %gs:CPU_THREAD, %eax
174 movl T_ONTRAP(%eax), %eax
175 addl $OT_JMPBUF, %eax
176 pushl %eax
177 call longjmp
178 SET_SIZE(on_trap_trampoline)
180 #endif /* __i386 */
181 #endif /* __lint */
184 * Push a new element on to the t_ontrap stack. Refer to <sys/ontrap.h> for
185 * more information about the on_trap() mechanism. If the on_trap_data is the
186 * same as the topmost stack element, we just modify that element.
188 #if defined(lint)
190 /*ARGSUSED*/
192 on_trap(on_trap_data_t *otp, uint_t prot)
193 { return (0); }
195 #else /* __lint */
197 #if defined(__amd64)
199 ENTRY(on_trap)
200 movw %si, OT_PROT(%rdi) /* ot_prot = prot */
201 movw $0, OT_TRAP(%rdi) /* ot_trap = 0 */
202 leaq on_trap_trampoline(%rip), %rdx /* rdx = &on_trap_trampoline */
203 movq %rdx, OT_TRAMPOLINE(%rdi) /* ot_trampoline = rdx */
204 xorl %ecx, %ecx
205 movq %rcx, OT_HANDLE(%rdi) /* ot_handle = NULL */
206 movq %rcx, OT_PAD1(%rdi) /* ot_pad1 = NULL */
207 movq %gs:CPU_THREAD, %rdx /* rdx = curthread */
208 movq T_ONTRAP(%rdx), %rcx /* rcx = curthread->t_ontrap */
209 cmpq %rdi, %rcx /* if (otp == %rcx) */
210 je 0f /* don't modify t_ontrap */
212 movq %rcx, OT_PREV(%rdi) /* ot_prev = t_ontrap */
213 movq %rdi, T_ONTRAP(%rdx) /* curthread->t_ontrap = otp */
215 0: addq $OT_JMPBUF, %rdi /* &ot_jmpbuf */
216 jmp setjmp
217 SET_SIZE(on_trap)
219 #elif defined(__i386)
221 ENTRY(on_trap)
222 movl 4(%esp), %eax /* %eax = otp */
223 movl 8(%esp), %edx /* %edx = prot */
225 movw %dx, OT_PROT(%eax) /* ot_prot = prot */
226 movw $0, OT_TRAP(%eax) /* ot_trap = 0 */
227 leal on_trap_trampoline, %edx /* %edx = &on_trap_trampoline */
228 movl %edx, OT_TRAMPOLINE(%eax) /* ot_trampoline = %edx */
229 movl $0, OT_HANDLE(%eax) /* ot_handle = NULL */
230 movl $0, OT_PAD1(%eax) /* ot_pad1 = NULL */
231 movl %gs:CPU_THREAD, %edx /* %edx = curthread */
232 movl T_ONTRAP(%edx), %ecx /* %ecx = curthread->t_ontrap */
233 cmpl %eax, %ecx /* if (otp == %ecx) */
234 je 0f /* don't modify t_ontrap */
236 movl %ecx, OT_PREV(%eax) /* ot_prev = t_ontrap */
237 movl %eax, T_ONTRAP(%edx) /* curthread->t_ontrap = otp */
239 0: addl $OT_JMPBUF, %eax /* %eax = &ot_jmpbuf */
240 movl %eax, 4(%esp) /* put %eax back on the stack */
241 jmp setjmp /* let setjmp do the rest */
242 SET_SIZE(on_trap)
244 #endif /* __i386 */
245 #endif /* __lint */
248 * Setjmp and longjmp implement non-local gotos using state vectors
249 * type label_t.
252 #if defined(__lint)
254 /* ARGSUSED */
256 setjmp(label_t *lp)
257 { return (0); }
259 /* ARGSUSED */
260 void
261 longjmp(label_t *lp)
264 #else /* __lint */
266 #if LABEL_PC != 0
267 #error LABEL_PC MUST be defined as 0 for setjmp/longjmp to work as coded
268 #endif /* LABEL_PC != 0 */
270 #if defined(__amd64)
272 ENTRY(setjmp)
273 movq %rsp, LABEL_SP(%rdi)
274 movq %rbp, LABEL_RBP(%rdi)
275 movq %rbx, LABEL_RBX(%rdi)
276 movq %r12, LABEL_R12(%rdi)
277 movq %r13, LABEL_R13(%rdi)
278 movq %r14, LABEL_R14(%rdi)
279 movq %r15, LABEL_R15(%rdi)
280 movq (%rsp), %rdx /* return address */
281 movq %rdx, (%rdi) /* LABEL_PC is 0 */
282 xorl %eax, %eax /* return 0 */
284 SET_SIZE(setjmp)
286 ENTRY(longjmp)
287 movq LABEL_SP(%rdi), %rsp
288 movq LABEL_RBP(%rdi), %rbp
289 movq LABEL_RBX(%rdi), %rbx
290 movq LABEL_R12(%rdi), %r12
291 movq LABEL_R13(%rdi), %r13
292 movq LABEL_R14(%rdi), %r14
293 movq LABEL_R15(%rdi), %r15
294 movq (%rdi), %rdx /* return address; LABEL_PC is 0 */
295 movq %rdx, (%rsp)
296 xorl %eax, %eax
297 incl %eax /* return 1 */
299 SET_SIZE(longjmp)
301 #elif defined(__i386)
303 ENTRY(setjmp)
304 movl 4(%esp), %edx /* address of save area */
305 movl %ebp, LABEL_EBP(%edx)
306 movl %ebx, LABEL_EBX(%edx)
307 movl %esi, LABEL_ESI(%edx)
308 movl %edi, LABEL_EDI(%edx)
309 movl %esp, 4(%edx)
310 movl (%esp), %ecx /* %eip (return address) */
311 movl %ecx, (%edx) /* LABEL_PC is 0 */
312 subl %eax, %eax /* return 0 */
314 SET_SIZE(setjmp)
316 ENTRY(longjmp)
317 movl 4(%esp), %edx /* address of save area */
318 movl LABEL_EBP(%edx), %ebp
319 movl LABEL_EBX(%edx), %ebx
320 movl LABEL_ESI(%edx), %esi
321 movl LABEL_EDI(%edx), %edi
322 movl 4(%edx), %esp
323 movl (%edx), %ecx /* %eip (return addr); LABEL_PC is 0 */
324 movl $1, %eax
325 addl $4, %esp /* pop ret adr */
326 jmp *%ecx /* indirect */
327 SET_SIZE(longjmp)
329 #endif /* __i386 */
330 #endif /* __lint */
333 * if a() calls b() calls caller(),
334 * caller() returns return address in a().
335 * (Note: We assume a() and b() are C routines which do the normal entry/exit
336 * sequence.)
339 #if defined(__lint)
341 caddr_t
342 caller(void)
343 { return (0); }
345 #else /* __lint */
347 #if defined(__amd64)
349 ENTRY(caller)
350 movq 8(%rbp), %rax /* b()'s return pc, in a() */
352 SET_SIZE(caller)
354 #elif defined(__i386)
356 ENTRY(caller)
357 movl 4(%ebp), %eax /* b()'s return pc, in a() */
359 SET_SIZE(caller)
361 #endif /* __i386 */
362 #endif /* __lint */
365 * if a() calls callee(), callee() returns the
366 * return address in a();
369 #if defined(__lint)
371 caddr_t
372 callee(void)
373 { return (0); }
375 #else /* __lint */
377 #if defined(__amd64)
379 ENTRY(callee)
380 movq (%rsp), %rax /* callee()'s return pc, in a() */
382 SET_SIZE(callee)
384 #elif defined(__i386)
386 ENTRY(callee)
387 movl (%esp), %eax /* callee()'s return pc, in a() */
389 SET_SIZE(callee)
391 #endif /* __i386 */
392 #endif /* __lint */
395 * return the current frame pointer
398 #if defined(__lint)
400 greg_t
401 getfp(void)
402 { return (0); }
404 #else /* __lint */
406 #if defined(__amd64)
408 ENTRY(getfp)
409 movq %rbp, %rax
411 SET_SIZE(getfp)
413 #elif defined(__i386)
415 ENTRY(getfp)
416 movl %ebp, %eax
418 SET_SIZE(getfp)
420 #endif /* __i386 */
421 #endif /* __lint */
424 * Invalidate a single page table entry in the TLB
427 #if defined(__lint)
429 /* ARGSUSED */
430 void
431 mmu_tlbflush_entry(caddr_t m)
434 #else /* __lint */
436 #if defined(__amd64)
438 ENTRY(mmu_tlbflush_entry)
439 invlpg (%rdi)
441 SET_SIZE(mmu_tlbflush_entry)
443 #elif defined(__i386)
445 ENTRY(mmu_tlbflush_entry)
446 movl 4(%esp), %eax
447 invlpg (%eax)
449 SET_SIZE(mmu_tlbflush_entry)
451 #endif /* __i386 */
452 #endif /* __lint */
456 * Get/Set the value of various control registers
459 #if defined(__lint)
461 ulong_t
462 getcr0(void)
463 { return (0); }
465 /* ARGSUSED */
466 void
467 setcr0(ulong_t value)
470 ulong_t
471 getcr2(void)
472 { return (0); }
474 ulong_t
475 getcr3(void)
476 { return (0); }
478 #if !defined(__xpv)
479 /* ARGSUSED */
480 void
481 setcr3(ulong_t val)
484 void
485 reload_cr3(void)
487 #endif
489 ulong_t
490 getcr4(void)
491 { return (0); }
493 /* ARGSUSED */
494 void
495 setcr4(ulong_t val)
498 #if defined(__amd64)
500 ulong_t
501 getcr8(void)
502 { return (0); }
504 /* ARGSUSED */
505 void
506 setcr8(ulong_t val)
509 #endif /* __amd64 */
511 #else /* __lint */
513 #if defined(__amd64)
515 ENTRY(getcr0)
516 movq %cr0, %rax
518 SET_SIZE(getcr0)
520 ENTRY(setcr0)
521 movq %rdi, %cr0
523 SET_SIZE(setcr0)
525 ENTRY(getcr2)
526 #if defined(__xpv)
527 movq %gs:CPU_VCPU_INFO, %rax
528 movq VCPU_INFO_ARCH_CR2(%rax), %rax
529 #else
530 movq %cr2, %rax
531 #endif
533 SET_SIZE(getcr2)
535 ENTRY(getcr3)
536 movq %cr3, %rax
538 SET_SIZE(getcr3)
540 #if !defined(__xpv)
542 ENTRY(setcr3)
543 movq %rdi, %cr3
545 SET_SIZE(setcr3)
547 ENTRY(reload_cr3)
548 movq %cr3, %rdi
549 movq %rdi, %cr3
551 SET_SIZE(reload_cr3)
553 #endif /* __xpv */
555 ENTRY(getcr4)
556 movq %cr4, %rax
558 SET_SIZE(getcr4)
560 ENTRY(setcr4)
561 movq %rdi, %cr4
563 SET_SIZE(setcr4)
565 ENTRY(getcr8)
566 movq %cr8, %rax
568 SET_SIZE(getcr8)
570 ENTRY(setcr8)
571 movq %rdi, %cr8
573 SET_SIZE(setcr8)
575 #elif defined(__i386)
577 ENTRY(getcr0)
578 movl %cr0, %eax
580 SET_SIZE(getcr0)
582 ENTRY(setcr0)
583 movl 4(%esp), %eax
584 movl %eax, %cr0
586 SET_SIZE(setcr0)
589 * "lock mov %cr0" is used on processors which indicate it is
590 * supported via CPUID. Normally the 32 bit TPR is accessed via
591 * the local APIC.
593 ENTRY(getcr8)
594 lock
595 movl %cr0, %eax
597 SET_SIZE(getcr8)
599 ENTRY(setcr8)
600 movl 4(%esp), %eax
601 lock
602 movl %eax, %cr0
604 SET_SIZE(setcr8)
606 ENTRY(getcr2)
607 #if defined(__xpv)
608 movl %gs:CPU_VCPU_INFO, %eax
609 movl VCPU_INFO_ARCH_CR2(%eax), %eax
610 #else
611 movl %cr2, %eax
612 #endif
614 SET_SIZE(getcr2)
616 ENTRY(getcr3)
617 movl %cr3, %eax
619 SET_SIZE(getcr3)
621 #if !defined(__xpv)
623 ENTRY(setcr3)
624 movl 4(%esp), %eax
625 movl %eax, %cr3
627 SET_SIZE(setcr3)
629 ENTRY(reload_cr3)
630 movl %cr3, %eax
631 movl %eax, %cr3
633 SET_SIZE(reload_cr3)
635 #endif /* __xpv */
637 ENTRY(getcr4)
638 movl %cr4, %eax
640 SET_SIZE(getcr4)
642 ENTRY(setcr4)
643 movl 4(%esp), %eax
644 movl %eax, %cr4
646 SET_SIZE(setcr4)
648 #endif /* __i386 */
649 #endif /* __lint */
651 #if defined(__lint)
653 /*ARGSUSED*/
654 uint32_t
655 __cpuid_insn(struct cpuid_regs *regs)
656 { return (0); }
658 #else /* __lint */
660 #if defined(__amd64)
662 ENTRY(__cpuid_insn)
663 movq %rbx, %r8
664 movq %rcx, %r9
665 movq %rdx, %r11
666 movl (%rdi), %eax /* %eax = regs->cp_eax */
667 movl 0x4(%rdi), %ebx /* %ebx = regs->cp_ebx */
668 movl 0x8(%rdi), %ecx /* %ecx = regs->cp_ecx */
669 movl 0xc(%rdi), %edx /* %edx = regs->cp_edx */
670 cpuid
671 movl %eax, (%rdi) /* regs->cp_eax = %eax */
672 movl %ebx, 0x4(%rdi) /* regs->cp_ebx = %ebx */
673 movl %ecx, 0x8(%rdi) /* regs->cp_ecx = %ecx */
674 movl %edx, 0xc(%rdi) /* regs->cp_edx = %edx */
675 movq %r8, %rbx
676 movq %r9, %rcx
677 movq %r11, %rdx
679 SET_SIZE(__cpuid_insn)
681 #elif defined(__i386)
683 ENTRY(__cpuid_insn)
684 pushl %ebp
685 movl 0x8(%esp), %ebp /* %ebp = regs */
686 pushl %ebx
687 pushl %ecx
688 pushl %edx
689 movl (%ebp), %eax /* %eax = regs->cp_eax */
690 movl 0x4(%ebp), %ebx /* %ebx = regs->cp_ebx */
691 movl 0x8(%ebp), %ecx /* %ecx = regs->cp_ecx */
692 movl 0xc(%ebp), %edx /* %edx = regs->cp_edx */
693 cpuid
694 movl %eax, (%ebp) /* regs->cp_eax = %eax */
695 movl %ebx, 0x4(%ebp) /* regs->cp_ebx = %ebx */
696 movl %ecx, 0x8(%ebp) /* regs->cp_ecx = %ecx */
697 movl %edx, 0xc(%ebp) /* regs->cp_edx = %edx */
698 popl %edx
699 popl %ecx
700 popl %ebx
701 popl %ebp
703 SET_SIZE(__cpuid_insn)
705 #endif /* __i386 */
706 #endif /* __lint */
708 #if defined(__lint)
710 /*ARGSUSED*/
711 void
712 i86_monitor(volatile uint32_t *addr, uint32_t extensions, uint32_t hints)
715 #else /* __lint */
717 #if defined(__amd64)
719 ENTRY_NP(i86_monitor)
720 pushq %rbp
721 movq %rsp, %rbp
722 movq %rdi, %rax /* addr */
723 movq %rsi, %rcx /* extensions */
724 /* rdx contains input arg3: hints */
725 clflush (%rax)
726 .byte 0x0f, 0x01, 0xc8 /* monitor */
727 leave
729 SET_SIZE(i86_monitor)
731 #elif defined(__i386)
733 ENTRY_NP(i86_monitor)
734 pushl %ebp
735 movl %esp, %ebp
736 movl 0x8(%ebp),%eax /* addr */
737 movl 0xc(%ebp),%ecx /* extensions */
738 movl 0x10(%ebp),%edx /* hints */
739 clflush (%eax)
740 .byte 0x0f, 0x01, 0xc8 /* monitor */
741 leave
743 SET_SIZE(i86_monitor)
745 #endif /* __i386 */
746 #endif /* __lint */
748 #if defined(__lint)
750 /*ARGSUSED*/
751 void
752 i86_mwait(uint32_t data, uint32_t extensions)
755 #else /* __lint */
757 #if defined(__amd64)
759 ENTRY_NP(i86_mwait)
760 pushq %rbp
761 movq %rsp, %rbp
762 movq %rdi, %rax /* data */
763 movq %rsi, %rcx /* extensions */
764 .byte 0x0f, 0x01, 0xc9 /* mwait */
765 leave
767 SET_SIZE(i86_mwait)
769 #elif defined(__i386)
771 ENTRY_NP(i86_mwait)
772 pushl %ebp
773 movl %esp, %ebp
774 movl 0x8(%ebp),%eax /* data */
775 movl 0xc(%ebp),%ecx /* extensions */
776 .byte 0x0f, 0x01, 0xc9 /* mwait */
777 leave
779 SET_SIZE(i86_mwait)
781 #endif /* __i386 */
782 #endif /* __lint */
784 #if defined(__xpv)
786 * Defined in C
788 #else
790 #if defined(__lint)
792 hrtime_t
793 tsc_read(void)
795 return (0);
798 #else /* __lint */
800 #if defined(__amd64)
802 ENTRY_NP(tsc_read)
803 movq %rbx, %r11
804 movl $0, %eax
805 cpuid
806 rdtsc
807 movq %r11, %rbx
808 shlq $32, %rdx
809 orq %rdx, %rax
811 .globl _tsc_mfence_start
812 _tsc_mfence_start:
813 mfence
814 rdtsc
815 shlq $32, %rdx
816 orq %rdx, %rax
818 .globl _tsc_mfence_end
819 _tsc_mfence_end:
820 .globl _tscp_start
821 _tscp_start:
822 .byte 0x0f, 0x01, 0xf9 /* rdtscp instruction */
823 shlq $32, %rdx
824 orq %rdx, %rax
826 .globl _tscp_end
827 _tscp_end:
828 .globl _no_rdtsc_start
829 _no_rdtsc_start:
830 xorl %edx, %edx
831 xorl %eax, %eax
833 .globl _no_rdtsc_end
834 _no_rdtsc_end:
835 .globl _tsc_lfence_start
836 _tsc_lfence_start:
837 lfence
838 rdtsc
839 shlq $32, %rdx
840 orq %rdx, %rax
842 .globl _tsc_lfence_end
843 _tsc_lfence_end:
844 SET_SIZE(tsc_read)
846 #else /* __i386 */
848 ENTRY_NP(tsc_read)
849 pushl %ebx
850 movl $0, %eax
851 cpuid
852 rdtsc
853 popl %ebx
855 .globl _tsc_mfence_start
856 _tsc_mfence_start:
857 mfence
858 rdtsc
860 .globl _tsc_mfence_end
861 _tsc_mfence_end:
862 .globl _tscp_start
863 _tscp_start:
864 .byte 0x0f, 0x01, 0xf9 /* rdtscp instruction */
866 .globl _tscp_end
867 _tscp_end:
868 .globl _no_rdtsc_start
869 _no_rdtsc_start:
870 xorl %edx, %edx
871 xorl %eax, %eax
873 .globl _no_rdtsc_end
874 _no_rdtsc_end:
875 .globl _tsc_lfence_start
876 _tsc_lfence_start:
877 lfence
878 rdtsc
880 .globl _tsc_lfence_end
881 _tsc_lfence_end:
882 SET_SIZE(tsc_read)
884 #endif /* __i386 */
886 #endif /* __lint */
889 #endif /* __xpv */
891 #ifdef __lint
893 * Do not use this function for obtaining clock tick. This
894 * is called by callers who do not need to have a guarenteed
895 * correct tick value. The proper routine to use is tsc_read().
897 u_longlong_t
898 randtick(void)
900 return (0);
902 #else
903 #if defined(__amd64)
904 ENTRY_NP(randtick)
905 rdtsc
906 shlq $32, %rdx
907 orq %rdx, %rax
909 SET_SIZE(randtick)
910 #else
911 ENTRY_NP(randtick)
912 rdtsc
914 SET_SIZE(randtick)
915 #endif /* __i386 */
916 #endif /* __lint */
918 * Insert entryp after predp in a doubly linked list.
921 #if defined(__lint)
923 /*ARGSUSED*/
924 void
925 _insque(caddr_t entryp, caddr_t predp)
928 #else /* __lint */
930 #if defined(__amd64)
932 ENTRY(_insque)
933 movq (%rsi), %rax /* predp->forw */
934 movq %rsi, CPTRSIZE(%rdi) /* entryp->back = predp */
935 movq %rax, (%rdi) /* entryp->forw = predp->forw */
936 movq %rdi, (%rsi) /* predp->forw = entryp */
937 movq %rdi, CPTRSIZE(%rax) /* predp->forw->back = entryp */
939 SET_SIZE(_insque)
941 #elif defined(__i386)
943 ENTRY(_insque)
944 movl 8(%esp), %edx
945 movl 4(%esp), %ecx
946 movl (%edx), %eax /* predp->forw */
947 movl %edx, CPTRSIZE(%ecx) /* entryp->back = predp */
948 movl %eax, (%ecx) /* entryp->forw = predp->forw */
949 movl %ecx, (%edx) /* predp->forw = entryp */
950 movl %ecx, CPTRSIZE(%eax) /* predp->forw->back = entryp */
952 SET_SIZE(_insque)
954 #endif /* __i386 */
955 #endif /* __lint */
958 * Remove entryp from a doubly linked list
961 #if defined(__lint)
963 /*ARGSUSED*/
964 void
965 _remque(caddr_t entryp)
968 #else /* __lint */
970 #if defined(__amd64)
972 ENTRY(_remque)
973 movq (%rdi), %rax /* entry->forw */
974 movq CPTRSIZE(%rdi), %rdx /* entry->back */
975 movq %rax, (%rdx) /* entry->back->forw = entry->forw */
976 movq %rdx, CPTRSIZE(%rax) /* entry->forw->back = entry->back */
978 SET_SIZE(_remque)
980 #elif defined(__i386)
982 ENTRY(_remque)
983 movl 4(%esp), %ecx
984 movl (%ecx), %eax /* entry->forw */
985 movl CPTRSIZE(%ecx), %edx /* entry->back */
986 movl %eax, (%edx) /* entry->back->forw = entry->forw */
987 movl %edx, CPTRSIZE(%eax) /* entry->forw->back = entry->back */
989 SET_SIZE(_remque)
991 #endif /* __i386 */
992 #endif /* __lint */
995 * Returns the number of
996 * non-NULL bytes in string argument.
999 #if defined(__lint)
1001 /* ARGSUSED */
1002 size_t
1003 strlen(const char *str)
1004 { return (0); }
1006 #else /* __lint */
1008 #if defined(__amd64)
1011 * This is close to a simple transliteration of a C version of this
1012 * routine. We should either just -make- this be a C version, or
1013 * justify having it in assembler by making it significantly faster.
1015 * size_t
1016 * strlen(const char *s)
1018 * const char *s0;
1019 * #if defined(DEBUG)
1020 * if ((uintptr_t)s < KERNELBASE)
1021 * panic(.str_panic_msg);
1022 * #endif
1023 * for (s0 = s; *s; s++)
1025 * return (s - s0);
1029 ENTRY(strlen)
1030 #ifdef DEBUG
1031 movq postbootkernelbase(%rip), %rax
1032 cmpq %rax, %rdi
1033 jae str_valid
1034 pushq %rbp
1035 movq %rsp, %rbp
1036 leaq .str_panic_msg(%rip), %rdi
1037 xorl %eax, %eax
1038 call panic
1039 #endif /* DEBUG */
1040 str_valid:
1041 cmpb $0, (%rdi)
1042 movq %rdi, %rax
1043 je .null_found
1044 .align 4
1045 .strlen_loop:
1046 incq %rdi
1047 cmpb $0, (%rdi)
1048 jne .strlen_loop
1049 .null_found:
1050 subq %rax, %rdi
1051 movq %rdi, %rax
1053 SET_SIZE(strlen)
1055 #elif defined(__i386)
1057 ENTRY(strlen)
1058 #ifdef DEBUG
1059 movl postbootkernelbase, %eax
1060 cmpl %eax, 4(%esp)
1061 jae str_valid
1062 pushl %ebp
1063 movl %esp, %ebp
1064 pushl $.str_panic_msg
1065 call panic
1066 #endif /* DEBUG */
1068 str_valid:
1069 movl 4(%esp), %eax /* %eax = string address */
1070 testl $3, %eax /* if %eax not word aligned */
1071 jnz .not_word_aligned /* goto .not_word_aligned */
1072 .align 4
1073 .word_aligned:
1074 movl (%eax), %edx /* move 1 word from (%eax) to %edx */
1075 movl $0x7f7f7f7f, %ecx
1076 andl %edx, %ecx /* %ecx = %edx & 0x7f7f7f7f */
1077 addl $4, %eax /* next word */
1078 addl $0x7f7f7f7f, %ecx /* %ecx += 0x7f7f7f7f */
1079 orl %edx, %ecx /* %ecx |= %edx */
1080 andl $0x80808080, %ecx /* %ecx &= 0x80808080 */
1081 cmpl $0x80808080, %ecx /* if no null byte in this word */
1082 je .word_aligned /* goto .word_aligned */
1083 subl $4, %eax /* post-incremented */
1084 .not_word_aligned:
1085 cmpb $0, (%eax) /* if a byte in (%eax) is null */
1086 je .null_found /* goto .null_found */
1087 incl %eax /* next byte */
1088 testl $3, %eax /* if %eax not word aligned */
1089 jnz .not_word_aligned /* goto .not_word_aligned */
1090 jmp .word_aligned /* goto .word_aligned */
1091 .align 4
1092 .null_found:
1093 subl 4(%esp), %eax /* %eax -= string address */
1095 SET_SIZE(strlen)
1097 #endif /* __i386 */
1099 #ifdef DEBUG
1100 .text
1101 .str_panic_msg:
1102 .string "strlen: argument below kernelbase"
1103 #endif /* DEBUG */
1105 #endif /* __lint */
1108 * Berkeley 4.3 introduced symbolically named interrupt levels
1109 * as a way deal with priority in a machine independent fashion.
1110 * Numbered priorities are machine specific, and should be
1111 * discouraged where possible.
1113 * Note, for the machine specific priorities there are
1114 * examples listed for devices that use a particular priority.
1115 * It should not be construed that all devices of that
1116 * type should be at that priority. It is currently were
1117 * the current devices fit into the priority scheme based
1118 * upon time criticalness.
1120 * The underlying assumption of these assignments is that
1121 * IPL 10 is the highest level from which a device
1122 * routine can call wakeup. Devices that interrupt from higher
1123 * levels are restricted in what they can do. If they need
1124 * kernels services they should schedule a routine at a lower
1125 * level (via software interrupt) to do the required
1126 * processing.
1128 * Examples of this higher usage:
1129 * Level Usage
1130 * 14 Profiling clock (and PROM uart polling clock)
1131 * 12 Serial ports
1133 * The serial ports request lower level processing on level 6.
1135 * Also, almost all splN routines (where N is a number or a
1136 * mnemonic) will do a RAISE(), on the assumption that they are
1137 * never used to lower our priority.
1138 * The exceptions are:
1139 * spl8() Because you can't be above 15 to begin with!
1140 * splzs() Because this is used at boot time to lower our
1141 * priority, to allow the PROM to poll the uart.
1142 * spl0() Used to lower priority to 0.
1145 #if defined(__lint)
1147 int spl0(void) { return (0); }
1148 int spl6(void) { return (0); }
1149 int spl7(void) { return (0); }
1150 int spl8(void) { return (0); }
1151 int splhigh(void) { return (0); }
1152 int splhi(void) { return (0); }
1153 int splzs(void) { return (0); }
1155 /* ARGSUSED */
1156 void
1157 splx(int level)
1160 #else /* __lint */
1162 #if defined(__amd64)
1164 #define SETPRI(level) \
1165 movl $/**/level, %edi; /* new priority */ \
1166 jmp do_splx /* redirect to do_splx */
1168 #define RAISE(level) \
1169 movl $/**/level, %edi; /* new priority */ \
1170 jmp splr /* redirect to splr */
1172 #elif defined(__i386)
1174 #define SETPRI(level) \
1175 pushl $/**/level; /* new priority */ \
1176 call do_splx; /* invoke common splx code */ \
1177 addl $4, %esp; /* unstack arg */ \
1180 #define RAISE(level) \
1181 pushl $/**/level; /* new priority */ \
1182 call splr; /* invoke common splr code */ \
1183 addl $4, %esp; /* unstack args */ \
1186 #endif /* __i386 */
1188 /* locks out all interrupts, including memory errors */
1189 ENTRY(spl8)
1190 SETPRI(15)
1191 SET_SIZE(spl8)
1193 /* just below the level that profiling runs */
1194 ENTRY(spl7)
1195 RAISE(13)
1196 SET_SIZE(spl7)
1198 /* sun specific - highest priority onboard serial i/o asy ports */
1199 ENTRY(splzs)
1200 SETPRI(12) /* Can't be a RAISE, as it's used to lower us */
1201 SET_SIZE(splzs)
1203 ENTRY(splhi)
1204 ALTENTRY(splhigh)
1205 ALTENTRY(spl6)
1206 ALTENTRY(i_ddi_splhigh)
1208 RAISE(DISP_LEVEL)
1210 SET_SIZE(i_ddi_splhigh)
1211 SET_SIZE(spl6)
1212 SET_SIZE(splhigh)
1213 SET_SIZE(splhi)
1215 /* allow all interrupts */
1216 ENTRY(spl0)
1217 SETPRI(0)
1218 SET_SIZE(spl0)
1221 /* splx implementation */
1222 ENTRY(splx)
1223 jmp do_splx /* redirect to common splx code */
1224 SET_SIZE(splx)
1226 #endif /* __lint */
1228 #if defined(__i386)
1231 * Read and write the %gs register
1234 #if defined(__lint)
1236 /*ARGSUSED*/
1237 uint16_t
1238 getgs(void)
1239 { return (0); }
1241 /*ARGSUSED*/
1242 void
1243 setgs(uint16_t sel)
1246 #else /* __lint */
1248 ENTRY(getgs)
1249 clr %eax
1250 movw %gs, %ax
1252 SET_SIZE(getgs)
1254 ENTRY(setgs)
1255 movw 4(%esp), %gs
1257 SET_SIZE(setgs)
1259 #endif /* __lint */
1260 #endif /* __i386 */
1262 #if defined(__lint)
1264 void
1265 pc_reset(void)
1268 void
1269 efi_reset(void)
1272 #else /* __lint */
1274 ENTRY(wait_500ms)
1275 #if defined(__amd64)
1276 pushq %rbx
1277 #elif defined(__i386)
1278 push %ebx
1279 #endif
1280 movl $50000, %ebx
1282 call tenmicrosec
1283 decl %ebx
1284 jnz 1b
1285 #if defined(__amd64)
1286 popq %rbx
1287 #elif defined(__i386)
1288 pop %ebx
1289 #endif
1290 ret
1291 SET_SIZE(wait_500ms)
1293 #define RESET_METHOD_KBC 1
1294 #define RESET_METHOD_PORT92 2
1295 #define RESET_METHOD_PCI 4
1297 DGDEF3(pc_reset_methods, 4, 8)
1298 .long RESET_METHOD_KBC|RESET_METHOD_PORT92|RESET_METHOD_PCI;
1300 ENTRY(pc_reset)
1302 #if defined(__i386)
1303 testl $RESET_METHOD_KBC, pc_reset_methods
1304 #elif defined(__amd64)
1305 testl $RESET_METHOD_KBC, pc_reset_methods(%rip)
1306 #endif
1307 jz 1f
1310 / Try the classic keyboard controller-triggered reset.
1312 movw $0x64, %dx
1313 movb $0xfe, %al
1314 outb (%dx)
1316 / Wait up to 500 milliseconds here for the keyboard controller
1317 / to pull the reset line. On some systems where the keyboard
1318 / controller is slow to pull the reset line, the next reset method
1319 / may be executed (which may be bad if those systems hang when the
1320 / next reset method is used, e.g. Ferrari 3400 (doesn't like port 92),
1321 / and Ferrari 4000 (doesn't like the cf9 reset method))
1323 call wait_500ms
1326 #if defined(__i386)
1327 testl $RESET_METHOD_PORT92, pc_reset_methods
1328 #elif defined(__amd64)
1329 testl $RESET_METHOD_PORT92, pc_reset_methods(%rip)
1330 #endif
1331 jz 3f
1334 / Try port 0x92 fast reset
1336 movw $0x92, %dx
1337 inb (%dx)
1338 cmpb $0xff, %al / If port's not there, we should get back 0xFF
1339 je 1f
1340 testb $1, %al / If bit 0
1341 jz 2f / is clear, jump to perform the reset
1342 andb $0xfe, %al / otherwise,
1343 outb (%dx) / clear bit 0 first, then
1345 orb $1, %al / Set bit 0
1346 outb (%dx) / and reset the system
1349 call wait_500ms
1352 #if defined(__i386)
1353 testl $RESET_METHOD_PCI, pc_reset_methods
1354 #elif defined(__amd64)
1355 testl $RESET_METHOD_PCI, pc_reset_methods(%rip)
1356 #endif
1357 jz 4f
1359 / Try the PCI (soft) reset vector (should work on all modern systems,
1360 / but has been shown to cause problems on 450NX systems, and some newer
1361 / systems (e.g. ATI IXP400-equipped systems))
1362 / When resetting via this method, 2 writes are required. The first
1363 / targets bit 1 (0=hard reset without power cycle, 1=hard reset with
1364 / power cycle).
1365 / The reset occurs on the second write, during bit 2's transition from
1366 / 0->1.
1367 movw $0xcf9, %dx
1368 movb $0x2, %al / Reset mode = hard, no power cycle
1369 outb (%dx)
1370 movb $0x6, %al
1371 outb (%dx)
1373 call wait_500ms
1377 / port 0xcf9 failed also. Last-ditch effort is to
1378 / triple-fault the CPU.
1379 / Also, use triple fault for EFI firmware
1381 ENTRY(efi_reset)
1382 #if defined(__amd64)
1383 pushq $0x0
1384 pushq $0x0 / IDT base of 0, limit of 0 + 2 unused bytes
1385 lidt (%rsp)
1386 #elif defined(__i386)
1387 pushl $0x0
1388 pushl $0x0 / IDT base of 0, limit of 0 + 2 unused bytes
1389 lidt (%esp)
1390 #endif
1391 int $0x0 / Trigger interrupt, generate triple-fault
1394 hlt / Wait forever
1395 /*NOTREACHED*/
1396 SET_SIZE(efi_reset)
1397 SET_SIZE(pc_reset)
1399 #endif /* __lint */
1402 * C callable in and out routines
1405 #if defined(__lint)
1407 /* ARGSUSED */
1408 void
1409 outl(int port_address, uint32_t val)
1412 #else /* __lint */
1414 #if defined(__amd64)
1416 ENTRY(outl)
1417 movw %di, %dx
1418 movl %esi, %eax
1419 outl (%dx)
1421 SET_SIZE(outl)
1423 #elif defined(__i386)
1425 .set PORT, 4
1426 .set VAL, 8
1428 ENTRY(outl)
1429 movw PORT(%esp), %dx
1430 movl VAL(%esp), %eax
1431 outl (%dx)
1433 SET_SIZE(outl)
1435 #endif /* __i386 */
1436 #endif /* __lint */
1438 #if defined(__lint)
1440 /* ARGSUSED */
1441 void
1442 outw(int port_address, uint16_t val)
1445 #else /* __lint */
1447 #if defined(__amd64)
1449 ENTRY(outw)
1450 movw %di, %dx
1451 movw %si, %ax
1452 D16 outl (%dx) /* XX64 why not outw? */
1454 SET_SIZE(outw)
1456 #elif defined(__i386)
1458 ENTRY(outw)
1459 movw PORT(%esp), %dx
1460 movw VAL(%esp), %ax
1461 D16 outl (%dx)
1463 SET_SIZE(outw)
1465 #endif /* __i386 */
1466 #endif /* __lint */
1468 #if defined(__lint)
1470 /* ARGSUSED */
1471 void
1472 outb(int port_address, uint8_t val)
1475 #else /* __lint */
1477 #if defined(__amd64)
1479 ENTRY(outb)
1480 movw %di, %dx
1481 movb %sil, %al
1482 outb (%dx)
1484 SET_SIZE(outb)
1486 #elif defined(__i386)
1488 ENTRY(outb)
1489 movw PORT(%esp), %dx
1490 movb VAL(%esp), %al
1491 outb (%dx)
1493 SET_SIZE(outb)
1495 #endif /* __i386 */
1496 #endif /* __lint */
1498 #if defined(__lint)
1500 /* ARGSUSED */
1501 uint32_t
1502 inl(int port_address)
1503 { return (0); }
1505 #else /* __lint */
1507 #if defined(__amd64)
1509 ENTRY(inl)
1510 xorl %eax, %eax
1511 movw %di, %dx
1512 inl (%dx)
1514 SET_SIZE(inl)
1516 #elif defined(__i386)
1518 ENTRY(inl)
1519 movw PORT(%esp), %dx
1520 inl (%dx)
1522 SET_SIZE(inl)
1524 #endif /* __i386 */
1525 #endif /* __lint */
1527 #if defined(__lint)
1529 /* ARGSUSED */
1530 uint16_t
1531 inw(int port_address)
1532 { return (0); }
1534 #else /* __lint */
1536 #if defined(__amd64)
1538 ENTRY(inw)
1539 xorl %eax, %eax
1540 movw %di, %dx
1541 D16 inl (%dx)
1543 SET_SIZE(inw)
1545 #elif defined(__i386)
1547 ENTRY(inw)
1548 subl %eax, %eax
1549 movw PORT(%esp), %dx
1550 D16 inl (%dx)
1552 SET_SIZE(inw)
1554 #endif /* __i386 */
1555 #endif /* __lint */
1558 #if defined(__lint)
1560 /* ARGSUSED */
1561 uint8_t
1562 inb(int port_address)
1563 { return (0); }
1565 #else /* __lint */
1567 #if defined(__amd64)
1569 ENTRY(inb)
1570 xorl %eax, %eax
1571 movw %di, %dx
1572 inb (%dx)
1574 SET_SIZE(inb)
1576 #elif defined(__i386)
1578 ENTRY(inb)
1579 subl %eax, %eax
1580 movw PORT(%esp), %dx
1581 inb (%dx)
1583 SET_SIZE(inb)
1585 #endif /* __i386 */
1586 #endif /* __lint */
1589 #if defined(__lint)
1591 /* ARGSUSED */
1592 void
1593 repoutsw(int port, uint16_t *addr, int cnt)
1596 #else /* __lint */
1598 #if defined(__amd64)
1600 ENTRY(repoutsw)
1601 movl %edx, %ecx
1602 movw %di, %dx
1604 D16 outsl
1606 SET_SIZE(repoutsw)
1608 #elif defined(__i386)
1611 * The arguments and saved registers are on the stack in the
1612 * following order:
1613 * | cnt | +16
1614 * | *addr | +12
1615 * | port | +8
1616 * | eip | +4
1617 * | esi | <-- %esp
1618 * If additional values are pushed onto the stack, make sure
1619 * to adjust the following constants accordingly.
1621 .set PORT, 8
1622 .set ADDR, 12
1623 .set COUNT, 16
1625 ENTRY(repoutsw)
1626 pushl %esi
1627 movl PORT(%esp), %edx
1628 movl ADDR(%esp), %esi
1629 movl COUNT(%esp), %ecx
1631 D16 outsl
1632 popl %esi
1634 SET_SIZE(repoutsw)
1636 #endif /* __i386 */
1637 #endif /* __lint */
1640 #if defined(__lint)
1642 /* ARGSUSED */
1643 void
1644 repinsw(int port_addr, uint16_t *addr, int cnt)
1647 #else /* __lint */
1649 #if defined(__amd64)
1651 ENTRY(repinsw)
1652 movl %edx, %ecx
1653 movw %di, %dx
1655 D16 insl
1657 SET_SIZE(repinsw)
1659 #elif defined(__i386)
1661 ENTRY(repinsw)
1662 pushl %edi
1663 movl PORT(%esp), %edx
1664 movl ADDR(%esp), %edi
1665 movl COUNT(%esp), %ecx
1667 D16 insl
1668 popl %edi
1670 SET_SIZE(repinsw)
1672 #endif /* __i386 */
1673 #endif /* __lint */
1676 #if defined(__lint)
1678 /* ARGSUSED */
1679 void
1680 repinsb(int port, uint8_t *addr, int count)
1683 #else /* __lint */
1685 #if defined(__amd64)
1687 ENTRY(repinsb)
1688 movl %edx, %ecx
1689 movw %di, %dx
1690 movq %rsi, %rdi
1692 insb
1693 ret
1694 SET_SIZE(repinsb)
1696 #elif defined(__i386)
1699 * The arguments and saved registers are on the stack in the
1700 * following order:
1701 * | cnt | +16
1702 * | *addr | +12
1703 * | port | +8
1704 * | eip | +4
1705 * | esi | <-- %esp
1706 * If additional values are pushed onto the stack, make sure
1707 * to adjust the following constants accordingly.
1709 .set IO_PORT, 8
1710 .set IO_ADDR, 12
1711 .set IO_COUNT, 16
1713 ENTRY(repinsb)
1714 pushl %edi
1715 movl IO_ADDR(%esp), %edi
1716 movl IO_COUNT(%esp), %ecx
1717 movl IO_PORT(%esp), %edx
1719 insb
1720 popl %edi
1722 SET_SIZE(repinsb)
1724 #endif /* __i386 */
1725 #endif /* __lint */
1729 * Input a stream of 32-bit words.
1730 * NOTE: count is a DWORD count.
1732 #if defined(__lint)
1734 /* ARGSUSED */
1735 void
1736 repinsd(int port, uint32_t *addr, int count)
1739 #else /* __lint */
1741 #if defined(__amd64)
1743 ENTRY(repinsd)
1744 movl %edx, %ecx
1745 movw %di, %dx
1746 movq %rsi, %rdi
1748 insl
1750 SET_SIZE(repinsd)
1752 #elif defined(__i386)
1754 ENTRY(repinsd)
1755 pushl %edi
1756 movl IO_ADDR(%esp), %edi
1757 movl IO_COUNT(%esp), %ecx
1758 movl IO_PORT(%esp), %edx
1760 insl
1761 popl %edi
1763 SET_SIZE(repinsd)
1765 #endif /* __i386 */
1766 #endif /* __lint */
1769 * Output a stream of bytes
1770 * NOTE: count is a byte count
1772 #if defined(__lint)
1774 /* ARGSUSED */
1775 void
1776 repoutsb(int port, uint8_t *addr, int count)
1779 #else /* __lint */
1781 #if defined(__amd64)
1783 ENTRY(repoutsb)
1784 movl %edx, %ecx
1785 movw %di, %dx
1787 outsb
1788 ret
1789 SET_SIZE(repoutsb)
1791 #elif defined(__i386)
1793 ENTRY(repoutsb)
1794 pushl %esi
1795 movl IO_ADDR(%esp), %esi
1796 movl IO_COUNT(%esp), %ecx
1797 movl IO_PORT(%esp), %edx
1799 outsb
1800 popl %esi
1802 SET_SIZE(repoutsb)
1804 #endif /* __i386 */
1805 #endif /* __lint */
1808 * Output a stream of 32-bit words
1809 * NOTE: count is a DWORD count
1811 #if defined(__lint)
1813 /* ARGSUSED */
1814 void
1815 repoutsd(int port, uint32_t *addr, int count)
1818 #else /* __lint */
1820 #if defined(__amd64)
1822 ENTRY(repoutsd)
1823 movl %edx, %ecx
1824 movw %di, %dx
1826 outsl
1827 ret
1828 SET_SIZE(repoutsd)
1830 #elif defined(__i386)
1832 ENTRY(repoutsd)
1833 pushl %esi
1834 movl IO_ADDR(%esp), %esi
1835 movl IO_COUNT(%esp), %ecx
1836 movl IO_PORT(%esp), %edx
1838 outsl
1839 popl %esi
1841 SET_SIZE(repoutsd)
1843 #endif /* __i386 */
1844 #endif /* __lint */
1847 * void int3(void)
1848 * void int18(void)
1849 * void int20(void)
1850 * void int_cmci(void)
1853 #if defined(__lint)
1855 void
1856 int3(void)
1859 void
1860 int18(void)
1863 void
1864 int20(void)
1867 void
1868 int_cmci(void)
1871 #else /* __lint */
1873 ENTRY(int3)
1874 int $T_BPTFLT
1876 SET_SIZE(int3)
1878 ENTRY(int18)
1879 int $T_MCE
1881 SET_SIZE(int18)
1883 ENTRY(int20)
1884 movl boothowto, %eax
1885 andl $RB_DEBUG, %eax
1886 jz 1f
1888 int $T_DBGENTR
1890 rep; ret /* use 2 byte return instruction when branch target */
1891 /* AMD Software Optimization Guide - Section 6.2 */
1892 SET_SIZE(int20)
1894 ENTRY(int_cmci)
1895 int $T_ENOEXTFLT
1897 SET_SIZE(int_cmci)
1899 #endif /* __lint */
1901 #if defined(__lint)
1903 /* ARGSUSED */
1905 scanc(size_t size, uchar_t *cp, uchar_t *table, uchar_t mask)
1906 { return (0); }
1908 #else /* __lint */
1910 #if defined(__amd64)
1912 ENTRY(scanc)
1913 /* rdi == size */
1914 /* rsi == cp */
1915 /* rdx == table */
1916 /* rcx == mask */
1917 addq %rsi, %rdi /* end = &cp[size] */
1918 .scanloop:
1919 cmpq %rdi, %rsi /* while (cp < end */
1920 jnb .scandone
1921 movzbq (%rsi), %r8 /* %r8 = *cp */
1922 incq %rsi /* cp++ */
1923 testb %cl, (%r8, %rdx)
1924 jz .scanloop /* && (table[*cp] & mask) == 0) */
1925 decq %rsi /* (fix post-increment) */
1926 .scandone:
1927 movl %edi, %eax
1928 subl %esi, %eax /* return (end - cp) */
1930 SET_SIZE(scanc)
1932 #elif defined(__i386)
1934 ENTRY(scanc)
1935 pushl %edi
1936 pushl %esi
1937 movb 24(%esp), %cl /* mask = %cl */
1938 movl 16(%esp), %esi /* cp = %esi */
1939 movl 20(%esp), %edx /* table = %edx */
1940 movl %esi, %edi
1941 addl 12(%esp), %edi /* end = &cp[size]; */
1942 .scanloop:
1943 cmpl %edi, %esi /* while (cp < end */
1944 jnb .scandone
1945 movzbl (%esi), %eax /* %al = *cp */
1946 incl %esi /* cp++ */
1947 movb (%edx, %eax), %al /* %al = table[*cp] */
1948 testb %al, %cl
1949 jz .scanloop /* && (table[*cp] & mask) == 0) */
1950 dec %esi /* post-incremented */
1951 .scandone:
1952 movl %edi, %eax
1953 subl %esi, %eax /* return (end - cp) */
1954 popl %esi
1955 popl %edi
1957 SET_SIZE(scanc)
1959 #endif /* __i386 */
1960 #endif /* __lint */
1963 * Replacement functions for ones that are normally inlined.
1964 * In addition to the copy in i86.il, they are defined here just in case.
1967 #if defined(__lint)
1969 ulong_t
1970 intr_clear(void)
1971 { return (0); }
1973 ulong_t
1974 clear_int_flag(void)
1975 { return (0); }
1977 #else /* __lint */
1979 #if defined(__amd64)
1981 ENTRY(intr_clear)
1982 ENTRY(clear_int_flag)
1983 pushfq
1984 popq %rax
1985 #if defined(__xpv)
1986 leaq xpv_panicking, %rdi
1987 movl (%rdi), %edi
1988 cmpl $0, %edi
1989 jne 2f
1990 CLIRET(%rdi, %dl) /* returns event mask in %dl */
1992 * Synthesize the PS_IE bit from the event mask bit
1994 andq $_BITNOT(PS_IE), %rax
1995 testb $1, %dl
1996 jnz 1f
1997 orq $PS_IE, %rax
2001 #endif
2002 CLI(%rdi)
2004 SET_SIZE(clear_int_flag)
2005 SET_SIZE(intr_clear)
2007 #elif defined(__i386)
2009 ENTRY(intr_clear)
2010 ENTRY(clear_int_flag)
2011 pushfl
2012 popl %eax
2013 #if defined(__xpv)
2014 leal xpv_panicking, %edx
2015 movl (%edx), %edx
2016 cmpl $0, %edx
2017 jne 2f
2018 CLIRET(%edx, %cl) /* returns event mask in %cl */
2020 * Synthesize the PS_IE bit from the event mask bit
2022 andl $_BITNOT(PS_IE), %eax
2023 testb $1, %cl
2024 jnz 1f
2025 orl $PS_IE, %eax
2029 #endif
2030 CLI(%edx)
2032 SET_SIZE(clear_int_flag)
2033 SET_SIZE(intr_clear)
2035 #endif /* __i386 */
2036 #endif /* __lint */
2038 #if defined(__lint)
2040 struct cpu *
2041 curcpup(void)
2042 { return 0; }
2044 #else /* __lint */
2046 #if defined(__amd64)
2048 ENTRY(curcpup)
2049 movq %gs:CPU_SELF, %rax
2051 SET_SIZE(curcpup)
2053 #elif defined(__i386)
2055 ENTRY(curcpup)
2056 movl %gs:CPU_SELF, %eax
2058 SET_SIZE(curcpup)
2060 #endif /* __i386 */
2061 #endif /* __lint */
2063 /* htonll(), ntohll(), htonl(), ntohl(), htons(), ntohs()
2064 * These functions reverse the byte order of the input parameter and returns
2065 * the result. This is to convert the byte order from host byte order
2066 * (little endian) to network byte order (big endian), or vice versa.
2069 #if defined(__lint)
2071 uint64_t
2072 htonll(uint64_t i)
2073 { return (i); }
2075 uint64_t
2076 ntohll(uint64_t i)
2077 { return (i); }
2079 uint32_t
2080 htonl(uint32_t i)
2081 { return (i); }
2083 uint32_t
2084 ntohl(uint32_t i)
2085 { return (i); }
2087 uint16_t
2088 htons(uint16_t i)
2089 { return (i); }
2091 uint16_t
2092 ntohs(uint16_t i)
2093 { return (i); }
2095 #else /* __lint */
2097 #if defined(__amd64)
2099 ENTRY(htonll)
2100 ALTENTRY(ntohll)
2101 movq %rdi, %rax
2102 bswapq %rax
2104 SET_SIZE(ntohll)
2105 SET_SIZE(htonll)
2107 /* XX64 there must be shorter sequences for this */
2108 ENTRY(htonl)
2109 ALTENTRY(ntohl)
2110 movl %edi, %eax
2111 bswap %eax
2113 SET_SIZE(ntohl)
2114 SET_SIZE(htonl)
2116 /* XX64 there must be better sequences for this */
2117 ENTRY(htons)
2118 ALTENTRY(ntohs)
2119 movl %edi, %eax
2120 bswap %eax
2121 shrl $16, %eax
2123 SET_SIZE(ntohs)
2124 SET_SIZE(htons)
2126 #elif defined(__i386)
2128 ENTRY(htonll)
2129 ALTENTRY(ntohll)
2130 movl 4(%esp), %edx
2131 movl 8(%esp), %eax
2132 bswap %edx
2133 bswap %eax
2135 SET_SIZE(ntohll)
2136 SET_SIZE(htonll)
2138 ENTRY(htonl)
2139 ALTENTRY(ntohl)
2140 movl 4(%esp), %eax
2141 bswap %eax
2143 SET_SIZE(ntohl)
2144 SET_SIZE(htonl)
2146 ENTRY(htons)
2147 ALTENTRY(ntohs)
2148 movl 4(%esp), %eax
2149 bswap %eax
2150 shrl $16, %eax
2152 SET_SIZE(ntohs)
2153 SET_SIZE(htons)
2155 #endif /* __i386 */
2156 #endif /* __lint */
2159 #if defined(__lint)
2161 /* ARGSUSED */
2162 void
2163 intr_restore(ulong_t i)
2164 { return; }
2166 /* ARGSUSED */
2167 void
2168 restore_int_flag(ulong_t i)
2169 { return; }
2171 #else /* __lint */
2173 #if defined(__amd64)
2175 ENTRY(intr_restore)
2176 ENTRY(restore_int_flag)
2177 testq $PS_IE, %rdi
2178 jz 1f
2179 #if defined(__xpv)
2180 leaq xpv_panicking, %rsi
2181 movl (%rsi), %esi
2182 cmpl $0, %esi
2183 jne 1f
2185 * Since we're -really- running unprivileged, our attempt
2186 * to change the state of the IF bit will be ignored.
2187 * The virtual IF bit is tweaked by CLI and STI.
2189 IE_TO_EVENT_MASK(%rsi, %rdi)
2190 #else
2192 #endif
2195 SET_SIZE(restore_int_flag)
2196 SET_SIZE(intr_restore)
2198 #elif defined(__i386)
2200 ENTRY(intr_restore)
2201 ENTRY(restore_int_flag)
2202 testl $PS_IE, 4(%esp)
2203 jz 1f
2204 #if defined(__xpv)
2205 leal xpv_panicking, %edx
2206 movl (%edx), %edx
2207 cmpl $0, %edx
2208 jne 1f
2210 * Since we're -really- running unprivileged, our attempt
2211 * to change the state of the IF bit will be ignored.
2212 * The virtual IF bit is tweaked by CLI and STI.
2214 IE_TO_EVENT_MASK(%edx, 4(%esp))
2215 #else
2217 #endif
2220 SET_SIZE(restore_int_flag)
2221 SET_SIZE(intr_restore)
2223 #endif /* __i386 */
2224 #endif /* __lint */
2226 #if defined(__lint)
2228 void
2229 sti(void)
2232 void
2233 cli(void)
2236 #else /* __lint */
2238 ENTRY(sti)
2241 SET_SIZE(sti)
2243 ENTRY(cli)
2244 #if defined(__amd64)
2245 CLI(%rax)
2246 #elif defined(__i386)
2247 CLI(%eax)
2248 #endif /* __i386 */
2250 SET_SIZE(cli)
2252 #endif /* __lint */
2254 #if defined(__lint)
2256 dtrace_icookie_t
2257 dtrace_interrupt_disable(void)
2258 { return (0); }
2260 #else /* __lint */
2262 #if defined(__amd64)
2264 ENTRY(dtrace_interrupt_disable)
2265 pushfq
2266 popq %rax
2267 #if defined(__xpv)
2268 leaq xpv_panicking, %rdi
2269 movl (%rdi), %edi
2270 cmpl $0, %edi
2271 jne .dtrace_interrupt_disable_done
2272 CLIRET(%rdi, %dl) /* returns event mask in %dl */
2274 * Synthesize the PS_IE bit from the event mask bit
2276 andq $_BITNOT(PS_IE), %rax
2277 testb $1, %dl
2278 jnz .dtrace_interrupt_disable_done
2279 orq $PS_IE, %rax
2280 #else
2281 CLI(%rdx)
2282 #endif
2283 .dtrace_interrupt_disable_done:
2285 SET_SIZE(dtrace_interrupt_disable)
2287 #elif defined(__i386)
2289 ENTRY(dtrace_interrupt_disable)
2290 pushfl
2291 popl %eax
2292 #if defined(__xpv)
2293 leal xpv_panicking, %edx
2294 movl (%edx), %edx
2295 cmpl $0, %edx
2296 jne .dtrace_interrupt_disable_done
2297 CLIRET(%edx, %cl) /* returns event mask in %cl */
2299 * Synthesize the PS_IE bit from the event mask bit
2301 andl $_BITNOT(PS_IE), %eax
2302 testb $1, %cl
2303 jnz .dtrace_interrupt_disable_done
2304 orl $PS_IE, %eax
2305 #else
2306 CLI(%edx)
2307 #endif
2308 .dtrace_interrupt_disable_done:
2310 SET_SIZE(dtrace_interrupt_disable)
2312 #endif /* __i386 */
2313 #endif /* __lint */
2315 #if defined(__lint)
2317 /*ARGSUSED*/
2318 void
2319 dtrace_interrupt_enable(dtrace_icookie_t cookie)
2322 #else /* __lint */
2324 #if defined(__amd64)
2326 ENTRY(dtrace_interrupt_enable)
2327 pushq %rdi
2328 popfq
2329 #if defined(__xpv)
2330 leaq xpv_panicking, %rdx
2331 movl (%rdx), %edx
2332 cmpl $0, %edx
2333 jne .dtrace_interrupt_enable_done
2335 * Since we're -really- running unprivileged, our attempt
2336 * to change the state of the IF bit will be ignored. The
2337 * virtual IF bit is tweaked by CLI and STI.
2339 IE_TO_EVENT_MASK(%rdx, %rdi)
2340 #endif
2341 .dtrace_interrupt_enable_done:
2343 SET_SIZE(dtrace_interrupt_enable)
2345 #elif defined(__i386)
2347 ENTRY(dtrace_interrupt_enable)
2348 movl 4(%esp), %eax
2349 pushl %eax
2350 popfl
2351 #if defined(__xpv)
2352 leal xpv_panicking, %edx
2353 movl (%edx), %edx
2354 cmpl $0, %edx
2355 jne .dtrace_interrupt_enable_done
2357 * Since we're -really- running unprivileged, our attempt
2358 * to change the state of the IF bit will be ignored. The
2359 * virtual IF bit is tweaked by CLI and STI.
2361 IE_TO_EVENT_MASK(%edx, %eax)
2362 #endif
2363 .dtrace_interrupt_enable_done:
2365 SET_SIZE(dtrace_interrupt_enable)
2367 #endif /* __i386 */
2368 #endif /* __lint */
2371 #if defined(lint)
2373 void
2374 dtrace_membar_producer(void)
2377 void
2378 dtrace_membar_consumer(void)
2381 #else /* __lint */
2383 ENTRY(dtrace_membar_producer)
2384 rep; ret /* use 2 byte return instruction when branch target */
2385 /* AMD Software Optimization Guide - Section 6.2 */
2386 SET_SIZE(dtrace_membar_producer)
2388 ENTRY(dtrace_membar_consumer)
2389 rep; ret /* use 2 byte return instruction when branch target */
2390 /* AMD Software Optimization Guide - Section 6.2 */
2391 SET_SIZE(dtrace_membar_consumer)
2393 #endif /* __lint */
2395 #if defined(__lint)
2397 kthread_id_t
2398 threadp(void)
2399 { return ((kthread_id_t)0); }
2401 #else /* __lint */
2403 #if defined(__amd64)
2405 ENTRY(threadp)
2406 movq %gs:CPU_THREAD, %rax
2408 SET_SIZE(threadp)
2410 #elif defined(__i386)
2412 ENTRY(threadp)
2413 movl %gs:CPU_THREAD, %eax
2415 SET_SIZE(threadp)
2417 #endif /* __i386 */
2418 #endif /* __lint */
2421 * Checksum routine for Internet Protocol Headers
2424 #if defined(__lint)
2426 /* ARGSUSED */
2427 unsigned int
2428 ip_ocsum(
2429 ushort_t *address, /* ptr to 1st message buffer */
2430 int halfword_count, /* length of data */
2431 unsigned int sum) /* partial checksum */
2433 int i;
2434 unsigned int psum = 0; /* partial sum */
2436 for (i = 0; i < halfword_count; i++, address++) {
2437 psum += *address;
2440 while ((psum >> 16) != 0) {
2441 psum = (psum & 0xffff) + (psum >> 16);
2444 psum += sum;
2446 while ((psum >> 16) != 0) {
2447 psum = (psum & 0xffff) + (psum >> 16);
2450 return (psum);
2453 #else /* __lint */
2455 #if defined(__amd64)
2457 ENTRY(ip_ocsum)
2458 pushq %rbp
2459 movq %rsp, %rbp
2460 #ifdef DEBUG
2461 movq postbootkernelbase(%rip), %rax
2462 cmpq %rax, %rdi
2463 jnb 1f
2464 xorl %eax, %eax
2465 movq %rdi, %rsi
2466 leaq .ip_ocsum_panic_msg(%rip), %rdi
2467 call panic
2468 /*NOTREACHED*/
2469 .ip_ocsum_panic_msg:
2470 .string "ip_ocsum: address 0x%p below kernelbase\n"
2472 #endif
2473 movl %esi, %ecx /* halfword_count */
2474 movq %rdi, %rsi /* address */
2475 /* partial sum in %edx */
2476 xorl %eax, %eax
2477 testl %ecx, %ecx
2478 jz .ip_ocsum_done
2479 testq $3, %rsi
2480 jnz .ip_csum_notaligned
2481 .ip_csum_aligned: /* XX64 opportunities for 8-byte operations? */
2482 .next_iter:
2483 /* XX64 opportunities for prefetch? */
2484 /* XX64 compute csum with 64 bit quantities? */
2485 subl $32, %ecx
2486 jl .less_than_32
2488 addl 0(%rsi), %edx
2489 .only60:
2490 adcl 4(%rsi), %eax
2491 .only56:
2492 adcl 8(%rsi), %edx
2493 .only52:
2494 adcl 12(%rsi), %eax
2495 .only48:
2496 adcl 16(%rsi), %edx
2497 .only44:
2498 adcl 20(%rsi), %eax
2499 .only40:
2500 adcl 24(%rsi), %edx
2501 .only36:
2502 adcl 28(%rsi), %eax
2503 .only32:
2504 adcl 32(%rsi), %edx
2505 .only28:
2506 adcl 36(%rsi), %eax
2507 .only24:
2508 adcl 40(%rsi), %edx
2509 .only20:
2510 adcl 44(%rsi), %eax
2511 .only16:
2512 adcl 48(%rsi), %edx
2513 .only12:
2514 adcl 52(%rsi), %eax
2515 .only8:
2516 adcl 56(%rsi), %edx
2517 .only4:
2518 adcl 60(%rsi), %eax /* could be adding -1 and -1 with a carry */
2519 .only0:
2520 adcl $0, %eax /* could be adding -1 in eax with a carry */
2521 adcl $0, %eax
2523 addq $64, %rsi
2524 testl %ecx, %ecx
2525 jnz .next_iter
2527 .ip_ocsum_done:
2528 addl %eax, %edx
2529 adcl $0, %edx
2530 movl %edx, %eax /* form a 16 bit checksum by */
2531 shrl $16, %eax /* adding two halves of 32 bit checksum */
2532 addw %dx, %ax
2533 adcw $0, %ax
2534 andl $0xffff, %eax
2535 leave
2538 .ip_csum_notaligned:
2539 xorl %edi, %edi
2540 movw (%rsi), %di
2541 addl %edi, %edx
2542 adcl $0, %edx
2543 addq $2, %rsi
2544 decl %ecx
2545 jmp .ip_csum_aligned
2547 .less_than_32:
2548 addl $32, %ecx
2549 testl $1, %ecx
2550 jz .size_aligned
2551 andl $0xfe, %ecx
2552 movzwl (%rsi, %rcx, 2), %edi
2553 addl %edi, %edx
2554 adcl $0, %edx
2555 .size_aligned:
2556 movl %ecx, %edi
2557 shrl $1, %ecx
2558 shl $1, %edi
2559 subq $64, %rdi
2560 addq %rdi, %rsi
2561 leaq .ip_ocsum_jmptbl(%rip), %rdi
2562 leaq (%rdi, %rcx, 8), %rdi
2563 xorl %ecx, %ecx
2565 jmp *(%rdi)
2567 .align 8
2568 .ip_ocsum_jmptbl:
2569 .quad .only0, .only4, .only8, .only12, .only16, .only20
2570 .quad .only24, .only28, .only32, .only36, .only40, .only44
2571 .quad .only48, .only52, .only56, .only60
2572 SET_SIZE(ip_ocsum)
2574 #elif defined(__i386)
2576 ENTRY(ip_ocsum)
2577 pushl %ebp
2578 movl %esp, %ebp
2579 pushl %ebx
2580 pushl %esi
2581 pushl %edi
2582 movl 12(%ebp), %ecx /* count of half words */
2583 movl 16(%ebp), %edx /* partial checksum */
2584 movl 8(%ebp), %esi
2585 xorl %eax, %eax
2586 testl %ecx, %ecx
2587 jz .ip_ocsum_done
2589 testl $3, %esi
2590 jnz .ip_csum_notaligned
2591 .ip_csum_aligned:
2592 .next_iter:
2593 subl $32, %ecx
2594 jl .less_than_32
2596 addl 0(%esi), %edx
2597 .only60:
2598 adcl 4(%esi), %eax
2599 .only56:
2600 adcl 8(%esi), %edx
2601 .only52:
2602 adcl 12(%esi), %eax
2603 .only48:
2604 adcl 16(%esi), %edx
2605 .only44:
2606 adcl 20(%esi), %eax
2607 .only40:
2608 adcl 24(%esi), %edx
2609 .only36:
2610 adcl 28(%esi), %eax
2611 .only32:
2612 adcl 32(%esi), %edx
2613 .only28:
2614 adcl 36(%esi), %eax
2615 .only24:
2616 adcl 40(%esi), %edx
2617 .only20:
2618 adcl 44(%esi), %eax
2619 .only16:
2620 adcl 48(%esi), %edx
2621 .only12:
2622 adcl 52(%esi), %eax
2623 .only8:
2624 adcl 56(%esi), %edx
2625 .only4:
2626 adcl 60(%esi), %eax /* We could be adding -1 and -1 with a carry */
2627 .only0:
2628 adcl $0, %eax /* we could be adding -1 in eax with a carry */
2629 adcl $0, %eax
2631 addl $64, %esi
2632 andl %ecx, %ecx
2633 jnz .next_iter
2635 .ip_ocsum_done:
2636 addl %eax, %edx
2637 adcl $0, %edx
2638 movl %edx, %eax /* form a 16 bit checksum by */
2639 shrl $16, %eax /* adding two halves of 32 bit checksum */
2640 addw %dx, %ax
2641 adcw $0, %ax
2642 andl $0xffff, %eax
2643 popl %edi /* restore registers */
2644 popl %esi
2645 popl %ebx
2646 leave
2649 .ip_csum_notaligned:
2650 xorl %edi, %edi
2651 movw (%esi), %di
2652 addl %edi, %edx
2653 adcl $0, %edx
2654 addl $2, %esi
2655 decl %ecx
2656 jmp .ip_csum_aligned
2658 .less_than_32:
2659 addl $32, %ecx
2660 testl $1, %ecx
2661 jz .size_aligned
2662 andl $0xfe, %ecx
2663 movzwl (%esi, %ecx, 2), %edi
2664 addl %edi, %edx
2665 adcl $0, %edx
2666 .size_aligned:
2667 movl %ecx, %edi
2668 shrl $1, %ecx
2669 shl $1, %edi
2670 subl $64, %edi
2671 addl %edi, %esi
2672 movl $.ip_ocsum_jmptbl, %edi
2673 lea (%edi, %ecx, 4), %edi
2674 xorl %ecx, %ecx
2676 jmp *(%edi)
2677 SET_SIZE(ip_ocsum)
2679 .data
2680 .align 4
2682 .ip_ocsum_jmptbl:
2683 .long .only0, .only4, .only8, .only12, .only16, .only20
2684 .long .only24, .only28, .only32, .only36, .only40, .only44
2685 .long .only48, .only52, .only56, .only60
2688 #endif /* __i386 */
2689 #endif /* __lint */
2692 * multiply two long numbers and yield a u_longlong_t result, callable from C.
2693 * Provided to manipulate hrtime_t values.
2695 #if defined(__lint)
2697 /* result = a * b; */
2699 /* ARGSUSED */
2700 unsigned long long
2701 mul32(uint_t a, uint_t b)
2702 { return (0); }
2704 #else /* __lint */
2706 #if defined(__amd64)
2708 ENTRY(mul32)
2709 xorl %edx, %edx /* XX64 joe, paranoia? */
2710 movl %edi, %eax
2711 mull %esi
2712 shlq $32, %rdx
2713 orq %rdx, %rax
2715 SET_SIZE(mul32)
2717 #elif defined(__i386)
2719 ENTRY(mul32)
2720 movl 8(%esp), %eax
2721 movl 4(%esp), %ecx
2722 mull %ecx
2724 SET_SIZE(mul32)
2726 #endif /* __i386 */
2727 #endif /* __lint */
2729 #if defined(notused)
2730 #if defined(__lint)
2731 /* ARGSUSED */
2732 void
2733 load_pte64(uint64_t *pte, uint64_t pte_value)
2735 #else /* __lint */
2736 .globl load_pte64
2737 load_pte64:
2738 movl 4(%esp), %eax
2739 movl 8(%esp), %ecx
2740 movl 12(%esp), %edx
2741 movl %edx, 4(%eax)
2742 movl %ecx, (%eax)
2744 #endif /* __lint */
2745 #endif /* notused */
2747 #if defined(__lint)
2749 /*ARGSUSED*/
2750 void
2751 scan_memory(caddr_t addr, size_t size)
2754 #else /* __lint */
2756 #if defined(__amd64)
2758 ENTRY(scan_memory)
2759 shrq $3, %rsi /* convert %rsi from byte to quadword count */
2760 jz .scanm_done
2761 movq %rsi, %rcx /* move count into rep control register */
2762 movq %rdi, %rsi /* move addr into lodsq control reg. */
2763 rep lodsq /* scan the memory range */
2764 .scanm_done:
2765 rep; ret /* use 2 byte return instruction when branch target */
2766 /* AMD Software Optimization Guide - Section 6.2 */
2767 SET_SIZE(scan_memory)
2769 #elif defined(__i386)
2771 ENTRY(scan_memory)
2772 pushl %ecx
2773 pushl %esi
2774 movl 16(%esp), %ecx /* move 2nd arg into rep control register */
2775 shrl $2, %ecx /* convert from byte count to word count */
2776 jz .scanm_done
2777 movl 12(%esp), %esi /* move 1st arg into lodsw control register */
2778 .byte 0xf3 /* rep prefix. lame assembler. sigh. */
2779 lodsl
2780 .scanm_done:
2781 popl %esi
2782 popl %ecx
2784 SET_SIZE(scan_memory)
2786 #endif /* __i386 */
2787 #endif /* __lint */
2790 #if defined(__lint)
2792 /*ARGSUSED */
2794 lowbit(ulong_t i)
2795 { return (0); }
2797 #else /* __lint */
2799 #if defined(__amd64)
2801 ENTRY(lowbit)
2802 movl $-1, %eax
2803 bsfq %rdi, %rax
2804 incl %eax
2806 SET_SIZE(lowbit)
2808 #elif defined(__i386)
2810 ENTRY(lowbit)
2811 movl $-1, %eax
2812 bsfl 4(%esp), %eax
2813 incl %eax
2815 SET_SIZE(lowbit)
2817 #endif /* __i386 */
2818 #endif /* __lint */
2820 #if defined(__lint)
2822 /*ARGSUSED*/
2824 highbit(ulong_t i)
2825 { return (0); }
2827 #else /* __lint */
2829 #if defined(__amd64)
2831 ENTRY(highbit)
2832 movl $-1, %eax
2833 bsrq %rdi, %rax
2834 incl %eax
2836 SET_SIZE(highbit)
2838 #elif defined(__i386)
2840 ENTRY(highbit)
2841 movl $-1, %eax
2842 bsrl 4(%esp), %eax
2843 incl %eax
2845 SET_SIZE(highbit)
2847 #endif /* __i386 */
2848 #endif /* __lint */
2850 #if defined(__lint)
2852 /*ARGSUSED*/
2853 uint64_t
2854 rdmsr(uint_t r)
2855 { return (0); }
2857 /*ARGSUSED*/
2858 void
2859 wrmsr(uint_t r, const uint64_t val)
2862 /*ARGSUSED*/
2863 uint64_t
2864 xrdmsr(uint_t r)
2865 { return (0); }
2867 /*ARGSUSED*/
2868 void
2869 xwrmsr(uint_t r, const uint64_t val)
2872 void
2873 invalidate_cache(void)
2876 /*ARGSUSED*/
2877 uint64_t
2878 get_xcr(uint_t r)
2879 { return (0); }
2881 /*ARGSUSED*/
2882 void
2883 set_xcr(uint_t r, const uint64_t val)
2886 #else /* __lint */
2888 #define XMSR_ACCESS_VAL $0x9c5a203a
2890 #if defined(__amd64)
2892 ENTRY(rdmsr)
2893 movl %edi, %ecx
2894 rdmsr
2895 shlq $32, %rdx
2896 orq %rdx, %rax
2898 SET_SIZE(rdmsr)
2900 ENTRY(wrmsr)
2901 movq %rsi, %rdx
2902 shrq $32, %rdx
2903 movl %esi, %eax
2904 movl %edi, %ecx
2905 wrmsr
2907 SET_SIZE(wrmsr)
2909 ENTRY(xrdmsr)
2910 pushq %rbp
2911 movq %rsp, %rbp
2912 movl %edi, %ecx
2913 movl XMSR_ACCESS_VAL, %edi /* this value is needed to access MSR */
2914 rdmsr
2915 shlq $32, %rdx
2916 orq %rdx, %rax
2917 leave
2919 SET_SIZE(xrdmsr)
2921 ENTRY(xwrmsr)
2922 pushq %rbp
2923 movq %rsp, %rbp
2924 movl %edi, %ecx
2925 movl XMSR_ACCESS_VAL, %edi /* this value is needed to access MSR */
2926 movq %rsi, %rdx
2927 shrq $32, %rdx
2928 movl %esi, %eax
2929 wrmsr
2930 leave
2932 SET_SIZE(xwrmsr)
2934 ENTRY(get_xcr)
2935 movl %edi, %ecx
2936 #xgetbv
2937 .byte 0x0f,0x01,0xd0
2938 shlq $32, %rdx
2939 orq %rdx, %rax
2941 SET_SIZE(get_xcr)
2943 ENTRY(set_xcr)
2944 movq %rsi, %rdx
2945 shrq $32, %rdx
2946 movl %esi, %eax
2947 movl %edi, %ecx
2948 #xsetbv
2949 .byte 0x0f,0x01,0xd1
2951 SET_SIZE(set_xcr)
2953 #elif defined(__i386)
2955 ENTRY(rdmsr)
2956 movl 4(%esp), %ecx
2957 rdmsr
2959 SET_SIZE(rdmsr)
2961 ENTRY(wrmsr)
2962 movl 4(%esp), %ecx
2963 movl 8(%esp), %eax
2964 movl 12(%esp), %edx
2965 wrmsr
2967 SET_SIZE(wrmsr)
2969 ENTRY(xrdmsr)
2970 pushl %ebp
2971 movl %esp, %ebp
2972 movl 8(%esp), %ecx
2973 pushl %edi
2974 movl XMSR_ACCESS_VAL, %edi /* this value is needed to access MSR */
2975 rdmsr
2976 popl %edi
2977 leave
2979 SET_SIZE(xrdmsr)
2981 ENTRY(xwrmsr)
2982 pushl %ebp
2983 movl %esp, %ebp
2984 movl 8(%esp), %ecx
2985 movl 12(%esp), %eax
2986 movl 16(%esp), %edx
2987 pushl %edi
2988 movl XMSR_ACCESS_VAL, %edi /* this value is needed to access MSR */
2989 wrmsr
2990 popl %edi
2991 leave
2993 SET_SIZE(xwrmsr)
2995 ENTRY(get_xcr)
2996 movl 4(%esp), %ecx
2997 #xgetbv
2998 .byte 0x0f,0x01,0xd0
3000 SET_SIZE(get_xcr)
3002 ENTRY(set_xcr)
3003 movl 4(%esp), %ecx
3004 movl 8(%esp), %eax
3005 movl 12(%esp), %edx
3006 #xsetbv
3007 .byte 0x0f,0x01,0xd1
3009 SET_SIZE(set_xcr)
3011 #endif /* __i386 */
3013 ENTRY(invalidate_cache)
3014 wbinvd
3016 SET_SIZE(invalidate_cache)
3018 #endif /* __lint */
3020 #if defined(__lint)
3022 /*ARGSUSED*/
3023 void
3024 getcregs(struct cregs *crp)
3027 #else /* __lint */
3029 #if defined(__amd64)
3031 ENTRY_NP(getcregs)
3032 #if defined(__xpv)
3034 * Only a few of the hardware control registers or descriptor tables
3035 * are directly accessible to us, so just zero the structure.
3037 * XXPV Perhaps it would be helpful for the hypervisor to return
3038 * virtualized versions of these for post-mortem use.
3039 * (Need to reevaluate - perhaps it already does!)
3041 pushq %rdi /* save *crp */
3042 movq $CREGSZ, %rsi
3043 call bzero
3044 popq %rdi
3047 * Dump what limited information we can
3049 movq %cr0, %rax
3050 movq %rax, CREG_CR0(%rdi) /* cr0 */
3051 movq %cr2, %rax
3052 movq %rax, CREG_CR2(%rdi) /* cr2 */
3053 movq %cr3, %rax
3054 movq %rax, CREG_CR3(%rdi) /* cr3 */
3055 movq %cr4, %rax
3056 movq %rax, CREG_CR4(%rdi) /* cr4 */
3058 #else /* __xpv */
3060 #define GETMSR(r, off, d) \
3061 movl $r, %ecx; \
3062 rdmsr; \
3063 movl %eax, off(d); \
3064 movl %edx, off+4(d)
3066 xorl %eax, %eax
3067 movq %rax, CREG_GDT+8(%rdi)
3068 sgdt CREG_GDT(%rdi) /* 10 bytes */
3069 movq %rax, CREG_IDT+8(%rdi)
3070 sidt CREG_IDT(%rdi) /* 10 bytes */
3071 movq %rax, CREG_LDT(%rdi)
3072 sldt CREG_LDT(%rdi) /* 2 bytes */
3073 movq %rax, CREG_TASKR(%rdi)
3074 str CREG_TASKR(%rdi) /* 2 bytes */
3075 movq %cr0, %rax
3076 movq %rax, CREG_CR0(%rdi) /* cr0 */
3077 movq %cr2, %rax
3078 movq %rax, CREG_CR2(%rdi) /* cr2 */
3079 movq %cr3, %rax
3080 movq %rax, CREG_CR3(%rdi) /* cr3 */
3081 movq %cr4, %rax
3082 movq %rax, CREG_CR4(%rdi) /* cr4 */
3083 movq %cr8, %rax
3084 movq %rax, CREG_CR8(%rdi) /* cr8 */
3085 GETMSR(MSR_AMD_KGSBASE, CREG_KGSBASE, %rdi)
3086 GETMSR(MSR_AMD_EFER, CREG_EFER, %rdi)
3087 #endif /* __xpv */
3089 SET_SIZE(getcregs)
3091 #undef GETMSR
3093 #elif defined(__i386)
3095 ENTRY_NP(getcregs)
3096 #if defined(__xpv)
3098 * Only a few of the hardware control registers or descriptor tables
3099 * are directly accessible to us, so just zero the structure.
3101 * XXPV Perhaps it would be helpful for the hypervisor to return
3102 * virtualized versions of these for post-mortem use.
3103 * (Need to reevaluate - perhaps it already does!)
3105 movl 4(%esp), %edx
3106 pushl $CREGSZ
3107 pushl %edx
3108 call bzero
3109 addl $8, %esp
3110 movl 4(%esp), %edx
3113 * Dump what limited information we can
3115 movl %cr0, %eax
3116 movl %eax, CREG_CR0(%edx) /* cr0 */
3117 movl %cr2, %eax
3118 movl %eax, CREG_CR2(%edx) /* cr2 */
3119 movl %cr3, %eax
3120 movl %eax, CREG_CR3(%edx) /* cr3 */
3121 movl %cr4, %eax
3122 movl %eax, CREG_CR4(%edx) /* cr4 */
3124 #else /* __xpv */
3126 movl 4(%esp), %edx
3127 movw $0, CREG_GDT+6(%edx)
3128 movw $0, CREG_IDT+6(%edx)
3129 sgdt CREG_GDT(%edx) /* gdt */
3130 sidt CREG_IDT(%edx) /* idt */
3131 sldt CREG_LDT(%edx) /* ldt */
3132 str CREG_TASKR(%edx) /* task */
3133 movl %cr0, %eax
3134 movl %eax, CREG_CR0(%edx) /* cr0 */
3135 movl %cr2, %eax
3136 movl %eax, CREG_CR2(%edx) /* cr2 */
3137 movl %cr3, %eax
3138 movl %eax, CREG_CR3(%edx) /* cr3 */
3139 bt $X86FSET_LARGEPAGE, x86_featureset
3140 jnc .nocr4
3141 movl %cr4, %eax
3142 movl %eax, CREG_CR4(%edx) /* cr4 */
3143 jmp .skip
3144 .nocr4:
3145 movl $0, CREG_CR4(%edx)
3146 .skip:
3147 #endif
3149 SET_SIZE(getcregs)
3151 #endif /* __i386 */
3152 #endif /* __lint */
3156 * A panic trigger is a word which is updated atomically and can only be set
3157 * once. We atomically store 0xDEFACEDD and load the old value. If the
3158 * previous value was 0, we succeed and return 1; otherwise return 0.
3159 * This allows a partially corrupt trigger to still trigger correctly. DTrace
3160 * has its own version of this function to allow it to panic correctly from
3161 * probe context.
3163 #if defined(__lint)
3165 /*ARGSUSED*/
3167 panic_trigger(int *tp)
3168 { return (0); }
3170 /*ARGSUSED*/
3172 dtrace_panic_trigger(int *tp)
3173 { return (0); }
3175 #else /* __lint */
3177 #if defined(__amd64)
3179 ENTRY_NP(panic_trigger)
3180 xorl %eax, %eax
3181 movl $0xdefacedd, %edx
3182 lock
3183 xchgl %edx, (%rdi)
3184 cmpl $0, %edx
3185 je 0f
3186 movl $0, %eax
3188 0: movl $1, %eax
3190 SET_SIZE(panic_trigger)
3192 ENTRY_NP(dtrace_panic_trigger)
3193 xorl %eax, %eax
3194 movl $0xdefacedd, %edx
3195 lock
3196 xchgl %edx, (%rdi)
3197 cmpl $0, %edx
3198 je 0f
3199 movl $0, %eax
3201 0: movl $1, %eax
3203 SET_SIZE(dtrace_panic_trigger)
3205 #elif defined(__i386)
3207 ENTRY_NP(panic_trigger)
3208 movl 4(%esp), %edx / %edx = address of trigger
3209 movl $0xdefacedd, %eax / %eax = 0xdefacedd
3210 lock / assert lock
3211 xchgl %eax, (%edx) / exchange %eax and the trigger
3212 cmpl $0, %eax / if (%eax == 0x0)
3213 je 0f / return (1);
3214 movl $0, %eax / else
3215 ret / return (0);
3216 0: movl $1, %eax
3218 SET_SIZE(panic_trigger)
3220 ENTRY_NP(dtrace_panic_trigger)
3221 movl 4(%esp), %edx / %edx = address of trigger
3222 movl $0xdefacedd, %eax / %eax = 0xdefacedd
3223 lock / assert lock
3224 xchgl %eax, (%edx) / exchange %eax and the trigger
3225 cmpl $0, %eax / if (%eax == 0x0)
3226 je 0f / return (1);
3227 movl $0, %eax / else
3228 ret / return (0);
3229 0: movl $1, %eax
3231 SET_SIZE(dtrace_panic_trigger)
3233 #endif /* __i386 */
3234 #endif /* __lint */
3237 * The panic() and cmn_err() functions invoke vpanic() as a common entry point
3238 * into the panic code implemented in panicsys(). vpanic() is responsible
3239 * for passing through the format string and arguments, and constructing a
3240 * regs structure on the stack into which it saves the current register
3241 * values. If we are not dying due to a fatal trap, these registers will
3242 * then be preserved in panicbuf as the current processor state. Before
3243 * invoking panicsys(), vpanic() activates the first panic trigger (see
3244 * common/os/panic.c) and switches to the panic_stack if successful. Note that
3245 * DTrace takes a slightly different panic path if it must panic from probe
3246 * context. Instead of calling panic, it calls into dtrace_vpanic(), which
3247 * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
3248 * branches back into vpanic().
3250 #if defined(__lint)
3252 /*ARGSUSED*/
3253 void
3254 vpanic(const char *format, va_list alist)
3257 /*ARGSUSED*/
3258 void
3259 dtrace_vpanic(const char *format, va_list alist)
3262 #else /* __lint */
3264 #if defined(__amd64)
3266 ENTRY_NP(vpanic) /* Initial stack layout: */
3268 pushq %rbp /* | %rip | 0x60 */
3269 movq %rsp, %rbp /* | %rbp | 0x58 */
3270 pushfq /* | rfl | 0x50 */
3271 pushq %r11 /* | %r11 | 0x48 */
3272 pushq %r10 /* | %r10 | 0x40 */
3273 pushq %rbx /* | %rbx | 0x38 */
3274 pushq %rax /* | %rax | 0x30 */
3275 pushq %r9 /* | %r9 | 0x28 */
3276 pushq %r8 /* | %r8 | 0x20 */
3277 pushq %rcx /* | %rcx | 0x18 */
3278 pushq %rdx /* | %rdx | 0x10 */
3279 pushq %rsi /* | %rsi | 0x8 alist */
3280 pushq %rdi /* | %rdi | 0x0 format */
3282 movq %rsp, %rbx /* %rbx = current %rsp */
3284 leaq panic_quiesce(%rip), %rdi /* %rdi = &panic_quiesce */
3285 call panic_trigger /* %eax = panic_trigger() */
3287 vpanic_common:
3289 * The panic_trigger result is in %eax from the call above, and
3290 * dtrace_panic places it in %eax before branching here.
3291 * The rdmsr instructions that follow below will clobber %eax so
3292 * we stash the panic_trigger result in %r11d.
3294 movl %eax, %r11d
3295 cmpl $0, %r11d
3296 je 0f
3299 * If panic_trigger() was successful, we are the first to initiate a
3300 * panic: we now switch to the reserved panic_stack before continuing.
3302 leaq panic_stack(%rip), %rsp
3303 addq $PANICSTKSIZE, %rsp
3304 0: subq $REGSIZE, %rsp
3306 * Now that we've got everything set up, store the register values as
3307 * they were when we entered vpanic() to the designated location in
3308 * the regs structure we allocated on the stack.
3310 movq 0x0(%rbx), %rcx
3311 movq %rcx, REGOFF_RDI(%rsp)
3312 movq 0x8(%rbx), %rcx
3313 movq %rcx, REGOFF_RSI(%rsp)
3314 movq 0x10(%rbx), %rcx
3315 movq %rcx, REGOFF_RDX(%rsp)
3316 movq 0x18(%rbx), %rcx
3317 movq %rcx, REGOFF_RCX(%rsp)
3318 movq 0x20(%rbx), %rcx
3320 movq %rcx, REGOFF_R8(%rsp)
3321 movq 0x28(%rbx), %rcx
3322 movq %rcx, REGOFF_R9(%rsp)
3323 movq 0x30(%rbx), %rcx
3324 movq %rcx, REGOFF_RAX(%rsp)
3325 movq 0x38(%rbx), %rcx
3326 movq %rcx, REGOFF_RBX(%rsp)
3327 movq 0x58(%rbx), %rcx
3329 movq %rcx, REGOFF_RBP(%rsp)
3330 movq 0x40(%rbx), %rcx
3331 movq %rcx, REGOFF_R10(%rsp)
3332 movq 0x48(%rbx), %rcx
3333 movq %rcx, REGOFF_R11(%rsp)
3334 movq %r12, REGOFF_R12(%rsp)
3336 movq %r13, REGOFF_R13(%rsp)
3337 movq %r14, REGOFF_R14(%rsp)
3338 movq %r15, REGOFF_R15(%rsp)
3340 xorl %ecx, %ecx
3341 movw %ds, %cx
3342 movq %rcx, REGOFF_DS(%rsp)
3343 movw %es, %cx
3344 movq %rcx, REGOFF_ES(%rsp)
3345 movw %fs, %cx
3346 movq %rcx, REGOFF_FS(%rsp)
3347 movw %gs, %cx
3348 movq %rcx, REGOFF_GS(%rsp)
3350 movq $0, REGOFF_TRAPNO(%rsp)
3352 movq $0, REGOFF_ERR(%rsp)
3353 leaq vpanic(%rip), %rcx
3354 movq %rcx, REGOFF_RIP(%rsp)
3355 movw %cs, %cx
3356 movzwq %cx, %rcx
3357 movq %rcx, REGOFF_CS(%rsp)
3358 movq 0x50(%rbx), %rcx
3359 movq %rcx, REGOFF_RFL(%rsp)
3360 movq %rbx, %rcx
3361 addq $0x60, %rcx
3362 movq %rcx, REGOFF_RSP(%rsp)
3363 movw %ss, %cx
3364 movzwq %cx, %rcx
3365 movq %rcx, REGOFF_SS(%rsp)
3368 * panicsys(format, alist, rp, on_panic_stack)
3370 movq REGOFF_RDI(%rsp), %rdi /* format */
3371 movq REGOFF_RSI(%rsp), %rsi /* alist */
3372 movq %rsp, %rdx /* struct regs */
3373 movl %r11d, %ecx /* on_panic_stack */
3374 call panicsys
3375 addq $REGSIZE, %rsp
3376 popq %rdi
3377 popq %rsi
3378 popq %rdx
3379 popq %rcx
3380 popq %r8
3381 popq %r9
3382 popq %rax
3383 popq %rbx
3384 popq %r10
3385 popq %r11
3386 popfq
3387 leave
3389 SET_SIZE(vpanic)
3391 ENTRY_NP(dtrace_vpanic) /* Initial stack layout: */
3393 pushq %rbp /* | %rip | 0x60 */
3394 movq %rsp, %rbp /* | %rbp | 0x58 */
3395 pushfq /* | rfl | 0x50 */
3396 pushq %r11 /* | %r11 | 0x48 */
3397 pushq %r10 /* | %r10 | 0x40 */
3398 pushq %rbx /* | %rbx | 0x38 */
3399 pushq %rax /* | %rax | 0x30 */
3400 pushq %r9 /* | %r9 | 0x28 */
3401 pushq %r8 /* | %r8 | 0x20 */
3402 pushq %rcx /* | %rcx | 0x18 */
3403 pushq %rdx /* | %rdx | 0x10 */
3404 pushq %rsi /* | %rsi | 0x8 alist */
3405 pushq %rdi /* | %rdi | 0x0 format */
3407 movq %rsp, %rbx /* %rbx = current %rsp */
3409 leaq panic_quiesce(%rip), %rdi /* %rdi = &panic_quiesce */
3410 call dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */
3411 jmp vpanic_common
3413 SET_SIZE(dtrace_vpanic)
3415 #elif defined(__i386)
3417 ENTRY_NP(vpanic) / Initial stack layout:
3419 pushl %ebp / | %eip | 20
3420 movl %esp, %ebp / | %ebp | 16
3421 pushl %eax / | %eax | 12
3422 pushl %ebx / | %ebx | 8
3423 pushl %ecx / | %ecx | 4
3424 pushl %edx / | %edx | 0
3426 movl %esp, %ebx / %ebx = current stack pointer
3428 lea panic_quiesce, %eax / %eax = &panic_quiesce
3429 pushl %eax / push &panic_quiesce
3430 call panic_trigger / %eax = panic_trigger()
3431 addl $4, %esp / reset stack pointer
3433 vpanic_common:
3434 cmpl $0, %eax / if (%eax == 0)
3435 je 0f / goto 0f;
3438 * If panic_trigger() was successful, we are the first to initiate a
3439 * panic: we now switch to the reserved panic_stack before continuing.
3441 lea panic_stack, %esp / %esp = panic_stack
3442 addl $PANICSTKSIZE, %esp / %esp += PANICSTKSIZE
3444 0: subl $REGSIZE, %esp / allocate struct regs
3447 * Now that we've got everything set up, store the register values as
3448 * they were when we entered vpanic() to the designated location in
3449 * the regs structure we allocated on the stack.
3451 #if !defined(__GNUC_AS__)
3452 movw %gs, %edx
3453 movl %edx, REGOFF_GS(%esp)
3454 movw %fs, %edx
3455 movl %edx, REGOFF_FS(%esp)
3456 movw %es, %edx
3457 movl %edx, REGOFF_ES(%esp)
3458 movw %ds, %edx
3459 movl %edx, REGOFF_DS(%esp)
3460 #else /* __GNUC_AS__ */
3461 mov %gs, %edx
3462 mov %edx, REGOFF_GS(%esp)
3463 mov %fs, %edx
3464 mov %edx, REGOFF_FS(%esp)
3465 mov %es, %edx
3466 mov %edx, REGOFF_ES(%esp)
3467 mov %ds, %edx
3468 mov %edx, REGOFF_DS(%esp)
3469 #endif /* __GNUC_AS__ */
3470 movl %edi, REGOFF_EDI(%esp)
3471 movl %esi, REGOFF_ESI(%esp)
3472 movl 16(%ebx), %ecx
3473 movl %ecx, REGOFF_EBP(%esp)
3474 movl %ebx, %ecx
3475 addl $20, %ecx
3476 movl %ecx, REGOFF_ESP(%esp)
3477 movl 8(%ebx), %ecx
3478 movl %ecx, REGOFF_EBX(%esp)
3479 movl 0(%ebx), %ecx
3480 movl %ecx, REGOFF_EDX(%esp)
3481 movl 4(%ebx), %ecx
3482 movl %ecx, REGOFF_ECX(%esp)
3483 movl 12(%ebx), %ecx
3484 movl %ecx, REGOFF_EAX(%esp)
3485 movl $0, REGOFF_TRAPNO(%esp)
3486 movl $0, REGOFF_ERR(%esp)
3487 lea vpanic, %ecx
3488 movl %ecx, REGOFF_EIP(%esp)
3489 #if !defined(__GNUC_AS__)
3490 movw %cs, %edx
3491 #else /* __GNUC_AS__ */
3492 mov %cs, %edx
3493 #endif /* __GNUC_AS__ */
3494 movl %edx, REGOFF_CS(%esp)
3495 pushfl
3496 popl %ecx
3497 #if defined(__xpv)
3499 * Synthesize the PS_IE bit from the event mask bit
3501 CURTHREAD(%edx)
3502 KPREEMPT_DISABLE(%edx)
3503 EVENT_MASK_TO_IE(%edx, %ecx)
3504 CURTHREAD(%edx)
3505 KPREEMPT_ENABLE_NOKP(%edx)
3506 #endif
3507 movl %ecx, REGOFF_EFL(%esp)
3508 movl $0, REGOFF_UESP(%esp)
3509 #if !defined(__GNUC_AS__)
3510 movw %ss, %edx
3511 #else /* __GNUC_AS__ */
3512 mov %ss, %edx
3513 #endif /* __GNUC_AS__ */
3514 movl %edx, REGOFF_SS(%esp)
3516 movl %esp, %ecx / %ecx = &regs
3517 pushl %eax / push on_panic_stack
3518 pushl %ecx / push &regs
3519 movl 12(%ebp), %ecx / %ecx = alist
3520 pushl %ecx / push alist
3521 movl 8(%ebp), %ecx / %ecx = format
3522 pushl %ecx / push format
3523 call panicsys / panicsys();
3524 addl $16, %esp / pop arguments
3526 addl $REGSIZE, %esp
3527 popl %edx
3528 popl %ecx
3529 popl %ebx
3530 popl %eax
3531 leave
3533 SET_SIZE(vpanic)
3535 ENTRY_NP(dtrace_vpanic) / Initial stack layout:
3537 pushl %ebp / | %eip | 20
3538 movl %esp, %ebp / | %ebp | 16
3539 pushl %eax / | %eax | 12
3540 pushl %ebx / | %ebx | 8
3541 pushl %ecx / | %ecx | 4
3542 pushl %edx / | %edx | 0
3544 movl %esp, %ebx / %ebx = current stack pointer
3546 lea panic_quiesce, %eax / %eax = &panic_quiesce
3547 pushl %eax / push &panic_quiesce
3548 call dtrace_panic_trigger / %eax = dtrace_panic_trigger()
3549 addl $4, %esp / reset stack pointer
3550 jmp vpanic_common / jump back to common code
3552 SET_SIZE(dtrace_vpanic)
3554 #endif /* __i386 */
3555 #endif /* __lint */
3557 #if defined(__lint)
3559 void
3560 hres_tick(void)
3563 int64_t timedelta;
3564 hrtime_t hres_last_tick;
3565 volatile timestruc_t hrestime;
3566 int64_t hrestime_adj;
3567 volatile int hres_lock;
3568 hrtime_t hrtime_base;
3570 #else /* __lint */
3572 DGDEF3(hrestime, _MUL(2, CLONGSIZE), 8)
3573 .NWORD 0, 0
3575 DGDEF3(hrestime_adj, 8, 8)
3576 .long 0, 0
3578 DGDEF3(hres_last_tick, 8, 8)
3579 .long 0, 0
3581 DGDEF3(timedelta, 8, 8)
3582 .long 0, 0
3584 DGDEF3(hres_lock, 4, 8)
3585 .long 0
3588 * initialized to a non zero value to make pc_gethrtime()
3589 * work correctly even before clock is initialized
3591 DGDEF3(hrtime_base, 8, 8)
3592 .long _MUL(NSEC_PER_CLOCK_TICK, 6), 0
3594 DGDEF3(adj_shift, 4, 4)
3595 .long ADJ_SHIFT
3597 #if defined(__amd64)
3599 ENTRY_NP(hres_tick)
3600 pushq %rbp
3601 movq %rsp, %rbp
3604 * We need to call *gethrtimef before picking up CLOCK_LOCK (obviously,
3605 * hres_last_tick can only be modified while holding CLOCK_LOCK).
3606 * At worst, performing this now instead of under CLOCK_LOCK may
3607 * introduce some jitter in pc_gethrestime().
3609 call *gethrtimef(%rip)
3610 movq %rax, %r8
3612 leaq hres_lock(%rip), %rax
3613 movb $-1, %dl
3614 .CL1:
3615 xchgb %dl, (%rax)
3616 testb %dl, %dl
3617 jz .CL3 /* got it */
3618 .CL2:
3619 cmpb $0, (%rax) /* possible to get lock? */
3620 pause
3621 jne .CL2
3622 jmp .CL1 /* yes, try again */
3623 .CL3:
3625 * compute the interval since last time hres_tick was called
3626 * and adjust hrtime_base and hrestime accordingly
3627 * hrtime_base is an 8 byte value (in nsec), hrestime is
3628 * a timestruc_t (sec, nsec)
3630 leaq hres_last_tick(%rip), %rax
3631 movq %r8, %r11
3632 subq (%rax), %r8
3633 addq %r8, hrtime_base(%rip) /* add interval to hrtime_base */
3634 addq %r8, hrestime+8(%rip) /* add interval to hrestime.tv_nsec */
3636 * Now that we have CLOCK_LOCK, we can update hres_last_tick
3638 movq %r11, (%rax)
3640 call __adj_hrestime
3643 * release the hres_lock
3645 incl hres_lock(%rip)
3646 leave
3648 SET_SIZE(hres_tick)
3650 #elif defined(__i386)
3652 ENTRY_NP(hres_tick)
3653 pushl %ebp
3654 movl %esp, %ebp
3655 pushl %esi
3656 pushl %ebx
3659 * We need to call *gethrtimef before picking up CLOCK_LOCK (obviously,
3660 * hres_last_tick can only be modified while holding CLOCK_LOCK).
3661 * At worst, performing this now instead of under CLOCK_LOCK may
3662 * introduce some jitter in pc_gethrestime().
3664 call *gethrtimef
3665 movl %eax, %ebx
3666 movl %edx, %esi
3668 movl $hres_lock, %eax
3669 movl $-1, %edx
3670 .CL1:
3671 xchgb %dl, (%eax)
3672 testb %dl, %dl
3673 jz .CL3 / got it
3674 .CL2:
3675 cmpb $0, (%eax) / possible to get lock?
3676 pause
3677 jne .CL2
3678 jmp .CL1 / yes, try again
3679 .CL3:
3681 * compute the interval since last time hres_tick was called
3682 * and adjust hrtime_base and hrestime accordingly
3683 * hrtime_base is an 8 byte value (in nsec), hrestime is
3684 * timestruc_t (sec, nsec)
3687 lea hres_last_tick, %eax
3689 movl %ebx, %edx
3690 movl %esi, %ecx
3692 subl (%eax), %edx
3693 sbbl 4(%eax), %ecx
3695 addl %edx, hrtime_base / add interval to hrtime_base
3696 adcl %ecx, hrtime_base+4
3698 addl %edx, hrestime+4 / add interval to hrestime.tv_nsec
3701 / Now that we have CLOCK_LOCK, we can update hres_last_tick.
3703 movl %ebx, (%eax)
3704 movl %esi, 4(%eax)
3706 / get hrestime at this moment. used as base for pc_gethrestime
3708 / Apply adjustment, if any
3710 / #define HRES_ADJ (NSEC_PER_CLOCK_TICK >> ADJ_SHIFT)
3711 / (max_hres_adj)
3713 / void
3714 / adj_hrestime()
3716 / long long adj;
3718 / if (hrestime_adj == 0)
3719 / adj = 0;
3720 / else if (hrestime_adj > 0) {
3721 / if (hrestime_adj < HRES_ADJ)
3722 / adj = hrestime_adj;
3723 / else
3724 / adj = HRES_ADJ;
3726 / else {
3727 / if (hrestime_adj < -(HRES_ADJ))
3728 / adj = -(HRES_ADJ);
3729 / else
3730 / adj = hrestime_adj;
3733 / timedelta -= adj;
3734 / hrestime_adj = timedelta;
3735 / hrestime.tv_nsec += adj;
3737 / while (hrestime.tv_nsec >= NANOSEC) {
3738 / one_sec++;
3739 / hrestime.tv_sec++;
3740 / hrestime.tv_nsec -= NANOSEC;
3743 __adj_hrestime:
3744 movl hrestime_adj, %esi / if (hrestime_adj == 0)
3745 movl hrestime_adj+4, %edx
3746 andl %esi, %esi
3747 jne .CL4 / no
3748 andl %edx, %edx
3749 jne .CL4 / no
3750 subl %ecx, %ecx / yes, adj = 0;
3751 subl %edx, %edx
3752 jmp .CL5
3753 .CL4:
3754 subl %ecx, %ecx
3755 subl %eax, %eax
3756 subl %esi, %ecx
3757 sbbl %edx, %eax
3758 andl %eax, %eax / if (hrestime_adj > 0)
3759 jge .CL6
3761 / In the following comments, HRES_ADJ is used, while in the code
3762 / max_hres_adj is used.
3764 / The test for "hrestime_adj < HRES_ADJ" is complicated because
3765 / hrestime_adj is 64-bits, while HRES_ADJ is 32-bits. We rely
3766 / on the logical equivalence of:
3768 / !(hrestime_adj < HRES_ADJ)
3770 / and the two step sequence:
3772 / (HRES_ADJ - lsw(hrestime_adj)) generates a Borrow/Carry
3774 / which computes whether or not the least significant 32-bits
3775 / of hrestime_adj is greater than HRES_ADJ, followed by:
3777 / Previous Borrow/Carry + -1 + msw(hrestime_adj) generates a Carry
3779 / which generates a carry whenever step 1 is true or the most
3780 / significant long of the longlong hrestime_adj is non-zero.
3782 movl max_hres_adj, %ecx / hrestime_adj is positive
3783 subl %esi, %ecx
3784 movl %edx, %eax
3785 adcl $-1, %eax
3786 jnc .CL7
3787 movl max_hres_adj, %ecx / adj = HRES_ADJ;
3788 subl %edx, %edx
3789 jmp .CL5
3791 / The following computation is similar to the one above.
3793 / The test for "hrestime_adj < -(HRES_ADJ)" is complicated because
3794 / hrestime_adj is 64-bits, while HRES_ADJ is 32-bits. We rely
3795 / on the logical equivalence of:
3797 / (hrestime_adj > -HRES_ADJ)
3799 / and the two step sequence:
3801 / (HRES_ADJ + lsw(hrestime_adj)) generates a Carry
3803 / which means the least significant 32-bits of hrestime_adj is
3804 / greater than -HRES_ADJ, followed by:
3806 / Previous Carry + 0 + msw(hrestime_adj) generates a Carry
3808 / which generates a carry only when step 1 is true and the most
3809 / significant long of the longlong hrestime_adj is -1.
3811 .CL6: / hrestime_adj is negative
3812 movl %esi, %ecx
3813 addl max_hres_adj, %ecx
3814 movl %edx, %eax
3815 adcl $0, %eax
3816 jc .CL7
3817 xor %ecx, %ecx
3818 subl max_hres_adj, %ecx / adj = -(HRES_ADJ);
3819 movl $-1, %edx
3820 jmp .CL5
3821 .CL7:
3822 movl %esi, %ecx / adj = hrestime_adj;
3823 .CL5:
3824 movl timedelta, %esi
3825 subl %ecx, %esi
3826 movl timedelta+4, %eax
3827 sbbl %edx, %eax
3828 movl %esi, timedelta
3829 movl %eax, timedelta+4 / timedelta -= adj;
3830 movl %esi, hrestime_adj
3831 movl %eax, hrestime_adj+4 / hrestime_adj = timedelta;
3832 addl hrestime+4, %ecx
3834 movl %ecx, %eax / eax = tv_nsec
3836 cmpl $NANOSEC, %eax / if ((unsigned long)tv_nsec >= NANOSEC)
3837 jb .CL8 / no
3838 incl one_sec / yes, one_sec++;
3839 incl hrestime / hrestime.tv_sec++;
3840 addl $-NANOSEC, %eax / tv_nsec -= NANOSEC
3841 jmp 1b / check for more seconds
3843 .CL8:
3844 movl %eax, hrestime+4 / store final into hrestime.tv_nsec
3845 incl hres_lock / release the hres_lock
3847 popl %ebx
3848 popl %esi
3849 leave
3851 SET_SIZE(hres_tick)
3853 #endif /* __i386 */
3854 #endif /* __lint */
3857 * void prefetch_smap_w(void *)
3859 * Prefetch ahead within a linear list of smap structures.
3860 * Not implemented for ia32. Stub for compatibility.
3863 #if defined(__lint)
3865 /*ARGSUSED*/
3866 void prefetch_smap_w(void *smp)
3869 #else /* __lint */
3871 ENTRY(prefetch_smap_w)
3872 rep; ret /* use 2 byte return instruction when branch target */
3873 /* AMD Software Optimization Guide - Section 6.2 */
3874 SET_SIZE(prefetch_smap_w)
3876 #endif /* __lint */
3879 * prefetch_page_r(page_t *)
3880 * issue prefetch instructions for a page_t
3882 #if defined(__lint)
3884 /*ARGSUSED*/
3885 void
3886 prefetch_page_r(void *pp)
3889 #else /* __lint */
3891 ENTRY(prefetch_page_r)
3892 rep; ret /* use 2 byte return instruction when branch target */
3893 /* AMD Software Optimization Guide - Section 6.2 */
3894 SET_SIZE(prefetch_page_r)
3896 #endif /* __lint */
3898 #if defined(__lint)
3900 /*ARGSUSED*/
3902 bcmp(const void *s1, const void *s2, size_t count)
3903 { return (0); }
3905 #else /* __lint */
3907 #if defined(__amd64)
3909 ENTRY(bcmp)
3910 pushq %rbp
3911 movq %rsp, %rbp
3912 #ifdef DEBUG
3913 testq %rdx,%rdx
3914 je 1f
3915 movq postbootkernelbase(%rip), %r11
3916 cmpq %r11, %rdi
3917 jb 0f
3918 cmpq %r11, %rsi
3919 jnb 1f
3920 0: leaq .bcmp_panic_msg(%rip), %rdi
3921 xorl %eax, %eax
3922 call panic
3924 #endif /* DEBUG */
3925 call memcmp
3926 testl %eax, %eax
3927 setne %dl
3928 leave
3929 movzbl %dl, %eax
3931 SET_SIZE(bcmp)
3933 #elif defined(__i386)
3935 #define ARG_S1 8
3936 #define ARG_S2 12
3937 #define ARG_LENGTH 16
3939 ENTRY(bcmp)
3940 pushl %ebp
3941 movl %esp, %ebp / create new stack frame
3942 #ifdef DEBUG
3943 cmpl $0, ARG_LENGTH(%ebp)
3944 je 1f
3945 movl postbootkernelbase, %eax
3946 cmpl %eax, ARG_S1(%ebp)
3947 jb 0f
3948 cmpl %eax, ARG_S2(%ebp)
3949 jnb 1f
3950 0: pushl $.bcmp_panic_msg
3951 call panic
3953 #endif /* DEBUG */
3955 pushl %edi / save register variable
3956 movl ARG_S1(%ebp), %eax / %eax = address of string 1
3957 movl ARG_S2(%ebp), %ecx / %ecx = address of string 2
3958 cmpl %eax, %ecx / if the same string
3959 je .equal / goto .equal
3960 movl ARG_LENGTH(%ebp), %edi / %edi = length in bytes
3961 cmpl $4, %edi / if %edi < 4
3962 jb .byte_check / goto .byte_check
3963 .align 4
3964 .word_loop:
3965 movl (%ecx), %edx / move 1 word from (%ecx) to %edx
3966 leal -4(%edi), %edi / %edi -= 4
3967 cmpl (%eax), %edx / compare 1 word from (%eax) with %edx
3968 jne .word_not_equal / if not equal, goto .word_not_equal
3969 leal 4(%ecx), %ecx / %ecx += 4 (next word)
3970 leal 4(%eax), %eax / %eax += 4 (next word)
3971 cmpl $4, %edi / if %edi >= 4
3972 jae .word_loop / goto .word_loop
3973 .byte_check:
3974 cmpl $0, %edi / if %edi == 0
3975 je .equal / goto .equal
3976 jmp .byte_loop / goto .byte_loop (checks in bytes)
3977 .word_not_equal:
3978 leal 4(%edi), %edi / %edi += 4 (post-decremented)
3979 .align 4
3980 .byte_loop:
3981 movb (%ecx), %dl / move 1 byte from (%ecx) to %dl
3982 cmpb %dl, (%eax) / compare %dl with 1 byte from (%eax)
3983 jne .not_equal / if not equal, goto .not_equal
3984 incl %ecx / %ecx++ (next byte)
3985 incl %eax / %eax++ (next byte)
3986 decl %edi / %edi--
3987 jnz .byte_loop / if not zero, goto .byte_loop
3988 .equal:
3989 xorl %eax, %eax / %eax = 0
3990 popl %edi / restore register variable
3991 leave / restore old stack frame
3992 ret / return (NULL)
3993 .align 4
3994 .not_equal:
3995 movl $1, %eax / return 1
3996 popl %edi / restore register variable
3997 leave / restore old stack frame
3998 ret / return (NULL)
3999 SET_SIZE(bcmp)
4001 #endif /* __i386 */
4003 #ifdef DEBUG
4004 .text
4005 .bcmp_panic_msg:
4006 .string "bcmp: arguments below kernelbase"
4007 #endif /* DEBUG */
4009 #endif /* __lint */
4011 #if defined(__lint)
4013 uint_t
4014 bsrw_insn(uint16_t mask)
4016 uint_t index = sizeof (mask) * NBBY - 1;
4018 while ((mask & (1 << index)) == 0)
4019 index--;
4020 return (index);
4023 #else /* __lint */
4025 #if defined(__amd64)
4027 ENTRY_NP(bsrw_insn)
4028 xorl %eax, %eax
4029 bsrw %di, %ax
4031 SET_SIZE(bsrw_insn)
4033 #elif defined(__i386)
4035 ENTRY_NP(bsrw_insn)
4036 movw 4(%esp), %cx
4037 xorl %eax, %eax
4038 bsrw %cx, %ax
4040 SET_SIZE(bsrw_insn)
4042 #endif /* __i386 */
4043 #endif /* __lint */
4045 #if defined(__lint)
4047 uint_t
4048 atomic_btr32(uint32_t *pending, uint_t pil)
4050 return (*pending &= ~(1 << pil));
4053 #else /* __lint */
4055 #if defined(__i386)
4057 ENTRY_NP(atomic_btr32)
4058 movl 4(%esp), %ecx
4059 movl 8(%esp), %edx
4060 xorl %eax, %eax
4061 lock
4062 btrl %edx, (%ecx)
4063 setc %al
4065 SET_SIZE(atomic_btr32)
4067 #endif /* __i386 */
4068 #endif /* __lint */
4070 #if defined(__lint)
4072 /*ARGSUSED*/
4073 void
4074 switch_sp_and_call(void *newsp, void (*func)(uint_t, uint_t), uint_t arg1,
4075 uint_t arg2)
4078 #else /* __lint */
4080 #if defined(__amd64)
4082 ENTRY_NP(switch_sp_and_call)
4083 pushq %rbp
4084 movq %rsp, %rbp /* set up stack frame */
4085 movq %rdi, %rsp /* switch stack pointer */
4086 movq %rdx, %rdi /* pass func arg 1 */
4087 movq %rsi, %r11 /* save function to call */
4088 movq %rcx, %rsi /* pass func arg 2 */
4089 call *%r11 /* call function */
4090 leave /* restore stack */
4092 SET_SIZE(switch_sp_and_call)
4094 #elif defined(__i386)
4096 ENTRY_NP(switch_sp_and_call)
4097 pushl %ebp
4098 mov %esp, %ebp /* set up stack frame */
4099 movl 8(%ebp), %esp /* switch stack pointer */
4100 pushl 20(%ebp) /* push func arg 2 */
4101 pushl 16(%ebp) /* push func arg 1 */
4102 call *12(%ebp) /* call function */
4103 addl $8, %esp /* pop arguments */
4104 leave /* restore stack */
4106 SET_SIZE(switch_sp_and_call)
4108 #endif /* __i386 */
4109 #endif /* __lint */
4111 #if defined(__lint)
4113 void
4114 kmdb_enter(void)
4117 #else /* __lint */
4119 #if defined(__amd64)
4121 ENTRY_NP(kmdb_enter)
4122 pushq %rbp
4123 movq %rsp, %rbp
4126 * Save flags, do a 'cli' then return the saved flags
4128 call intr_clear
4130 int $T_DBGENTR
4133 * Restore the saved flags
4135 movq %rax, %rdi
4136 call intr_restore
4138 leave
4139 ret
4140 SET_SIZE(kmdb_enter)
4142 #elif defined(__i386)
4144 ENTRY_NP(kmdb_enter)
4145 pushl %ebp
4146 movl %esp, %ebp
4149 * Save flags, do a 'cli' then return the saved flags
4151 call intr_clear
4153 int $T_DBGENTR
4156 * Restore the saved flags
4158 pushl %eax
4159 call intr_restore
4160 addl $4, %esp
4162 leave
4163 ret
4164 SET_SIZE(kmdb_enter)
4166 #endif /* __i386 */
4167 #endif /* __lint */
4169 #if defined(__lint)
4171 void
4172 return_instr(void)
4175 #else /* __lint */
4177 ENTRY_NP(return_instr)
4178 rep; ret /* use 2 byte instruction when branch target */
4179 /* AMD Software Optimization Guide - Section 6.2 */
4180 SET_SIZE(return_instr)
4182 #endif /* __lint */
4184 #if defined(__lint)
4186 ulong_t
4187 getflags(void)
4189 return (0);
4192 #else /* __lint */
4194 #if defined(__amd64)
4196 ENTRY(getflags)
4197 pushfq
4198 popq %rax
4199 #if defined(__xpv)
4200 CURTHREAD(%rdi)
4201 KPREEMPT_DISABLE(%rdi)
4203 * Synthesize the PS_IE bit from the event mask bit
4205 CURVCPU(%r11)
4206 andq $_BITNOT(PS_IE), %rax
4207 XEN_TEST_UPCALL_MASK(%r11)
4208 jnz 1f
4209 orq $PS_IE, %rax
4211 KPREEMPT_ENABLE_NOKP(%rdi)
4212 #endif
4214 SET_SIZE(getflags)
4216 #elif defined(__i386)
4218 ENTRY(getflags)
4219 pushfl
4220 popl %eax
4221 #if defined(__xpv)
4222 CURTHREAD(%ecx)
4223 KPREEMPT_DISABLE(%ecx)
4225 * Synthesize the PS_IE bit from the event mask bit
4227 CURVCPU(%edx)
4228 andl $_BITNOT(PS_IE), %eax
4229 XEN_TEST_UPCALL_MASK(%edx)
4230 jnz 1f
4231 orl $PS_IE, %eax
4233 KPREEMPT_ENABLE_NOKP(%ecx)
4234 #endif
4236 SET_SIZE(getflags)
4238 #endif /* __i386 */
4240 #endif /* __lint */
4242 #if defined(__lint)
4244 ftrace_icookie_t
4245 ftrace_interrupt_disable(void)
4246 { return (0); }
4248 #else /* __lint */
4250 #if defined(__amd64)
4252 ENTRY(ftrace_interrupt_disable)
4253 pushfq
4254 popq %rax
4255 CLI(%rdx)
4257 SET_SIZE(ftrace_interrupt_disable)
4259 #elif defined(__i386)
4261 ENTRY(ftrace_interrupt_disable)
4262 pushfl
4263 popl %eax
4264 CLI(%edx)
4266 SET_SIZE(ftrace_interrupt_disable)
4268 #endif /* __i386 */
4269 #endif /* __lint */
4271 #if defined(__lint)
4273 /*ARGSUSED*/
4274 void
4275 ftrace_interrupt_enable(ftrace_icookie_t cookie)
4278 #else /* __lint */
4280 #if defined(__amd64)
4282 ENTRY(ftrace_interrupt_enable)
4283 pushq %rdi
4284 popfq
4286 SET_SIZE(ftrace_interrupt_enable)
4288 #elif defined(__i386)
4290 ENTRY(ftrace_interrupt_enable)
4291 movl 4(%esp), %eax
4292 pushl %eax
4293 popfl
4295 SET_SIZE(ftrace_interrupt_enable)
4297 #endif /* __i386 */
4298 #endif /* __lint */
4300 #if defined (__lint)
4302 /*ARGSUSED*/
4303 void
4304 clflush_insn(caddr_t addr)
4307 #else /* __lint */
4309 #if defined (__amd64)
4310 ENTRY(clflush_insn)
4311 clflush (%rdi)
4313 SET_SIZE(clflush_insn)
4314 #elif defined (__i386)
4315 ENTRY(clflush_insn)
4316 movl 4(%esp), %eax
4317 clflush (%eax)
4319 SET_SIZE(clflush_insn)
4321 #endif /* __i386 */
4322 #endif /* __lint */
4324 #if defined (__lint)
4325 /*ARGSUSED*/
4326 void
4327 mfence_insn(void)
4330 #else /* __lint */
4332 #if defined (__amd64)
4333 ENTRY(mfence_insn)
4334 mfence
4336 SET_SIZE(mfence_insn)
4337 #elif defined (__i386)
4338 ENTRY(mfence_insn)
4339 mfence
4341 SET_SIZE(mfence_insn)
4343 #endif /* __i386 */
4344 #endif /* __lint */
4347 * VMware implements an I/O port that programs can query to detect if software
4348 * is running in a VMware hypervisor. This hypervisor port behaves differently
4349 * depending on magic values in certain registers and modifies some registers
4350 * as a side effect.
4352 * References: http://kb.vmware.com/kb/1009458
4355 #if defined(__lint)
4357 /* ARGSUSED */
4358 void
4359 vmware_port(int cmd, uint32_t *regs) { return; }
4361 #else
4363 #if defined(__amd64)
4365 ENTRY(vmware_port)
4366 pushq %rbx
4367 movl $VMWARE_HVMAGIC, %eax
4368 movl $0xffffffff, %ebx
4369 movl %edi, %ecx
4370 movl $VMWARE_HVPORT, %edx
4371 inl (%dx)
4372 movl %eax, (%rsi)
4373 movl %ebx, 4(%rsi)
4374 movl %ecx, 8(%rsi)
4375 movl %edx, 12(%rsi)
4376 popq %rbx
4378 SET_SIZE(vmware_port)
4380 #elif defined(__i386)
4382 ENTRY(vmware_port)
4383 pushl %ebx
4384 pushl %esi
4385 movl $VMWARE_HVMAGIC, %eax
4386 movl $0xffffffff, %ebx
4387 movl 12(%esp), %ecx
4388 movl $VMWARE_HVPORT, %edx
4389 inl (%dx)
4390 movl 16(%esp), %esi
4391 movl %eax, (%esi)
4392 movl %ebx, 4(%esi)
4393 movl %ecx, 8(%esi)
4394 movl %edx, 12(%esi)
4395 popl %esi
4396 popl %ebx
4398 SET_SIZE(vmware_port)
4400 #endif /* __i386 */
4401 #endif /* __lint */