]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
amd64: implement memcmp in assembly
[FreeBSD/FreeBSD.git] / sys / amd64 / amd64 / support.S
1 /*-
2  * Copyright (c) 2003 Peter Wemm.
3  * Copyright (c) 1993 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32
33 #include "opt_ddb.h"
34
35 #include <machine/asmacros.h>
36 #include <machine/specialreg.h>
37 #include <machine/pmap.h>
38
39 #include "assym.inc"
40
41         .text
42
43 /* Address: %rdi */
44 ENTRY(pagezero_std)
45         PUSH_FRAME_POINTER
46         movq    $PAGE_SIZE/8,%rcx
47         xorl    %eax,%eax
48         rep
49         stosq
50         POP_FRAME_POINTER
51         ret
52 END(pagezero_std)
53
54 ENTRY(pagezero_erms)
55         PUSH_FRAME_POINTER
56         movq    $PAGE_SIZE,%rcx
57         xorl    %eax,%eax
58         rep
59         stosb
60         POP_FRAME_POINTER
61         ret
62 END(pagezero_erms)
63
64 /*
65  * pagecopy(%rdi=from, %rsi=to)
66  */
67 ENTRY(pagecopy)
68         PUSH_FRAME_POINTER
69         movq    $PAGE_SIZE/8,%rcx
70         movq    %rdi,%r9
71         movq    %rsi,%rdi
72         movq    %r9,%rsi
73         rep
74         movsq
75         POP_FRAME_POINTER
76         ret
77 END(pagecopy)
78
79 /* Address: %rdi */
80 ENTRY(sse2_pagezero)
81         PUSH_FRAME_POINTER
82         movq    $-PAGE_SIZE,%rdx
83         subq    %rdx,%rdi
84         xorl    %eax,%eax
85         jmp     1f
86         /*
87          * The loop takes 29 bytes.  Ensure that it doesn't cross a 32-byte
88          * cache line.
89          */
90         .p2align 5,0x90
91 1:
92         movnti  %rax,(%rdi,%rdx)
93         movnti  %rax,8(%rdi,%rdx)
94         movnti  %rax,16(%rdi,%rdx)
95         movnti  %rax,24(%rdi,%rdx)
96         addq    $32,%rdx
97         jne     1b
98         sfence
99         POP_FRAME_POINTER
100         ret
101 END(sse2_pagezero)
102
103 /*
104  * memcmpy(b1, b2, len)
105  *         rdi,rsi,len
106  */
107 ENTRY(memcmp)
108         PUSH_FRAME_POINTER
109         cmpq    $16,%rdx
110         jae     5f
111 1:
112         testq   %rdx,%rdx
113         je      3f
114         xorl    %ecx,%ecx
115 2:
116         movzbl  (%rdi,%rcx,1),%eax
117         movzbl  (%rsi,%rcx,1),%r8d
118         cmpb    %r8b,%al
119         jne     4f
120         addq    $1,%rcx
121         cmpq    %rcx,%rdx
122         jz      3f
123         movzbl  (%rdi,%rcx,1),%eax
124         movzbl  (%rsi,%rcx,1),%r8d
125         cmpb    %r8b,%al
126         jne     4f
127         addq    $1,%rcx
128         cmpq    %rcx,%rdx
129         jz      3f
130         movzbl  (%rdi,%rcx,1),%eax
131         movzbl  (%rsi,%rcx,1),%r8d
132         cmpb    %r8b,%al
133         jne     4f
134         addq    $1,%rcx
135         cmpq    %rcx,%rdx
136         jz      3f
137         movzbl  (%rdi,%rcx,1),%eax
138         movzbl  (%rsi,%rcx,1),%r8d
139         cmpb    %r8b,%al
140         jne     4f
141         addq    $1,%rcx
142         cmpq    %rcx,%rdx
143         jne     2b
144 3:
145         xorl    %eax,%eax
146         POP_FRAME_POINTER
147         ret
148 4:
149         subl    %r8d,%eax
150         POP_FRAME_POINTER
151         ret
152 5:
153         cmpq    $32,%rdx
154         jae     7f
155 6:
156         /*
157          * 8 bytes
158          */
159         movq    (%rdi),%r8
160         movq    (%rsi),%r9
161         cmpq    %r8,%r9
162         jne     1b
163         leaq    8(%rdi),%rdi
164         leaq    8(%rsi),%rsi
165         subq    $8,%rdx
166         cmpq    $8,%rdx
167         jae     6b
168         jl      1b
169         jmp     3b
170 7:
171         /*
172          * 32 bytes
173          */
174         movq    (%rsi),%r8
175         movq    8(%rsi),%r9
176         subq    (%rdi),%r8
177         subq    8(%rdi),%r9
178         or      %r8,%r9
179         jnz     1b
180
181         movq    16(%rsi),%r8
182         movq    24(%rsi),%r9
183         subq    16(%rdi),%r8
184         subq    24(%rdi),%r9
185         or      %r8,%r9
186         jnz     1b
187
188         leaq    32(%rdi),%rdi
189         leaq    32(%rsi),%rsi
190         subq    $32,%rdx
191         cmpq    $32,%rdx
192         jae     7b
193         jnz     1b
194         jmp     3b
195 END(memcmp)
196
197 /*
198  * memmove(dst, src, cnt)
199  *         rdi, rsi, rdx
200  * Adapted from bcopy written by:
201  *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
202  */
203 ENTRY(memmove_std)
204         PUSH_FRAME_POINTER
205         movq    %rdi,%rax
206         movq    %rdx,%rcx
207
208         movq    %rdi,%r8
209         subq    %rsi,%r8
210         cmpq    %rcx,%r8                        /* overlapping && src < dst? */
211         jb      2f
212
213         cmpq    $15,%rcx
214         jbe     1f
215         shrq    $3,%rcx                         /* copy by 64-bit words */
216         rep
217         movsq
218         movq    %rdx,%rcx
219         andq    $7,%rcx                         /* any bytes left? */
220         jne     1f
221         POP_FRAME_POINTER
222         ret
223         ALIGN_TEXT
224 1:
225         rep
226         movsb
227         POP_FRAME_POINTER
228         ret
229
230         /* ALIGN_TEXT */
231 2:
232         addq    %rcx,%rdi                       /* copy backwards */
233         addq    %rcx,%rsi
234         decq    %rdi
235         decq    %rsi
236         std
237         andq    $7,%rcx                         /* any fractional bytes? */
238         je      3f
239         rep
240         movsb
241 3:
242         movq    %rdx,%rcx                       /* copy remainder by 32-bit words */
243         shrq    $3,%rcx
244         subq    $7,%rsi
245         subq    $7,%rdi
246         rep
247         movsq
248         cld
249         POP_FRAME_POINTER
250         ret
251 END(memmove_std)
252
253 ENTRY(memmove_erms)
254         PUSH_FRAME_POINTER
255         movq    %rdi,%rax
256         movq    %rdx,%rcx
257
258         movq    %rdi,%r8
259         subq    %rsi,%r8
260         cmpq    %rcx,%r8                        /* overlapping && src < dst? */
261         jb      1f
262
263         rep
264         movsb
265         POP_FRAME_POINTER
266         ret
267
268 1:
269         addq    %rcx,%rdi                       /* copy backwards */
270         addq    %rcx,%rsi
271         decq    %rdi
272         decq    %rsi
273         std
274         rep
275         movsb
276         cld
277         POP_FRAME_POINTER
278         ret
279 END(memmove_erms)
280
281 /*
282  * memcpy(dst, src, len)
283  *        rdi, rsi, rdx
284  *
285  * Note: memcpy does not support overlapping copies
286  */
287 ENTRY(memcpy_std)
288         PUSH_FRAME_POINTER
289         movq    %rdi,%rax
290         movq    %rdx,%rcx
291         cmpq    $15,%rcx
292         jbe     1f
293         shrq    $3,%rcx                         /* copy by 64-bit words */
294         rep
295         movsq
296         movq    %rdx,%rcx
297         andq    $7,%rcx                         /* any bytes left? */
298         jne     1f
299         POP_FRAME_POINTER
300         ret
301         ALIGN_TEXT
302 1:
303         rep
304         movsb
305         POP_FRAME_POINTER
306         ret
307 END(memcpy_std)
308
309 ENTRY(memcpy_erms)
310         PUSH_FRAME_POINTER
311         movq    %rdi,%rax
312         movq    %rdx,%rcx
313         rep
314         movsb
315         POP_FRAME_POINTER
316         ret
317 END(memcpy_erms)
318
319 /*
320  * memset(dst, c,   len)
321  *        rdi, rsi, rdx
322  */
323 ENTRY(memset_std)
324         PUSH_FRAME_POINTER
325         movq    %rdi,%r9
326         movq    %rdx,%rcx
327         movzbq  %sil,%r8
328         movabs  $0x0101010101010101,%rax
329         imulq   %r8,%rax
330         cmpq    $15,%rcx
331         jbe     1f
332         shrq    $3,%rcx
333         rep
334         stosq
335         movq    %rdx,%rcx
336         andq    $7,%rcx
337         jne     1f
338         movq    %r9,%rax
339         POP_FRAME_POINTER
340         ret
341         ALIGN_TEXT
342 1:
343         rep
344         stosb
345         movq    %r9,%rax
346         POP_FRAME_POINTER
347         ret
348 END(memset_std)
349
350 ENTRY(memset_erms)
351         PUSH_FRAME_POINTER
352         movq    %rdi,%r9
353         movq    %rdx,%rcx
354         movb    %sil,%al
355         rep
356         stosb
357         movq    %r9,%rax
358         POP_FRAME_POINTER
359         ret
360 END(memset_erms)
361
362 /* fillw(pat, base, cnt) */
363 /*       %rdi,%rsi, %rdx */
364 ENTRY(fillw)
365         PUSH_FRAME_POINTER
366         movq    %rdi,%rax
367         movq    %rsi,%rdi
368         movq    %rdx,%rcx
369         rep
370         stosw
371         POP_FRAME_POINTER
372         ret
373 END(fillw)
374
375 /*****************************************************************************/
376 /* copyout and fubyte family                                                 */
377 /*****************************************************************************/
378 /*
379  * Access user memory from inside the kernel. These routines should be
380  * the only places that do this.
381  *
382  * These routines set curpcb->pcb_onfault for the time they execute. When a
383  * protection violation occurs inside the functions, the trap handler
384  * returns to *curpcb->pcb_onfault instead of the function.
385  */
386
387 .macro SMAP_DISABLE smap
388 .if     \smap
389         stac
390 .endif
391 .endm
392
393
394 .macro SMAP_ENABLE smap
395 .if     \smap
396         clac
397 .endif
398 .endm
399
400 /*
401  * copyout(from_kernel, to_user, len)
402  *         %rdi,        %rsi,    %rdx
403  */
404 .macro  COPYOUT smap erms
405         PUSH_FRAME_POINTER
406         movq    PCPU(CURPCB),%r9
407         /* Trap entry clears PSL.AC */
408         movq    $copy_fault,PCB_ONFAULT(%r9)
409         testq   %rdx,%rdx                       /* anything to do? */
410         jz      2f
411
412         /*
413          * Check explicitly for non-user addresses.  If 486 write protection
414          * is being used, this check is essential because we are in kernel
415          * mode so the h/w does not provide any protection against writing
416          * kernel addresses.
417          */
418
419         /*
420          * First, prevent address wrapping.
421          */
422         movq    %rsi,%rax
423         addq    %rdx,%rax
424         jc      copy_fault
425 /*
426  * XXX STOP USING VM_MAXUSER_ADDRESS.
427  * It is an end address, not a max, so every time it is used correctly it
428  * looks like there is an off by one error, and of course it caused an off
429  * by one error in several places.
430  */
431         movq    $VM_MAXUSER_ADDRESS,%rcx
432         cmpq    %rcx,%rax
433         ja      copy_fault
434
435         xchgq   %rdi,%rsi
436         /* bcopy(%rsi, %rdi, %rdx) */
437         movq    %rdx,%rcx
438
439         SMAP_DISABLE \smap
440 .if     \erms == 0
441         cmpq    $15,%rcx
442         jbe     1f
443         shrq    $3,%rcx
444         rep
445         movsq
446         movb    %dl,%cl
447         andb    $7,%cl
448         jne     1f
449         SMAP_ENABLE \smap
450         xorl    %eax,%eax
451         movq    %rax,PCB_ONFAULT(%r9)
452         POP_FRAME_POINTER
453         ret
454 .endif
455 1:
456         rep
457         movsb
458         SMAP_ENABLE \smap
459 2:
460         xorl    %eax,%eax
461         movq    %rax,PCB_ONFAULT(%r9)
462         POP_FRAME_POINTER
463         ret
464 .endm
465
466 ENTRY(copyout_nosmap_std)
467         COPYOUT smap=0 erms=0
468 END(copyout_nosmap_std)
469
470 ENTRY(copyout_smap_std)
471         COPYOUT smap=1 erms=0
472 END(copyout_smap_std)
473
474 ENTRY(copyout_nosmap_erms)
475         COPYOUT smap=0 erms=1
476 END(copyout_nosmap_erms)
477
478 ENTRY(copyout_smap_erms)
479         COPYOUT smap=1 erms=1
480 END(copyout_smap_erms)
481
482 /*
483  * copyin(from_user, to_kernel, len)
484  *        %rdi,      %rsi,      %rdx
485  */
486 .macro  COPYIN smap erms
487         PUSH_FRAME_POINTER
488         movq    PCPU(CURPCB),%r9
489         movq    $copy_fault,PCB_ONFAULT(%r9)
490         testq   %rdx,%rdx                       /* anything to do? */
491         jz      2f
492
493         /*
494          * make sure address is valid
495          */
496         movq    %rdi,%rax
497         addq    %rdx,%rax
498         jc      copy_fault
499         movq    $VM_MAXUSER_ADDRESS,%rcx
500         cmpq    %rcx,%rax
501         ja      copy_fault
502
503         xchgq   %rdi,%rsi
504         movq    %rdx,%rcx
505         movb    %cl,%al
506
507         SMAP_DISABLE \smap
508 .if \erms == 0
509         cmpq    $15,%rcx
510         jbe     1f
511         shrq    $3,%rcx                         /* copy longword-wise */
512         rep
513         movsq
514         movb    %al,%cl
515         andb    $7,%cl                          /* copy remaining bytes */
516         jne     1f
517         SMAP_ENABLE \smap
518         xorl    %eax,%eax
519         movq    %rax,PCB_ONFAULT(%r9)
520         POP_FRAME_POINTER
521         ret
522 .endif
523 1:
524         rep
525         movsb
526
527         SMAP_ENABLE \smap
528 2:
529         xorl    %eax,%eax
530         movq    %rax,PCB_ONFAULT(%r9)
531         POP_FRAME_POINTER
532         ret
533 .endm
534
535 ENTRY(copyin_nosmap_std)
536         COPYIN smap=0 erms=0
537 END(copyin_nosmap_std)
538
539 ENTRY(copyin_smap_std)
540         COPYIN smap=1 erms=0
541 END(copyin_smap_std)
542
543 ENTRY(copyin_nosmap_erms)
544         COPYIN smap=0 erms=1
545 END(copyin_nosmap_erms)
546
547 ENTRY(copyin_smap_erms)
548         COPYIN smap=1 erms=1
549 END(copyin_smap_erms)
550
551         ALIGN_TEXT
552 copy_fault:
553         movq    PCPU(CURPCB),%rdx
554         movq    $0,PCB_ONFAULT(%rdx)
555         movl    $EFAULT,%eax
556         POP_FRAME_POINTER
557         ret
558
559 /*
560  * casueword32.  Compare and set user integer.  Returns -1 on fault,
561  *        0 if access was successful.  Old value is written to *oldp.
562  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
563  */
564 ENTRY(casueword32_nosmap)
565         PUSH_FRAME_POINTER
566         movq    PCPU(CURPCB),%r8
567         movq    $fusufault,PCB_ONFAULT(%r8)
568
569         movq    $VM_MAXUSER_ADDRESS-4,%rax
570         cmpq    %rax,%rdi                       /* verify address is valid */
571         ja      fusufault
572
573         movl    %esi,%eax                       /* old */
574 #ifdef SMP
575         lock
576 #endif
577         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
578
579         /*
580          * The old value is in %eax.  If the store succeeded it will be the
581          * value we expected (old) from before the store, otherwise it will
582          * be the current value.  Save %eax into %esi to prepare the return
583          * value.
584          */
585         movl    %eax,%esi
586         xorl    %eax,%eax
587         movq    %rax,PCB_ONFAULT(%r8)
588
589         /*
590          * Access the oldp after the pcb_onfault is cleared, to correctly
591          * catch corrupted pointer.
592          */
593         movl    %esi,(%rdx)                     /* oldp = %rdx */
594         POP_FRAME_POINTER
595         ret
596 END(casueword32_nosmap)
597
598 ENTRY(casueword32_smap)
599         PUSH_FRAME_POINTER
600         movq    PCPU(CURPCB),%r8
601         movq    $fusufault,PCB_ONFAULT(%r8)
602
603         movq    $VM_MAXUSER_ADDRESS-4,%rax
604         cmpq    %rax,%rdi                       /* verify address is valid */
605         ja      fusufault
606
607         movl    %esi,%eax                       /* old */
608         stac
609 #ifdef SMP
610         lock
611 #endif
612         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
613         clac
614
615         /*
616          * The old value is in %eax.  If the store succeeded it will be the
617          * value we expected (old) from before the store, otherwise it will
618          * be the current value.  Save %eax into %esi to prepare the return
619          * value.
620          */
621         movl    %eax,%esi
622         xorl    %eax,%eax
623         movq    %rax,PCB_ONFAULT(%r8)
624
625         /*
626          * Access the oldp after the pcb_onfault is cleared, to correctly
627          * catch corrupted pointer.
628          */
629         movl    %esi,(%rdx)                     /* oldp = %rdx */
630         POP_FRAME_POINTER
631         ret
632 END(casueword32_smap)
633
634 /*
635  * casueword.  Compare and set user long.  Returns -1 on fault,
636  *        0 if access was successful.  Old value is written to *oldp.
637  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
638  */
639 ENTRY(casueword_nosmap)
640         PUSH_FRAME_POINTER
641         movq    PCPU(CURPCB),%r8
642         movq    $fusufault,PCB_ONFAULT(%r8)
643
644         movq    $VM_MAXUSER_ADDRESS-4,%rax
645         cmpq    %rax,%rdi                       /* verify address is valid */
646         ja      fusufault
647
648         movq    %rsi,%rax                       /* old */
649 #ifdef SMP
650         lock
651 #endif
652         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
653
654         /*
655          * The old value is in %rax.  If the store succeeded it will be the
656          * value we expected (old) from before the store, otherwise it will
657          * be the current value.
658          */
659         movq    %rax,%rsi
660         xorl    %eax,%eax
661         movq    %rax,PCB_ONFAULT(%r8)
662         movq    %rsi,(%rdx)
663         POP_FRAME_POINTER
664         ret
665 END(casueword_nosmap)
666
667 ENTRY(casueword_smap)
668         PUSH_FRAME_POINTER
669         movq    PCPU(CURPCB),%r8
670         movq    $fusufault,PCB_ONFAULT(%r8)
671
672         movq    $VM_MAXUSER_ADDRESS-4,%rax
673         cmpq    %rax,%rdi                       /* verify address is valid */
674         ja      fusufault
675
676         movq    %rsi,%rax                       /* old */
677         stac
678 #ifdef SMP
679         lock
680 #endif
681         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
682         clac
683
684         /*
685          * The old value is in %rax.  If the store succeeded it will be the
686          * value we expected (old) from before the store, otherwise it will
687          * be the current value.
688          */
689         movq    %rax,%rsi
690         xorl    %eax,%eax
691         movq    %rax,PCB_ONFAULT(%r8)
692         movq    %rsi,(%rdx)
693         POP_FRAME_POINTER
694         ret
695 END(casueword_smap)
696
697 /*
698  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
699  * byte from user memory.
700  * addr = %rdi, valp = %rsi
701  */
702
703 ENTRY(fueword_nosmap)
704         PUSH_FRAME_POINTER
705         movq    PCPU(CURPCB),%rcx
706         movq    $fusufault,PCB_ONFAULT(%rcx)
707
708         movq    $VM_MAXUSER_ADDRESS-8,%rax
709         cmpq    %rax,%rdi                       /* verify address is valid */
710         ja      fusufault
711
712         xorl    %eax,%eax
713         movq    (%rdi),%r11
714         movq    %rax,PCB_ONFAULT(%rcx)
715         movq    %r11,(%rsi)
716         POP_FRAME_POINTER
717         ret
718 END(fueword_nosmap)
719
720 ENTRY(fueword_smap)
721         PUSH_FRAME_POINTER
722         movq    PCPU(CURPCB),%rcx
723         movq    $fusufault,PCB_ONFAULT(%rcx)
724
725         movq    $VM_MAXUSER_ADDRESS-8,%rax
726         cmpq    %rax,%rdi                       /* verify address is valid */
727         ja      fusufault
728
729         xorl    %eax,%eax
730         stac
731         movq    (%rdi),%r11
732         clac
733         movq    %rax,PCB_ONFAULT(%rcx)
734         movq    %r11,(%rsi)
735         POP_FRAME_POINTER
736         ret
737 END(fueword_smap)
738
739 ENTRY(fueword32_nosmap)
740         PUSH_FRAME_POINTER
741         movq    PCPU(CURPCB),%rcx
742         movq    $fusufault,PCB_ONFAULT(%rcx)
743
744         movq    $VM_MAXUSER_ADDRESS-4,%rax
745         cmpq    %rax,%rdi                       /* verify address is valid */
746         ja      fusufault
747
748         xorl    %eax,%eax
749         movl    (%rdi),%r11d
750         movq    %rax,PCB_ONFAULT(%rcx)
751         movl    %r11d,(%rsi)
752         POP_FRAME_POINTER
753         ret
754 END(fueword32_nosmap)
755
756 ENTRY(fueword32_smap)
757         PUSH_FRAME_POINTER
758         movq    PCPU(CURPCB),%rcx
759         movq    $fusufault,PCB_ONFAULT(%rcx)
760
761         movq    $VM_MAXUSER_ADDRESS-4,%rax
762         cmpq    %rax,%rdi                       /* verify address is valid */
763         ja      fusufault
764
765         xorl    %eax,%eax
766         stac
767         movl    (%rdi),%r11d
768         clac
769         movq    %rax,PCB_ONFAULT(%rcx)
770         movl    %r11d,(%rsi)
771         POP_FRAME_POINTER
772         ret
773 END(fueword32_smap)
774
775 ENTRY(fuword16_nosmap)
776         PUSH_FRAME_POINTER
777         movq    PCPU(CURPCB),%rcx
778         movq    $fusufault,PCB_ONFAULT(%rcx)
779
780         movq    $VM_MAXUSER_ADDRESS-2,%rax
781         cmpq    %rax,%rdi
782         ja      fusufault
783
784         movzwl  (%rdi),%eax
785         movq    $0,PCB_ONFAULT(%rcx)
786         POP_FRAME_POINTER
787         ret
788 END(fuword16_nosmap)
789
790 ENTRY(fuword16_smap)
791         PUSH_FRAME_POINTER
792         movq    PCPU(CURPCB),%rcx
793         movq    $fusufault,PCB_ONFAULT(%rcx)
794
795         movq    $VM_MAXUSER_ADDRESS-2,%rax
796         cmpq    %rax,%rdi
797         ja      fusufault
798
799         stac
800         movzwl  (%rdi),%eax
801         clac
802         movq    $0,PCB_ONFAULT(%rcx)
803         POP_FRAME_POINTER
804         ret
805 END(fuword16_smap)
806
807 ENTRY(fubyte_nosmap)
808         PUSH_FRAME_POINTER
809         movq    PCPU(CURPCB),%rcx
810         movq    $fusufault,PCB_ONFAULT(%rcx)
811
812         movq    $VM_MAXUSER_ADDRESS-1,%rax
813         cmpq    %rax,%rdi
814         ja      fusufault
815
816         movzbl  (%rdi),%eax
817         movq    $0,PCB_ONFAULT(%rcx)
818         POP_FRAME_POINTER
819         ret
820 END(fubyte_nosmap)
821
822 ENTRY(fubyte_smap)
823         PUSH_FRAME_POINTER
824         movq    PCPU(CURPCB),%rcx
825         movq    $fusufault,PCB_ONFAULT(%rcx)
826
827         movq    $VM_MAXUSER_ADDRESS-1,%rax
828         cmpq    %rax,%rdi
829         ja      fusufault
830
831         stac
832         movzbl  (%rdi),%eax
833         clac
834         movq    $0,PCB_ONFAULT(%rcx)
835         POP_FRAME_POINTER
836         ret
837 END(fubyte_smap)
838
839 /*
840  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
841  * user memory.
842  * addr = %rdi, value = %rsi
843  */
844 ENTRY(suword_nosmap)
845         PUSH_FRAME_POINTER
846         movq    PCPU(CURPCB),%rcx
847         movq    $fusufault,PCB_ONFAULT(%rcx)
848
849         movq    $VM_MAXUSER_ADDRESS-8,%rax
850         cmpq    %rax,%rdi                       /* verify address validity */
851         ja      fusufault
852
853         movq    %rsi,(%rdi)
854         xorl    %eax,%eax
855         movq    PCPU(CURPCB),%rcx
856         movq    %rax,PCB_ONFAULT(%rcx)
857         POP_FRAME_POINTER
858         ret
859 END(suword_nosmap)
860
861 ENTRY(suword_smap)
862         PUSH_FRAME_POINTER
863         movq    PCPU(CURPCB),%rcx
864         movq    $fusufault,PCB_ONFAULT(%rcx)
865
866         movq    $VM_MAXUSER_ADDRESS-8,%rax
867         cmpq    %rax,%rdi                       /* verify address validity */
868         ja      fusufault
869
870         stac
871         movq    %rsi,(%rdi)
872         clac
873         xorl    %eax,%eax
874         movq    PCPU(CURPCB),%rcx
875         movq    %rax,PCB_ONFAULT(%rcx)
876         POP_FRAME_POINTER
877         ret
878 END(suword_smap)
879
880 ENTRY(suword32_nosmap)
881         PUSH_FRAME_POINTER
882         movq    PCPU(CURPCB),%rcx
883         movq    $fusufault,PCB_ONFAULT(%rcx)
884
885         movq    $VM_MAXUSER_ADDRESS-4,%rax
886         cmpq    %rax,%rdi                       /* verify address validity */
887         ja      fusufault
888
889         movl    %esi,(%rdi)
890         xorl    %eax,%eax
891         movq    PCPU(CURPCB),%rcx
892         movq    %rax,PCB_ONFAULT(%rcx)
893         POP_FRAME_POINTER
894         ret
895 END(suword32_nosmap)
896
897 ENTRY(suword32_smap)
898         PUSH_FRAME_POINTER
899         movq    PCPU(CURPCB),%rcx
900         movq    $fusufault,PCB_ONFAULT(%rcx)
901
902         movq    $VM_MAXUSER_ADDRESS-4,%rax
903         cmpq    %rax,%rdi                       /* verify address validity */
904         ja      fusufault
905
906         stac
907         movl    %esi,(%rdi)
908         clac
909         xorl    %eax,%eax
910         movq    PCPU(CURPCB),%rcx
911         movq    %rax,PCB_ONFAULT(%rcx)
912         POP_FRAME_POINTER
913         ret
914 END(suword32_smap)
915
916 ENTRY(suword16_nosmap)
917         PUSH_FRAME_POINTER
918         movq    PCPU(CURPCB),%rcx
919         movq    $fusufault,PCB_ONFAULT(%rcx)
920
921         movq    $VM_MAXUSER_ADDRESS-2,%rax
922         cmpq    %rax,%rdi                       /* verify address validity */
923         ja      fusufault
924
925         movw    %si,(%rdi)
926         xorl    %eax,%eax
927         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
928         movq    %rax,PCB_ONFAULT(%rcx)
929         POP_FRAME_POINTER
930         ret
931 END(suword16_nosmap)
932
933 ENTRY(suword16_smap)
934         PUSH_FRAME_POINTER
935         movq    PCPU(CURPCB),%rcx
936         movq    $fusufault,PCB_ONFAULT(%rcx)
937
938         movq    $VM_MAXUSER_ADDRESS-2,%rax
939         cmpq    %rax,%rdi                       /* verify address validity */
940         ja      fusufault
941
942         stac
943         movw    %si,(%rdi)
944         clac
945         xorl    %eax,%eax
946         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
947         movq    %rax,PCB_ONFAULT(%rcx)
948         POP_FRAME_POINTER
949         ret
950 END(suword16_smap)
951
952 ENTRY(subyte_nosmap)
953         PUSH_FRAME_POINTER
954         movq    PCPU(CURPCB),%rcx
955         movq    $fusufault,PCB_ONFAULT(%rcx)
956
957         movq    $VM_MAXUSER_ADDRESS-1,%rax
958         cmpq    %rax,%rdi                       /* verify address validity */
959         ja      fusufault
960
961         movl    %esi,%eax
962         movb    %al,(%rdi)
963         xorl    %eax,%eax
964         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
965         movq    %rax,PCB_ONFAULT(%rcx)
966         POP_FRAME_POINTER
967         ret
968 END(subyte_nosmap)
969
970 ENTRY(subyte_smap)
971         PUSH_FRAME_POINTER
972         movq    PCPU(CURPCB),%rcx
973         movq    $fusufault,PCB_ONFAULT(%rcx)
974
975         movq    $VM_MAXUSER_ADDRESS-1,%rax
976         cmpq    %rax,%rdi                       /* verify address validity */
977         ja      fusufault
978
979         movl    %esi,%eax
980         stac
981         movb    %al,(%rdi)
982         clac
983         xorl    %eax,%eax
984         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
985         movq    %rax,PCB_ONFAULT(%rcx)
986         POP_FRAME_POINTER
987         ret
988 END(subyte_smap)
989
990         ALIGN_TEXT
991         /* Fault entry clears PSL.AC */
992 fusufault:
993         movq    PCPU(CURPCB),%rcx
994         xorl    %eax,%eax
995         movq    %rax,PCB_ONFAULT(%rcx)
996         decq    %rax
997         POP_FRAME_POINTER
998         ret
999
1000 /*
1001  * copyinstr(from, to, maxlen, int *lencopied)
1002  *           %rdi, %rsi, %rdx, %rcx
1003  *
1004  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
1005  *      return ENAMETOOLONG if string is longer than maxlen, and
1006  *      EFAULT on protection violations. If lencopied is non-zero,
1007  *      return the actual length in *lencopied.
1008  */
1009 ENTRY(copyinstr_nosmap)
1010         PUSH_FRAME_POINTER
1011         movq    %rdx,%r8                        /* %r8 = maxlen */
1012         movq    %rcx,%r9                        /* %r9 = *len */
1013         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
1014         movq    PCPU(CURPCB),%rcx
1015         movq    $cpystrflt,PCB_ONFAULT(%rcx)
1016
1017         movq    $VM_MAXUSER_ADDRESS,%rax
1018
1019         /* make sure 'from' is within bounds */
1020         subq    %rsi,%rax
1021         jbe     cpystrflt
1022
1023         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1024         cmpq    %rdx,%rax
1025         jae     1f
1026         movq    %rax,%rdx
1027         movq    %rax,%r8
1028 1:
1029         incq    %rdx
1030
1031 2:
1032         decq    %rdx
1033         jz      copyinstr_toolong
1034
1035         lodsb
1036         stosb
1037         orb     %al,%al
1038         jnz     2b
1039
1040         jmp     copyinstr_succ
1041 END(copyinstr_nosmap)
1042
1043 ENTRY(copyinstr_smap)
1044         PUSH_FRAME_POINTER
1045         movq    %rdx,%r8                        /* %r8 = maxlen */
1046         movq    %rcx,%r9                        /* %r9 = *len */
1047         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
1048         movq    PCPU(CURPCB),%rcx
1049         movq    $cpystrflt,PCB_ONFAULT(%rcx)
1050
1051         movq    $VM_MAXUSER_ADDRESS,%rax
1052
1053         /* make sure 'from' is within bounds */
1054         subq    %rsi,%rax
1055         jbe     cpystrflt
1056
1057         stac
1058
1059         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1060         cmpq    %rdx,%rax
1061         jae     1f
1062         movq    %rax,%rdx
1063         movq    %rax,%r8
1064 1:
1065         incq    %rdx
1066
1067 2:
1068         decq    %rdx
1069         jz      copyinstr_toolong_smap
1070
1071         lodsb
1072         stosb
1073         orb     %al,%al
1074         jnz     2b
1075
1076         clac
1077
1078 copyinstr_succ:
1079         /* Success -- 0 byte reached */
1080         decq    %rdx
1081         xorl    %eax,%eax
1082
1083 cpystrflt_x:
1084         /* set *lencopied and return %eax */
1085         movq    PCPU(CURPCB),%rcx
1086         movq    $0,PCB_ONFAULT(%rcx)
1087
1088         testq   %r9,%r9
1089         jz      1f
1090         subq    %rdx,%r8
1091         movq    %r8,(%r9)
1092 1:
1093         POP_FRAME_POINTER
1094         ret
1095         /* Fault entry clears PSL.AC */
1096 cpystrflt:
1097         movq    $EFAULT,%rax
1098         jmp     cpystrflt_x
1099
1100 copyinstr_toolong_smap:
1101         clac
1102 copyinstr_toolong:
1103         /* rdx is zero - return ENAMETOOLONG or EFAULT */
1104         movq    $VM_MAXUSER_ADDRESS,%rax
1105         cmpq    %rax,%rsi
1106         jae     cpystrflt
1107         movq    $ENAMETOOLONG,%rax
1108         jmp     cpystrflt_x
1109
1110 END(copyinstr_smap)
1111
1112 /*
1113  * copystr(from, to, maxlen, int *lencopied)
1114  *         %rdi, %rsi, %rdx, %rcx
1115  */
1116 ENTRY(copystr)
1117         PUSH_FRAME_POINTER
1118         movq    %rdx,%r8                        /* %r8 = maxlen */
1119
1120         xchgq   %rdi,%rsi
1121         incq    %rdx
1122 1:
1123         decq    %rdx
1124         jz      4f
1125         lodsb
1126         stosb
1127         orb     %al,%al
1128         jnz     1b
1129
1130         /* Success -- 0 byte reached */
1131         decq    %rdx
1132         xorl    %eax,%eax
1133         jmp     6f
1134 4:
1135         /* rdx is zero -- return ENAMETOOLONG */
1136         movq    $ENAMETOOLONG,%rax
1137
1138 6:
1139
1140         testq   %rcx,%rcx
1141         jz      7f
1142         /* set *lencopied and return %rax */
1143         subq    %rdx,%r8
1144         movq    %r8,(%rcx)
1145 7:
1146         POP_FRAME_POINTER
1147         ret
1148 END(copystr)
1149
1150 /*
1151  * Handling of special amd64 registers and descriptor tables etc
1152  */
1153 /* void lgdt(struct region_descriptor *rdp); */
1154 ENTRY(lgdt)
1155         /* reload the descriptor table */
1156         lgdt    (%rdi)
1157
1158         /* flush the prefetch q */
1159         jmp     1f
1160         nop
1161 1:
1162         movl    $KDSEL,%eax
1163         movl    %eax,%ds
1164         movl    %eax,%es
1165         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
1166         movl    %eax,%gs
1167         movl    %eax,%ss
1168
1169         /* reload code selector by turning return into intersegmental return */
1170         popq    %rax
1171         pushq   $KCSEL
1172         pushq   %rax
1173         MEXITCOUNT
1174         lretq
1175 END(lgdt)
1176
1177 /*****************************************************************************/
1178 /* setjump, longjump                                                         */
1179 /*****************************************************************************/
1180
1181 ENTRY(setjmp)
1182         movq    %rbx,0(%rdi)                    /* save rbx */
1183         movq    %rsp,8(%rdi)                    /* save rsp */
1184         movq    %rbp,16(%rdi)                   /* save rbp */
1185         movq    %r12,24(%rdi)                   /* save r12 */
1186         movq    %r13,32(%rdi)                   /* save r13 */
1187         movq    %r14,40(%rdi)                   /* save r14 */
1188         movq    %r15,48(%rdi)                   /* save r15 */
1189         movq    0(%rsp),%rdx                    /* get rta */
1190         movq    %rdx,56(%rdi)                   /* save rip */
1191         xorl    %eax,%eax                       /* return(0); */
1192         ret
1193 END(setjmp)
1194
1195 ENTRY(longjmp)
1196         movq    0(%rdi),%rbx                    /* restore rbx */
1197         movq    8(%rdi),%rsp                    /* restore rsp */
1198         movq    16(%rdi),%rbp                   /* restore rbp */
1199         movq    24(%rdi),%r12                   /* restore r12 */
1200         movq    32(%rdi),%r13                   /* restore r13 */
1201         movq    40(%rdi),%r14                   /* restore r14 */
1202         movq    48(%rdi),%r15                   /* restore r15 */
1203         movq    56(%rdi),%rdx                   /* get rta */
1204         movq    %rdx,0(%rsp)                    /* put in return frame */
1205         xorl    %eax,%eax                       /* return(1); */
1206         incl    %eax
1207         ret
1208 END(longjmp)
1209
1210 /*
1211  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
1212  * return an error.)
1213  */
1214 ENTRY(rdmsr_safe)
1215 /* int rdmsr_safe(u_int msr, uint64_t *data) */
1216         PUSH_FRAME_POINTER
1217         movq    PCPU(CURPCB),%r8
1218         movq    $msr_onfault,PCB_ONFAULT(%r8)
1219         movl    %edi,%ecx
1220         rdmsr                   /* Read MSR pointed by %ecx. Returns
1221                                    hi byte in edx, lo in %eax */
1222         salq    $32,%rdx        /* sign-shift %rdx left */
1223         movl    %eax,%eax       /* zero-extend %eax -> %rax */
1224         orq     %rdx,%rax
1225         movq    %rax,(%rsi)
1226         xorq    %rax,%rax
1227         movq    %rax,PCB_ONFAULT(%r8)
1228         POP_FRAME_POINTER
1229         ret
1230
1231 /*
1232  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
1233  * return an error.)
1234  */
1235 ENTRY(wrmsr_safe)
1236 /* int wrmsr_safe(u_int msr, uint64_t data) */
1237         PUSH_FRAME_POINTER
1238         movq    PCPU(CURPCB),%r8
1239         movq    $msr_onfault,PCB_ONFAULT(%r8)
1240         movl    %edi,%ecx
1241         movl    %esi,%eax
1242         sarq    $32,%rsi
1243         movl    %esi,%edx
1244         wrmsr                   /* Write MSR pointed by %ecx. Accepts
1245                                    hi byte in edx, lo in %eax. */
1246         xorq    %rax,%rax
1247         movq    %rax,PCB_ONFAULT(%r8)
1248         POP_FRAME_POINTER
1249         ret
1250
1251 /*
1252  * MSR operations fault handler
1253  */
1254         ALIGN_TEXT
1255 msr_onfault:
1256         movq    $0,PCB_ONFAULT(%r8)
1257         movl    $EFAULT,%eax
1258         POP_FRAME_POINTER
1259         ret
1260
1261 /*
1262  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
1263  * Invalidates address space addressed by ucr3, then returns to kcr3.
1264  * Done in assembler to ensure no other memory accesses happen while
1265  * on ucr3.
1266  */
1267         ALIGN_TEXT
1268 ENTRY(pmap_pti_pcid_invalidate)
1269         pushfq
1270         cli
1271         movq    %rdi,%cr3       /* to user page table */
1272         movq    %rsi,%cr3       /* back to kernel */
1273         popfq
1274         retq
1275
1276 /*
1277  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
1278  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
1279  */
1280         ALIGN_TEXT
1281 ENTRY(pmap_pti_pcid_invlpg)
1282         pushfq
1283         cli
1284         movq    %rdi,%cr3       /* to user page table */
1285         invlpg  (%rdx)
1286         movq    %rsi,%cr3       /* back to kernel */
1287         popfq
1288         retq
1289
1290 /*
1291  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
1292  *     vm_offset_t eva);
1293  * Invalidates virtual addresses between sva and eva in address space ucr3,
1294  * then returns to kcr3.
1295  */
1296         ALIGN_TEXT
1297 ENTRY(pmap_pti_pcid_invlrng)
1298         pushfq
1299         cli
1300         movq    %rdi,%cr3       /* to user page table */
1301 1:      invlpg  (%rdx)
1302         addq    $PAGE_SIZE,%rdx
1303         cmpq    %rdx,%rcx
1304         ja      1b
1305         movq    %rsi,%cr3       /* back to kernel */
1306         popfq
1307         retq
1308
1309         .altmacro
1310         .macro  ibrs_seq_label l
1311 handle_ibrs_\l:
1312         .endm
1313         .macro  ibrs_call_label l
1314         call    handle_ibrs_\l
1315         .endm
1316         .macro  ibrs_seq count
1317         ll=1
1318         .rept   \count
1319         ibrs_call_label %(ll)
1320         nop
1321         ibrs_seq_label %(ll)
1322         addq    $8,%rsp
1323         ll=ll+1
1324         .endr
1325         .endm
1326
1327 /* all callers already saved %rax, %rdx, and %rcx */
1328 ENTRY(handle_ibrs_entry)
1329         cmpb    $0,hw_ibrs_active(%rip)
1330         je      1f
1331         movl    $MSR_IA32_SPEC_CTRL,%ecx
1332         rdmsr
1333         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1334         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
1335         wrmsr
1336         movb    $1,PCPU(IBPB_SET)
1337         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
1338         jne     1f
1339         ibrs_seq 32
1340 1:      ret
1341 END(handle_ibrs_entry)
1342
1343 ENTRY(handle_ibrs_exit)
1344         cmpb    $0,PCPU(IBPB_SET)
1345         je      1f
1346         movl    $MSR_IA32_SPEC_CTRL,%ecx
1347         rdmsr
1348         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1349         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1350         wrmsr
1351         movb    $0,PCPU(IBPB_SET)
1352 1:      ret
1353 END(handle_ibrs_exit)
1354
1355 /* registers-neutral version, but needs stack */
1356 ENTRY(handle_ibrs_exit_rs)
1357         cmpb    $0,PCPU(IBPB_SET)
1358         je      1f
1359         pushq   %rax
1360         pushq   %rdx
1361         pushq   %rcx
1362         movl    $MSR_IA32_SPEC_CTRL,%ecx
1363         rdmsr
1364         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1365         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1366         wrmsr
1367         popq    %rcx
1368         popq    %rdx
1369         popq    %rax
1370         movb    $0,PCPU(IBPB_SET)
1371 1:      ret
1372 END(handle_ibrs_exit_rs)
1373
1374         .noaltmacro
1375
1376 /*
1377  * Flush L1D cache.  Load enough of the data from the kernel text
1378  * to flush existing L1D content.
1379  *
1380  * N.B. The function does not follow ABI calling conventions, it corrupts %rbx.
1381  * The vmm.ko caller expects that only %rax, %rdx, %rbx, %rcx, %r9, and %rflags
1382  * registers are clobbered.  The NMI handler caller only needs %r13 preserved.
1383  */
1384 ENTRY(flush_l1d_sw)
1385 #define L1D_FLUSH_SIZE  (64 * 1024)
1386         movq    $KERNBASE, %r9
1387         movq    $-L1D_FLUSH_SIZE, %rcx
1388         /*
1389          * pass 1: Preload TLB.
1390          * Kernel text is mapped using superpages.  TLB preload is
1391          * done for the benefit of older CPUs which split 2M page
1392          * into 4k TLB entries.
1393          */
1394 1:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1395         addq    $PAGE_SIZE, %rcx
1396         jne     1b
1397         xorl    %eax, %eax
1398         cpuid
1399         movq    $-L1D_FLUSH_SIZE, %rcx
1400         /* pass 2: Read each cache line. */
1401 2:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1402         addq    $64, %rcx
1403         jne     2b
1404         lfence
1405         ret
1406 #undef  L1D_FLUSH_SIZE
1407 END(flush_l1d_sw)