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