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