]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
amd64: mostly depessimize copystr
[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         movq    $copy_fault,PCB_ONFAULT(%r9)
408
409         /*
410          * Check explicitly for non-user addresses.  If 486 write protection
411          * is being used, this check is essential because we are in kernel
412          * mode so the h/w does not provide any protection against writing
413          * kernel addresses.
414          */
415
416         /*
417          * First, prevent address wrapping.
418          */
419         movq    %rsi,%rax
420         addq    %rdx,%rax
421         jc      copy_fault
422 /*
423  * XXX STOP USING VM_MAXUSER_ADDRESS.
424  * It is an end address, not a max, so every time it is used correctly it
425  * looks like there is an off by one error, and of course it caused an off
426  * by one error in several places.
427  */
428         movq    $VM_MAXUSER_ADDRESS,%rcx
429         cmpq    %rcx,%rax
430         ja      copy_fault
431
432         /*
433          * Set up arguments for rep movs*.
434          */
435         movq    %rdi,%r8
436         movq    %rsi,%rdi
437         movq    %r8,%rsi
438         movq    %rdx,%rcx
439
440         /*
441          * Set return value to zero. Remaining failure mode goes through
442          * copy_fault.
443          */
444         xorl    %eax,%eax
445
446         SMAP_DISABLE \smap
447 .if     \erms == 0
448         cmpq    $15,%rcx
449         jbe     1f
450         shrq    $3,%rcx
451         rep
452         movsq
453         movb    %dl,%cl
454         andb    $7,%cl
455         jne     1f
456         SMAP_ENABLE \smap
457         movq    %rax,PCB_ONFAULT(%r9)
458         POP_FRAME_POINTER
459         ret
460 .endif
461         ALIGN_TEXT
462 1:
463         rep
464         movsb
465
466         SMAP_ENABLE \smap
467         movq    %rax,PCB_ONFAULT(%r9)
468         POP_FRAME_POINTER
469         ret
470 .endm
471
472 ENTRY(copyout_nosmap_std)
473         COPYOUT smap=0 erms=0
474 END(copyout_nosmap_std)
475
476 ENTRY(copyout_smap_std)
477         COPYOUT smap=1 erms=0
478 END(copyout_smap_std)
479
480 ENTRY(copyout_nosmap_erms)
481         COPYOUT smap=0 erms=1
482 END(copyout_nosmap_erms)
483
484 ENTRY(copyout_smap_erms)
485         COPYOUT smap=1 erms=1
486 END(copyout_smap_erms)
487
488 /*
489  * copyin(from_user, to_kernel, len)
490  *        %rdi,      %rsi,      %rdx
491  */
492 .macro  COPYIN smap erms
493         PUSH_FRAME_POINTER
494         movq    PCPU(CURPCB),%r9
495         movq    $copy_fault,PCB_ONFAULT(%r9)
496
497         /*
498          * make sure address is valid
499          */
500         movq    %rdi,%rax
501         addq    %rdx,%rax
502         jc      copy_fault
503         movq    $VM_MAXUSER_ADDRESS,%rcx
504         cmpq    %rcx,%rax
505         ja      copy_fault
506
507         movq    %rdi,%r8
508         movq    %rsi,%rdi
509         movq    %r8,%rsi
510         movq    %rdx,%rcx
511
512         xorl    %eax,%eax
513
514         SMAP_DISABLE \smap
515 .if \erms == 0
516         cmpq    $15,%rcx
517         jbe     1f
518         shrq    $3,%rcx                         /* copy longword-wise */
519         rep
520         movsq
521         movb    %dl,%cl
522         andb    $7,%cl                          /* copy remaining bytes */
523         jne     1f
524         SMAP_ENABLE \smap
525         movq    %rax,PCB_ONFAULT(%r9)
526         POP_FRAME_POINTER
527         ret
528 .endif
529         ALIGN_TEXT
530 1:
531         rep
532         movsb
533
534         SMAP_ENABLE \smap
535         movq    %rax,PCB_ONFAULT(%r9)
536         POP_FRAME_POINTER
537         ret
538 .endm
539
540 ENTRY(copyin_nosmap_std)
541         COPYIN smap=0 erms=0
542 END(copyin_nosmap_std)
543
544 ENTRY(copyin_smap_std)
545         COPYIN smap=1 erms=0
546 END(copyin_smap_std)
547
548 ENTRY(copyin_nosmap_erms)
549         COPYIN smap=0 erms=1
550 END(copyin_nosmap_erms)
551
552 ENTRY(copyin_smap_erms)
553         COPYIN smap=1 erms=1
554 END(copyin_smap_erms)
555
556         ALIGN_TEXT
557         /* Trap entry clears PSL.AC */
558 copy_fault:
559         movq    $0,PCB_ONFAULT(%r9)
560         movl    $EFAULT,%eax
561         POP_FRAME_POINTER
562         ret
563
564 /*
565  * casueword32.  Compare and set user integer.  Returns -1 on fault,
566  *        0 if access was successful.  Old value is written to *oldp.
567  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
568  */
569 ENTRY(casueword32_nosmap)
570         PUSH_FRAME_POINTER
571         movq    PCPU(CURPCB),%r8
572         movq    $fusufault,PCB_ONFAULT(%r8)
573
574         movq    $VM_MAXUSER_ADDRESS-4,%rax
575         cmpq    %rax,%rdi                       /* verify address is valid */
576         ja      fusufault
577
578         movl    %esi,%eax                       /* old */
579 #ifdef SMP
580         lock
581 #endif
582         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
583
584         /*
585          * The old value is in %eax.  If the store succeeded it will be the
586          * value we expected (old) from before the store, otherwise it will
587          * be the current value.  Save %eax into %esi to prepare the return
588          * value.
589          */
590         movl    %eax,%esi
591         xorl    %eax,%eax
592         movq    %rax,PCB_ONFAULT(%r8)
593
594         /*
595          * Access the oldp after the pcb_onfault is cleared, to correctly
596          * catch corrupted pointer.
597          */
598         movl    %esi,(%rdx)                     /* oldp = %rdx */
599         POP_FRAME_POINTER
600         ret
601 END(casueword32_nosmap)
602
603 ENTRY(casueword32_smap)
604         PUSH_FRAME_POINTER
605         movq    PCPU(CURPCB),%r8
606         movq    $fusufault,PCB_ONFAULT(%r8)
607
608         movq    $VM_MAXUSER_ADDRESS-4,%rax
609         cmpq    %rax,%rdi                       /* verify address is valid */
610         ja      fusufault
611
612         movl    %esi,%eax                       /* old */
613         stac
614 #ifdef SMP
615         lock
616 #endif
617         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
618         clac
619
620         /*
621          * The old value is in %eax.  If the store succeeded it will be the
622          * value we expected (old) from before the store, otherwise it will
623          * be the current value.  Save %eax into %esi to prepare the return
624          * value.
625          */
626         movl    %eax,%esi
627         xorl    %eax,%eax
628         movq    %rax,PCB_ONFAULT(%r8)
629
630         /*
631          * Access the oldp after the pcb_onfault is cleared, to correctly
632          * catch corrupted pointer.
633          */
634         movl    %esi,(%rdx)                     /* oldp = %rdx */
635         POP_FRAME_POINTER
636         ret
637 END(casueword32_smap)
638
639 /*
640  * casueword.  Compare and set user long.  Returns -1 on fault,
641  *        0 if access was successful.  Old value is written to *oldp.
642  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
643  */
644 ENTRY(casueword_nosmap)
645         PUSH_FRAME_POINTER
646         movq    PCPU(CURPCB),%r8
647         movq    $fusufault,PCB_ONFAULT(%r8)
648
649         movq    $VM_MAXUSER_ADDRESS-4,%rax
650         cmpq    %rax,%rdi                       /* verify address is valid */
651         ja      fusufault
652
653         movq    %rsi,%rax                       /* old */
654 #ifdef SMP
655         lock
656 #endif
657         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
658
659         /*
660          * The old value is in %rax.  If the store succeeded it will be the
661          * value we expected (old) from before the store, otherwise it will
662          * be the current value.
663          */
664         movq    %rax,%rsi
665         xorl    %eax,%eax
666         movq    %rax,PCB_ONFAULT(%r8)
667         movq    %rsi,(%rdx)
668         POP_FRAME_POINTER
669         ret
670 END(casueword_nosmap)
671
672 ENTRY(casueword_smap)
673         PUSH_FRAME_POINTER
674         movq    PCPU(CURPCB),%r8
675         movq    $fusufault,PCB_ONFAULT(%r8)
676
677         movq    $VM_MAXUSER_ADDRESS-4,%rax
678         cmpq    %rax,%rdi                       /* verify address is valid */
679         ja      fusufault
680
681         movq    %rsi,%rax                       /* old */
682         stac
683 #ifdef SMP
684         lock
685 #endif
686         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
687         clac
688
689         /*
690          * The old value is in %rax.  If the store succeeded it will be the
691          * value we expected (old) from before the store, otherwise it will
692          * be the current value.
693          */
694         movq    %rax,%rsi
695         xorl    %eax,%eax
696         movq    %rax,PCB_ONFAULT(%r8)
697         movq    %rsi,(%rdx)
698         POP_FRAME_POINTER
699         ret
700 END(casueword_smap)
701
702 /*
703  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
704  * byte from user memory.
705  * addr = %rdi, valp = %rsi
706  */
707
708 ENTRY(fueword_nosmap)
709         PUSH_FRAME_POINTER
710         movq    PCPU(CURPCB),%rcx
711         movq    $fusufault,PCB_ONFAULT(%rcx)
712
713         movq    $VM_MAXUSER_ADDRESS-8,%rax
714         cmpq    %rax,%rdi                       /* verify address is valid */
715         ja      fusufault
716
717         xorl    %eax,%eax
718         movq    (%rdi),%r11
719         movq    %rax,PCB_ONFAULT(%rcx)
720         movq    %r11,(%rsi)
721         POP_FRAME_POINTER
722         ret
723 END(fueword_nosmap)
724
725 ENTRY(fueword_smap)
726         PUSH_FRAME_POINTER
727         movq    PCPU(CURPCB),%rcx
728         movq    $fusufault,PCB_ONFAULT(%rcx)
729
730         movq    $VM_MAXUSER_ADDRESS-8,%rax
731         cmpq    %rax,%rdi                       /* verify address is valid */
732         ja      fusufault
733
734         xorl    %eax,%eax
735         stac
736         movq    (%rdi),%r11
737         clac
738         movq    %rax,PCB_ONFAULT(%rcx)
739         movq    %r11,(%rsi)
740         POP_FRAME_POINTER
741         ret
742 END(fueword_smap)
743
744 ENTRY(fueword32_nosmap)
745         PUSH_FRAME_POINTER
746         movq    PCPU(CURPCB),%rcx
747         movq    $fusufault,PCB_ONFAULT(%rcx)
748
749         movq    $VM_MAXUSER_ADDRESS-4,%rax
750         cmpq    %rax,%rdi                       /* verify address is valid */
751         ja      fusufault
752
753         xorl    %eax,%eax
754         movl    (%rdi),%r11d
755         movq    %rax,PCB_ONFAULT(%rcx)
756         movl    %r11d,(%rsi)
757         POP_FRAME_POINTER
758         ret
759 END(fueword32_nosmap)
760
761 ENTRY(fueword32_smap)
762         PUSH_FRAME_POINTER
763         movq    PCPU(CURPCB),%rcx
764         movq    $fusufault,PCB_ONFAULT(%rcx)
765
766         movq    $VM_MAXUSER_ADDRESS-4,%rax
767         cmpq    %rax,%rdi                       /* verify address is valid */
768         ja      fusufault
769
770         xorl    %eax,%eax
771         stac
772         movl    (%rdi),%r11d
773         clac
774         movq    %rax,PCB_ONFAULT(%rcx)
775         movl    %r11d,(%rsi)
776         POP_FRAME_POINTER
777         ret
778 END(fueword32_smap)
779
780 ENTRY(fuword16_nosmap)
781         PUSH_FRAME_POINTER
782         movq    PCPU(CURPCB),%rcx
783         movq    $fusufault,PCB_ONFAULT(%rcx)
784
785         movq    $VM_MAXUSER_ADDRESS-2,%rax
786         cmpq    %rax,%rdi
787         ja      fusufault
788
789         movzwl  (%rdi),%eax
790         movq    $0,PCB_ONFAULT(%rcx)
791         POP_FRAME_POINTER
792         ret
793 END(fuword16_nosmap)
794
795 ENTRY(fuword16_smap)
796         PUSH_FRAME_POINTER
797         movq    PCPU(CURPCB),%rcx
798         movq    $fusufault,PCB_ONFAULT(%rcx)
799
800         movq    $VM_MAXUSER_ADDRESS-2,%rax
801         cmpq    %rax,%rdi
802         ja      fusufault
803
804         stac
805         movzwl  (%rdi),%eax
806         clac
807         movq    $0,PCB_ONFAULT(%rcx)
808         POP_FRAME_POINTER
809         ret
810 END(fuword16_smap)
811
812 ENTRY(fubyte_nosmap)
813         PUSH_FRAME_POINTER
814         movq    PCPU(CURPCB),%rcx
815         movq    $fusufault,PCB_ONFAULT(%rcx)
816
817         movq    $VM_MAXUSER_ADDRESS-1,%rax
818         cmpq    %rax,%rdi
819         ja      fusufault
820
821         movzbl  (%rdi),%eax
822         movq    $0,PCB_ONFAULT(%rcx)
823         POP_FRAME_POINTER
824         ret
825 END(fubyte_nosmap)
826
827 ENTRY(fubyte_smap)
828         PUSH_FRAME_POINTER
829         movq    PCPU(CURPCB),%rcx
830         movq    $fusufault,PCB_ONFAULT(%rcx)
831
832         movq    $VM_MAXUSER_ADDRESS-1,%rax
833         cmpq    %rax,%rdi
834         ja      fusufault
835
836         stac
837         movzbl  (%rdi),%eax
838         clac
839         movq    $0,PCB_ONFAULT(%rcx)
840         POP_FRAME_POINTER
841         ret
842 END(fubyte_smap)
843
844 /*
845  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
846  * user memory.
847  * addr = %rdi, value = %rsi
848  */
849 ENTRY(suword_nosmap)
850         PUSH_FRAME_POINTER
851         movq    PCPU(CURPCB),%rcx
852         movq    $fusufault,PCB_ONFAULT(%rcx)
853
854         movq    $VM_MAXUSER_ADDRESS-8,%rax
855         cmpq    %rax,%rdi                       /* verify address validity */
856         ja      fusufault
857
858         movq    %rsi,(%rdi)
859         xorl    %eax,%eax
860         movq    PCPU(CURPCB),%rcx
861         movq    %rax,PCB_ONFAULT(%rcx)
862         POP_FRAME_POINTER
863         ret
864 END(suword_nosmap)
865
866 ENTRY(suword_smap)
867         PUSH_FRAME_POINTER
868         movq    PCPU(CURPCB),%rcx
869         movq    $fusufault,PCB_ONFAULT(%rcx)
870
871         movq    $VM_MAXUSER_ADDRESS-8,%rax
872         cmpq    %rax,%rdi                       /* verify address validity */
873         ja      fusufault
874
875         stac
876         movq    %rsi,(%rdi)
877         clac
878         xorl    %eax,%eax
879         movq    PCPU(CURPCB),%rcx
880         movq    %rax,PCB_ONFAULT(%rcx)
881         POP_FRAME_POINTER
882         ret
883 END(suword_smap)
884
885 ENTRY(suword32_nosmap)
886         PUSH_FRAME_POINTER
887         movq    PCPU(CURPCB),%rcx
888         movq    $fusufault,PCB_ONFAULT(%rcx)
889
890         movq    $VM_MAXUSER_ADDRESS-4,%rax
891         cmpq    %rax,%rdi                       /* verify address validity */
892         ja      fusufault
893
894         movl    %esi,(%rdi)
895         xorl    %eax,%eax
896         movq    PCPU(CURPCB),%rcx
897         movq    %rax,PCB_ONFAULT(%rcx)
898         POP_FRAME_POINTER
899         ret
900 END(suword32_nosmap)
901
902 ENTRY(suword32_smap)
903         PUSH_FRAME_POINTER
904         movq    PCPU(CURPCB),%rcx
905         movq    $fusufault,PCB_ONFAULT(%rcx)
906
907         movq    $VM_MAXUSER_ADDRESS-4,%rax
908         cmpq    %rax,%rdi                       /* verify address validity */
909         ja      fusufault
910
911         stac
912         movl    %esi,(%rdi)
913         clac
914         xorl    %eax,%eax
915         movq    PCPU(CURPCB),%rcx
916         movq    %rax,PCB_ONFAULT(%rcx)
917         POP_FRAME_POINTER
918         ret
919 END(suword32_smap)
920
921 ENTRY(suword16_nosmap)
922         PUSH_FRAME_POINTER
923         movq    PCPU(CURPCB),%rcx
924         movq    $fusufault,PCB_ONFAULT(%rcx)
925
926         movq    $VM_MAXUSER_ADDRESS-2,%rax
927         cmpq    %rax,%rdi                       /* verify address validity */
928         ja      fusufault
929
930         movw    %si,(%rdi)
931         xorl    %eax,%eax
932         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
933         movq    %rax,PCB_ONFAULT(%rcx)
934         POP_FRAME_POINTER
935         ret
936 END(suword16_nosmap)
937
938 ENTRY(suword16_smap)
939         PUSH_FRAME_POINTER
940         movq    PCPU(CURPCB),%rcx
941         movq    $fusufault,PCB_ONFAULT(%rcx)
942
943         movq    $VM_MAXUSER_ADDRESS-2,%rax
944         cmpq    %rax,%rdi                       /* verify address validity */
945         ja      fusufault
946
947         stac
948         movw    %si,(%rdi)
949         clac
950         xorl    %eax,%eax
951         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
952         movq    %rax,PCB_ONFAULT(%rcx)
953         POP_FRAME_POINTER
954         ret
955 END(suword16_smap)
956
957 ENTRY(subyte_nosmap)
958         PUSH_FRAME_POINTER
959         movq    PCPU(CURPCB),%rcx
960         movq    $fusufault,PCB_ONFAULT(%rcx)
961
962         movq    $VM_MAXUSER_ADDRESS-1,%rax
963         cmpq    %rax,%rdi                       /* verify address validity */
964         ja      fusufault
965
966         movl    %esi,%eax
967         movb    %al,(%rdi)
968         xorl    %eax,%eax
969         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
970         movq    %rax,PCB_ONFAULT(%rcx)
971         POP_FRAME_POINTER
972         ret
973 END(subyte_nosmap)
974
975 ENTRY(subyte_smap)
976         PUSH_FRAME_POINTER
977         movq    PCPU(CURPCB),%rcx
978         movq    $fusufault,PCB_ONFAULT(%rcx)
979
980         movq    $VM_MAXUSER_ADDRESS-1,%rax
981         cmpq    %rax,%rdi                       /* verify address validity */
982         ja      fusufault
983
984         movl    %esi,%eax
985         stac
986         movb    %al,(%rdi)
987         clac
988         xorl    %eax,%eax
989         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
990         movq    %rax,PCB_ONFAULT(%rcx)
991         POP_FRAME_POINTER
992         ret
993 END(subyte_smap)
994
995         ALIGN_TEXT
996         /* Fault entry clears PSL.AC */
997 fusufault:
998         movq    PCPU(CURPCB),%rcx
999         xorl    %eax,%eax
1000         movq    %rax,PCB_ONFAULT(%rcx)
1001         decq    %rax
1002         POP_FRAME_POINTER
1003         ret
1004
1005 /*
1006  * copyinstr(from, to, maxlen, int *lencopied)
1007  *           %rdi, %rsi, %rdx, %rcx
1008  *
1009  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
1010  *      return ENAMETOOLONG if string is longer than maxlen, and
1011  *      EFAULT on protection violations. If lencopied is non-zero,
1012  *      return the actual length in *lencopied.
1013  */
1014 ENTRY(copyinstr_nosmap)
1015         PUSH_FRAME_POINTER
1016         movq    %rdx,%r8                        /* %r8 = maxlen */
1017         movq    %rcx,%r9                        /* %r9 = *len */
1018         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
1019         movq    PCPU(CURPCB),%rcx
1020         movq    $cpystrflt,PCB_ONFAULT(%rcx)
1021
1022         movq    $VM_MAXUSER_ADDRESS,%rax
1023
1024         /* make sure 'from' is within bounds */
1025         subq    %rsi,%rax
1026         jbe     cpystrflt
1027
1028         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1029         cmpq    %rdx,%rax
1030         jae     1f
1031         movq    %rax,%rdx
1032         movq    %rax,%r8
1033 1:
1034         incq    %rdx
1035
1036 2:
1037         decq    %rdx
1038         jz      copyinstr_toolong
1039
1040         lodsb
1041         stosb
1042         orb     %al,%al
1043         jnz     2b
1044
1045         jmp     copyinstr_succ
1046 END(copyinstr_nosmap)
1047
1048 ENTRY(copyinstr_smap)
1049         PUSH_FRAME_POINTER
1050         movq    %rdx,%r8                        /* %r8 = maxlen */
1051         movq    %rcx,%r9                        /* %r9 = *len */
1052         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
1053         movq    PCPU(CURPCB),%rcx
1054         movq    $cpystrflt,PCB_ONFAULT(%rcx)
1055
1056         movq    $VM_MAXUSER_ADDRESS,%rax
1057
1058         /* make sure 'from' is within bounds */
1059         subq    %rsi,%rax
1060         jbe     cpystrflt
1061
1062         stac
1063
1064         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1065         cmpq    %rdx,%rax
1066         jae     1f
1067         movq    %rax,%rdx
1068         movq    %rax,%r8
1069 1:
1070         incq    %rdx
1071
1072 2:
1073         decq    %rdx
1074         jz      copyinstr_toolong_smap
1075
1076         lodsb
1077         stosb
1078         orb     %al,%al
1079         jnz     2b
1080
1081         clac
1082
1083 copyinstr_succ:
1084         /* Success -- 0 byte reached */
1085         decq    %rdx
1086         xorl    %eax,%eax
1087
1088 cpystrflt_x:
1089         /* set *lencopied and return %eax */
1090         movq    PCPU(CURPCB),%rcx
1091         movq    $0,PCB_ONFAULT(%rcx)
1092
1093         testq   %r9,%r9
1094         jz      1f
1095         subq    %rdx,%r8
1096         movq    %r8,(%r9)
1097 1:
1098         POP_FRAME_POINTER
1099         ret
1100         /* Fault entry clears PSL.AC */
1101 cpystrflt:
1102         movq    $EFAULT,%rax
1103         jmp     cpystrflt_x
1104
1105 copyinstr_toolong_smap:
1106         clac
1107 copyinstr_toolong:
1108         /* rdx is zero - return ENAMETOOLONG or EFAULT */
1109         movq    $VM_MAXUSER_ADDRESS,%rax
1110         cmpq    %rax,%rsi
1111         jae     cpystrflt
1112         movq    $ENAMETOOLONG,%rax
1113         jmp     cpystrflt_x
1114
1115 END(copyinstr_smap)
1116
1117 /*
1118  * copystr(from, to, maxlen, int *lencopied)
1119  *         %rdi, %rsi, %rdx, %rcx
1120  */
1121 ENTRY(copystr)
1122         PUSH_FRAME_POINTER
1123         movq    %rdx,%r8                        /* %r8 = maxlen */
1124
1125         incq    %rdx
1126 1:
1127         decq    %rdx
1128         jz      4f
1129         movb    (%rdi),%al
1130         movb    %al,(%rsi)
1131         incq    %rsi
1132         incq    %rdi
1133         testb   %al,%al
1134         jnz     1b
1135
1136         /* Success -- 0 byte reached */
1137         decq    %rdx
1138         xorl    %eax,%eax
1139 2:
1140         testq   %rcx,%rcx
1141         jz      3f
1142         /* set *lencopied and return %rax */
1143         subq    %rdx,%r8
1144         movq    %r8,(%rcx)
1145 3:
1146         POP_FRAME_POINTER
1147         ret
1148 4:
1149         /* rdx is zero -- return ENAMETOOLONG */
1150         movl    $ENAMETOOLONG,%eax
1151         jmp     2b
1152 END(copystr)
1153
1154 /*
1155  * Handling of special amd64 registers and descriptor tables etc
1156  */
1157 /* void lgdt(struct region_descriptor *rdp); */
1158 ENTRY(lgdt)
1159         /* reload the descriptor table */
1160         lgdt    (%rdi)
1161
1162         /* flush the prefetch q */
1163         jmp     1f
1164         nop
1165 1:
1166         movl    $KDSEL,%eax
1167         movl    %eax,%ds
1168         movl    %eax,%es
1169         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
1170         movl    %eax,%gs
1171         movl    %eax,%ss
1172
1173         /* reload code selector by turning return into intersegmental return */
1174         popq    %rax
1175         pushq   $KCSEL
1176         pushq   %rax
1177         MEXITCOUNT
1178         lretq
1179 END(lgdt)
1180
1181 /*****************************************************************************/
1182 /* setjump, longjump                                                         */
1183 /*****************************************************************************/
1184
1185 ENTRY(setjmp)
1186         movq    %rbx,0(%rdi)                    /* save rbx */
1187         movq    %rsp,8(%rdi)                    /* save rsp */
1188         movq    %rbp,16(%rdi)                   /* save rbp */
1189         movq    %r12,24(%rdi)                   /* save r12 */
1190         movq    %r13,32(%rdi)                   /* save r13 */
1191         movq    %r14,40(%rdi)                   /* save r14 */
1192         movq    %r15,48(%rdi)                   /* save r15 */
1193         movq    0(%rsp),%rdx                    /* get rta */
1194         movq    %rdx,56(%rdi)                   /* save rip */
1195         xorl    %eax,%eax                       /* return(0); */
1196         ret
1197 END(setjmp)
1198
1199 ENTRY(longjmp)
1200         movq    0(%rdi),%rbx                    /* restore rbx */
1201         movq    8(%rdi),%rsp                    /* restore rsp */
1202         movq    16(%rdi),%rbp                   /* restore rbp */
1203         movq    24(%rdi),%r12                   /* restore r12 */
1204         movq    32(%rdi),%r13                   /* restore r13 */
1205         movq    40(%rdi),%r14                   /* restore r14 */
1206         movq    48(%rdi),%r15                   /* restore r15 */
1207         movq    56(%rdi),%rdx                   /* get rta */
1208         movq    %rdx,0(%rsp)                    /* put in return frame */
1209         xorl    %eax,%eax                       /* return(1); */
1210         incl    %eax
1211         ret
1212 END(longjmp)
1213
1214 /*
1215  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
1216  * return an error.)
1217  */
1218 ENTRY(rdmsr_safe)
1219 /* int rdmsr_safe(u_int msr, uint64_t *data) */
1220         PUSH_FRAME_POINTER
1221         movq    PCPU(CURPCB),%r8
1222         movq    $msr_onfault,PCB_ONFAULT(%r8)
1223         movl    %edi,%ecx
1224         rdmsr                   /* Read MSR pointed by %ecx. Returns
1225                                    hi byte in edx, lo in %eax */
1226         salq    $32,%rdx        /* sign-shift %rdx left */
1227         movl    %eax,%eax       /* zero-extend %eax -> %rax */
1228         orq     %rdx,%rax
1229         movq    %rax,(%rsi)
1230         xorq    %rax,%rax
1231         movq    %rax,PCB_ONFAULT(%r8)
1232         POP_FRAME_POINTER
1233         ret
1234
1235 /*
1236  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
1237  * return an error.)
1238  */
1239 ENTRY(wrmsr_safe)
1240 /* int wrmsr_safe(u_int msr, uint64_t data) */
1241         PUSH_FRAME_POINTER
1242         movq    PCPU(CURPCB),%r8
1243         movq    $msr_onfault,PCB_ONFAULT(%r8)
1244         movl    %edi,%ecx
1245         movl    %esi,%eax
1246         sarq    $32,%rsi
1247         movl    %esi,%edx
1248         wrmsr                   /* Write MSR pointed by %ecx. Accepts
1249                                    hi byte in edx, lo in %eax. */
1250         xorq    %rax,%rax
1251         movq    %rax,PCB_ONFAULT(%r8)
1252         POP_FRAME_POINTER
1253         ret
1254
1255 /*
1256  * MSR operations fault handler
1257  */
1258         ALIGN_TEXT
1259 msr_onfault:
1260         movq    $0,PCB_ONFAULT(%r8)
1261         movl    $EFAULT,%eax
1262         POP_FRAME_POINTER
1263         ret
1264
1265 /*
1266  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
1267  * Invalidates address space addressed by ucr3, then returns to kcr3.
1268  * Done in assembler to ensure no other memory accesses happen while
1269  * on ucr3.
1270  */
1271         ALIGN_TEXT
1272 ENTRY(pmap_pti_pcid_invalidate)
1273         pushfq
1274         cli
1275         movq    %rdi,%cr3       /* to user page table */
1276         movq    %rsi,%cr3       /* back to kernel */
1277         popfq
1278         retq
1279
1280 /*
1281  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
1282  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
1283  */
1284         ALIGN_TEXT
1285 ENTRY(pmap_pti_pcid_invlpg)
1286         pushfq
1287         cli
1288         movq    %rdi,%cr3       /* to user page table */
1289         invlpg  (%rdx)
1290         movq    %rsi,%cr3       /* back to kernel */
1291         popfq
1292         retq
1293
1294 /*
1295  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
1296  *     vm_offset_t eva);
1297  * Invalidates virtual addresses between sva and eva in address space ucr3,
1298  * then returns to kcr3.
1299  */
1300         ALIGN_TEXT
1301 ENTRY(pmap_pti_pcid_invlrng)
1302         pushfq
1303         cli
1304         movq    %rdi,%cr3       /* to user page table */
1305 1:      invlpg  (%rdx)
1306         addq    $PAGE_SIZE,%rdx
1307         cmpq    %rdx,%rcx
1308         ja      1b
1309         movq    %rsi,%cr3       /* back to kernel */
1310         popfq
1311         retq
1312
1313         .altmacro
1314         .macro  ibrs_seq_label l
1315 handle_ibrs_\l:
1316         .endm
1317         .macro  ibrs_call_label l
1318         call    handle_ibrs_\l
1319         .endm
1320         .macro  ibrs_seq count
1321         ll=1
1322         .rept   \count
1323         ibrs_call_label %(ll)
1324         nop
1325         ibrs_seq_label %(ll)
1326         addq    $8,%rsp
1327         ll=ll+1
1328         .endr
1329         .endm
1330
1331 /* all callers already saved %rax, %rdx, and %rcx */
1332 ENTRY(handle_ibrs_entry)
1333         cmpb    $0,hw_ibrs_active(%rip)
1334         je      1f
1335         movl    $MSR_IA32_SPEC_CTRL,%ecx
1336         rdmsr
1337         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1338         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
1339         wrmsr
1340         movb    $1,PCPU(IBPB_SET)
1341         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
1342         jne     1f
1343         ibrs_seq 32
1344 1:      ret
1345 END(handle_ibrs_entry)
1346
1347 ENTRY(handle_ibrs_exit)
1348         cmpb    $0,PCPU(IBPB_SET)
1349         je      1f
1350         movl    $MSR_IA32_SPEC_CTRL,%ecx
1351         rdmsr
1352         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1353         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1354         wrmsr
1355         movb    $0,PCPU(IBPB_SET)
1356 1:      ret
1357 END(handle_ibrs_exit)
1358
1359 /* registers-neutral version, but needs stack */
1360 ENTRY(handle_ibrs_exit_rs)
1361         cmpb    $0,PCPU(IBPB_SET)
1362         je      1f
1363         pushq   %rax
1364         pushq   %rdx
1365         pushq   %rcx
1366         movl    $MSR_IA32_SPEC_CTRL,%ecx
1367         rdmsr
1368         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1369         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1370         wrmsr
1371         popq    %rcx
1372         popq    %rdx
1373         popq    %rax
1374         movb    $0,PCPU(IBPB_SET)
1375 1:      ret
1376 END(handle_ibrs_exit_rs)
1377
1378         .noaltmacro
1379
1380 /*
1381  * Flush L1D cache.  Load enough of the data from the kernel text
1382  * to flush existing L1D content.
1383  *
1384  * N.B. The function does not follow ABI calling conventions, it corrupts %rbx.
1385  * The vmm.ko caller expects that only %rax, %rdx, %rbx, %rcx, %r9, and %rflags
1386  * registers are clobbered.  The NMI handler caller only needs %r13 preserved.
1387  */
1388 ENTRY(flush_l1d_sw)
1389 #define L1D_FLUSH_SIZE  (64 * 1024)
1390         movq    $KERNBASE, %r9
1391         movq    $-L1D_FLUSH_SIZE, %rcx
1392         /*
1393          * pass 1: Preload TLB.
1394          * Kernel text is mapped using superpages.  TLB preload is
1395          * done for the benefit of older CPUs which split 2M page
1396          * into 4k TLB entries.
1397          */
1398 1:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1399         addq    $PAGE_SIZE, %rcx
1400         jne     1b
1401         xorl    %eax, %eax
1402         cpuid
1403         movq    $-L1D_FLUSH_SIZE, %rcx
1404         /* pass 2: Read each cache line. */
1405 2:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1406         addq    $64, %rcx
1407         jne     2b
1408         lfence
1409         ret
1410 #undef  L1D_FLUSH_SIZE
1411 END(flush_l1d_sw)