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