]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
amd64: move memcmp checks upfront
[FreeBSD/FreeBSD.git] / sys / amd64 / amd64 / support.S
1 /*-
2  * Copyright (c) 2018-2019 The FreeBSD Foundation
3  * Copyright (c) 2003 Peter Wemm.
4  * Copyright (c) 1993 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * Portions of this software were developed by
8  * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from
9  * the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $FreeBSD$
36  */
37
38 #include "opt_ddb.h"
39
40 #include <machine/asmacros.h>
41 #include <machine/specialreg.h>
42 #include <machine/pmap.h>
43
44 #include "assym.inc"
45
46         .text
47
48 /* Address: %rdi */
49 ENTRY(pagezero_std)
50         PUSH_FRAME_POINTER
51         movl    $PAGE_SIZE/8,%ecx
52         xorl    %eax,%eax
53         rep
54         stosq
55         POP_FRAME_POINTER
56         ret
57 END(pagezero_std)
58
59 ENTRY(pagezero_erms)
60         PUSH_FRAME_POINTER
61         movl    $PAGE_SIZE,%ecx
62         xorl    %eax,%eax
63         rep
64         stosb
65         POP_FRAME_POINTER
66         ret
67 END(pagezero_erms)
68
69 /*
70  * pagecopy(%rdi=from, %rsi=to)
71  */
72 ENTRY(pagecopy)
73         PUSH_FRAME_POINTER
74         movl    $PAGE_SIZE/8,%ecx
75         movq    %rdi,%r9
76         movq    %rsi,%rdi
77         movq    %r9,%rsi
78         rep
79         movsq
80         POP_FRAME_POINTER
81         ret
82 END(pagecopy)
83
84 /*
85  * memcmpy(b1, b2, len)
86  *         rdi,rsi,rdx
87  */
88 ENTRY(memcmp)
89         PUSH_FRAME_POINTER
90
91         xorl    %eax,%eax
92 10:
93         cmpq    $16,%rdx
94         ja      101632f
95
96         cmpb    $8,%dl
97         jg      100816f
98
99         cmpb    $4,%dl
100         jg      100408f
101
102         cmpb    $2,%dl
103         jge     100204f
104
105         cmpb    $1,%dl
106         jl      100000f
107         movzbl  (%rdi),%eax
108         movzbl  (%rsi),%r8d
109         subl    %r8d,%eax
110 100000:
111         POP_FRAME_POINTER
112         ret
113
114         ALIGN_TEXT
115 100816:
116         movq    (%rdi),%r8
117         movq    (%rsi),%r9
118         cmpq    %r8,%r9
119         jne     80f
120         movq    -8(%rdi,%rdx),%r8
121         movq    -8(%rsi,%rdx),%r9
122         cmpq    %r8,%r9
123         jne     10081608f
124         POP_FRAME_POINTER
125         ret
126         ALIGN_TEXT
127 100408:
128         movl    (%rdi),%r8d
129         movl    (%rsi),%r9d
130         cmpl    %r8d,%r9d
131         jne     80f
132         movl    -4(%rdi,%rdx),%r8d
133         movl    -4(%rsi,%rdx),%r9d
134         cmpl    %r8d,%r9d
135         jne     10040804f
136         POP_FRAME_POINTER
137         ret
138         ALIGN_TEXT
139 100204:
140         movzwl  (%rdi),%r8d
141         movzwl  (%rsi),%r9d
142         cmpl    %r8d,%r9d
143         jne     1f
144         movzwl  -2(%rdi,%rdx),%r8d
145         movzwl  -2(%rsi,%rdx),%r9d
146         cmpl    %r8d,%r9d
147         jne     1f
148         POP_FRAME_POINTER
149         ret
150         ALIGN_TEXT
151 101632:
152         cmpq    $32,%rdx
153         ja      103200f
154         movq    (%rdi),%r8
155         movq    (%rsi),%r9
156         cmpq    %r8,%r9
157         jne     80f
158         movq    8(%rdi),%r8
159         movq    8(%rsi),%r9
160         cmpq    %r8,%r9
161         jne     10163208f
162         movq    -16(%rdi,%rdx),%r8
163         movq    -16(%rsi,%rdx),%r9
164         cmpq    %r8,%r9
165         jne     10163216f
166         movq    -8(%rdi,%rdx),%r8
167         movq    -8(%rsi,%rdx),%r9
168         cmpq    %r8,%r9
169         jne     10163224f
170         POP_FRAME_POINTER
171         ret
172         ALIGN_TEXT
173 103200:
174         movq    (%rdi),%r8
175         movq    8(%rdi),%r9
176         subq    (%rsi),%r8
177         subq    8(%rsi),%r9
178         orq     %r8,%r9
179         jnz     10320000f
180
181         movq    16(%rdi),%r8
182         movq    24(%rdi),%r9
183         subq    16(%rsi),%r8
184         subq    24(%rsi),%r9
185         orq     %r8,%r9
186         jnz     10320016f
187
188         leaq    32(%rdi),%rdi
189         leaq    32(%rsi),%rsi
190         subq    $32,%rdx
191         cmpq    $32,%rdx
192         jae     103200b
193         cmpb    $0,%dl
194         jne     10b
195         POP_FRAME_POINTER
196         ret
197
198 /*
199  * Mismatch was found.
200  *
201  * Before we compute it we narrow down the range (16 -> 8 -> 4 bytes).
202  */
203         ALIGN_TEXT
204 10320016:
205         leaq    16(%rdi),%rdi
206         leaq    16(%rsi),%rsi
207 10320000:
208         movq    (%rdi),%r8
209         movq    (%rsi),%r9
210         cmpq    %r8,%r9
211         jne     80f
212         leaq    8(%rdi),%rdi
213         leaq    8(%rsi),%rsi
214         jmp     80f
215         ALIGN_TEXT
216 10081608:
217 10163224:
218         leaq    -8(%rdi,%rdx),%rdi
219         leaq    -8(%rsi,%rdx),%rsi
220         jmp     80f
221         ALIGN_TEXT
222 10163216:
223         leaq    -16(%rdi,%rdx),%rdi
224         leaq    -16(%rsi,%rdx),%rsi
225         jmp     80f
226         ALIGN_TEXT
227 10163208:
228         leaq    8(%rdi),%rdi
229         leaq    8(%rsi),%rsi
230         jmp     80f
231         ALIGN_TEXT
232 10040804:
233         leaq    -4(%rdi,%rdx),%rdi
234         leaq    -4(%rsi,%rdx),%rsi
235         jmp     1f
236
237         ALIGN_TEXT
238 80:
239         movl    (%rdi),%r8d
240         movl    (%rsi),%r9d
241         cmpl    %r8d,%r9d
242         jne     1f
243         leaq    4(%rdi),%rdi
244         leaq    4(%rsi),%rsi
245
246 /*
247  * We have up to 4 bytes to inspect.
248  */
249 1:
250         movzbl  (%rdi),%eax
251         movzbl  (%rsi),%r8d
252         cmpb    %r8b,%al
253         jne     2f
254
255         movzbl  1(%rdi),%eax
256         movzbl  1(%rsi),%r8d
257         cmpb    %r8b,%al
258         jne     2f
259
260         movzbl  2(%rdi),%eax
261         movzbl  2(%rsi),%r8d
262         cmpb    %r8b,%al
263         jne     2f
264
265         movzbl  3(%rdi),%eax
266         movzbl  3(%rsi),%r8d
267 2:
268         subl    %r8d,%eax
269         POP_FRAME_POINTER
270         ret
271 END(memcmp)
272
273 /*
274  * memmove(dst, src, cnt)
275  *         rdi, rsi, rdx
276  */
277
278 /*
279  * Register state at entry is supposed to be as follows:
280  * rdi - destination
281  * rsi - source
282  * rdx - count
283  *
284  * The macro possibly clobbers the above and: rcx, r8, r9, r10
285  * It does not clobber rax nor r11.
286  */
287 .macro MEMMOVE erms overlap begin end
288         \begin
289
290         /*
291          * For sizes 0..32 all data is read before it is written, so there
292          * is no correctness issue with direction of copying.
293          */
294         cmpq    $32,%rcx
295         jbe     101632f
296
297 .if \overlap == 1
298         movq    %rdi,%r8
299         subq    %rsi,%r8
300         cmpq    %rcx,%r8        /* overlapping && src < dst? */
301         jb      2f
302 .endif
303
304         cmpq    $256,%rcx
305         ja      1256f
306
307         ALIGN_TEXT
308 103200:
309         movq    (%rsi),%rdx
310         movq    %rdx,(%rdi)
311         movq    8(%rsi),%rdx
312         movq    %rdx,8(%rdi)
313         movq    16(%rsi),%rdx
314         movq    %rdx,16(%rdi)
315         movq    24(%rsi),%rdx
316         movq    %rdx,24(%rdi)
317         leaq    32(%rsi),%rsi
318         leaq    32(%rdi),%rdi
319         subq    $32,%rcx
320         cmpq    $32,%rcx
321         jae     103200b
322         cmpb    $0,%cl
323         jne     101632f
324         \end
325         ret
326         ALIGN_TEXT
327 101632:
328         cmpb    $16,%cl
329         jl      100816f
330         movq    (%rsi),%rdx
331         movq    8(%rsi),%r8
332         movq    -16(%rsi,%rcx),%r9
333         movq    -8(%rsi,%rcx),%r10
334         movq    %rdx,(%rdi)
335         movq    %r8,8(%rdi)
336         movq    %r9,-16(%rdi,%rcx)
337         movq    %r10,-8(%rdi,%rcx)
338         \end
339         ret
340         ALIGN_TEXT
341 100816:
342         cmpb    $8,%cl
343         jl      100408f
344         movq    (%rsi),%rdx
345         movq    -8(%rsi,%rcx),%r8
346         movq    %rdx,(%rdi)
347         movq    %r8,-8(%rdi,%rcx,)
348         \end
349         ret
350         ALIGN_TEXT
351 100408:
352         cmpb    $4,%cl
353         jl      100204f
354         movl    (%rsi),%edx
355         movl    -4(%rsi,%rcx),%r8d
356         movl    %edx,(%rdi)
357         movl    %r8d,-4(%rdi,%rcx)
358         \end
359         ret
360         ALIGN_TEXT
361 100204:
362         cmpb    $2,%cl
363         jl      100001f
364         movzwl  (%rsi),%edx
365         movzwl  -2(%rsi,%rcx),%r8d
366         movw    %dx,(%rdi)
367         movw    %r8w,-2(%rdi,%rcx)
368         \end
369         ret
370         ALIGN_TEXT
371 100001:
372         cmpb    $1,%cl
373         jl      100000f
374         movb    (%rsi),%dl
375         movb    %dl,(%rdi)
376 100000:
377         \end
378         ret
379
380         ALIGN_TEXT
381 1256:
382         testb   $15,%dil
383         jnz     100f
384 .if \erms == 1
385         rep
386         movsb
387 .else
388         shrq    $3,%rcx                         /* copy by 64-bit words */
389         rep
390         movsq
391         movq    %rdx,%rcx
392         andl    $7,%ecx                         /* any bytes left? */
393         jne     100408b
394 .endif
395         \end
396         ret
397 100:
398         movq    (%rsi),%r8
399         movq    8(%rsi),%r9
400         movq    %rdi,%r10
401         movq    %rdi,%rcx
402         andq    $15,%rcx
403         leaq    -16(%rdx,%rcx),%rdx
404         neg     %rcx
405         leaq    16(%rdi,%rcx),%rdi
406         leaq    16(%rsi,%rcx),%rsi
407         movq    %rdx,%rcx
408 .if \erms == 1
409         rep
410         movsb
411         movq    %r8,(%r10)
412         movq    %r9,8(%r10)
413 .else
414         shrq    $3,%rcx                         /* copy by 64-bit words */
415         rep
416         movsq
417         movq    %r8,(%r10)
418         movq    %r9,8(%r10)
419         movq    %rdx,%rcx
420         andl    $7,%ecx                         /* any bytes left? */
421         jne     100408b
422 .endif
423         \end
424         ret
425
426 .if \overlap == 1
427         /*
428          * Copy backwards.
429          */
430         ALIGN_TEXT
431 2:
432         cmpq    $256,%rcx
433         ja      2256f
434
435         leaq    -8(%rdi,%rcx),%rdi
436         leaq    -8(%rsi,%rcx),%rsi
437
438         cmpq    $32,%rcx
439         jb      2016f
440
441         ALIGN_TEXT
442 2032:
443         movq    (%rsi),%rdx
444         movq    %rdx,(%rdi)
445         movq    -8(%rsi),%rdx
446         movq    %rdx,-8(%rdi)
447         movq    -16(%rsi),%rdx
448         movq    %rdx,-16(%rdi)
449         movq    -24(%rsi),%rdx
450         movq    %rdx,-24(%rdi)
451         leaq    -32(%rsi),%rsi
452         leaq    -32(%rdi),%rdi
453         subq    $32,%rcx
454         cmpq    $32,%rcx
455         jae     2032b
456         cmpb    $0,%cl
457         jne     2016f
458         \end
459         ret
460         ALIGN_TEXT
461 2016:
462         cmpb    $16,%cl
463         jl      2008f
464         movq    (%rsi),%rdx
465         movq    %rdx,(%rdi)
466         movq    -8(%rsi),%rdx
467         movq    %rdx,-8(%rdi)
468         subb    $16,%cl
469         jz      2000f
470         leaq    -16(%rsi),%rsi
471         leaq    -16(%rdi),%rdi
472 2008:
473         cmpb    $8,%cl
474         jl      2004f
475         movq    (%rsi),%rdx
476         movq    %rdx,(%rdi)
477         subb    $8,%cl
478         jz      2000f
479         leaq    -8(%rsi),%rsi
480         leaq    -8(%rdi),%rdi
481 2004:
482         cmpb    $4,%cl
483         jl      2002f
484         movl    4(%rsi),%edx
485         movl    %edx,4(%rdi)
486         subb    $4,%cl
487         jz      2000f
488         leaq    -4(%rsi),%rsi
489         leaq    -4(%rdi),%rdi
490 2002:
491         cmpb    $2,%cl
492         jl      2001f
493         movw    6(%rsi),%dx
494         movw    %dx,6(%rdi)
495         subb    $2,%cl
496         jz      2000f
497         leaq    -2(%rsi),%rsi
498         leaq    -2(%rdi),%rdi
499 2001:
500         cmpb    $1,%cl
501         jl      2000f
502         movb    7(%rsi),%dl
503         movb    %dl,7(%rdi)
504 2000:
505         \end
506         ret
507         ALIGN_TEXT
508 2256:
509         std
510 .if \erms == 1
511         leaq    -1(%rdi,%rcx),%rdi
512         leaq    -1(%rsi,%rcx),%rsi
513         rep
514         movsb
515         cld
516 .else
517         leaq    -8(%rdi,%rcx),%rdi
518         leaq    -8(%rsi,%rcx),%rsi
519         shrq    $3,%rcx
520         rep
521         movsq
522         cld
523         movq    %rdx,%rcx
524         andb    $7,%cl
525         jne     2004b
526 .endif
527         \end
528         ret
529 .endif
530 .endm
531
532 .macro MEMMOVE_BEGIN
533         PUSH_FRAME_POINTER
534         movq    %rdi,%rax
535         movq    %rdx,%rcx
536 .endm
537
538 .macro MEMMOVE_END
539         POP_FRAME_POINTER
540 .endm
541
542 ENTRY(memmove_std)
543         MEMMOVE erms=0 overlap=1 begin=MEMMOVE_BEGIN end=MEMMOVE_END
544 END(memmove_std)
545
546 ENTRY(memmove_erms)
547         MEMMOVE erms=1 overlap=1 begin=MEMMOVE_BEGIN end=MEMMOVE_END
548 END(memmove_erms)
549
550 /*
551  * memcpy(dst, src, len)
552  *        rdi, rsi, rdx
553  *
554  * Note: memcpy does not support overlapping copies
555  */
556 ENTRY(memcpy_std)
557         MEMMOVE erms=0 overlap=0 begin=MEMMOVE_BEGIN end=MEMMOVE_END
558 END(memcpy_std)
559
560 ENTRY(memcpy_erms)
561         MEMMOVE erms=1 overlap=0 begin=MEMMOVE_BEGIN end=MEMMOVE_END
562 END(memcpy_erms)
563
564 /*
565  * memset(dst, c,   len)
566  *        rdi, rsi, rdx
567  */
568 .macro MEMSET erms
569         PUSH_FRAME_POINTER
570         movq    %rdi,%rax
571         movq    %rdx,%rcx
572         movzbq  %sil,%r8
573         movabs  $0x0101010101010101,%r10
574         imulq   %r8,%r10
575
576         cmpq    $32,%rcx
577         jbe     101632f
578
579         cmpq    $256,%rcx
580         ja      1256f
581
582         ALIGN_TEXT
583 103200:
584         movq    %r10,(%rdi)
585         movq    %r10,8(%rdi)
586         movq    %r10,16(%rdi)
587         movq    %r10,24(%rdi)
588         leaq    32(%rdi),%rdi
589         subq    $32,%rcx
590         cmpq    $32,%rcx
591         ja      103200b
592         cmpb    $16,%cl
593         ja      201632f
594         movq    %r10,-16(%rdi,%rcx)
595         movq    %r10,-8(%rdi,%rcx)
596         POP_FRAME_POINTER
597         ret
598         ALIGN_TEXT
599 101632:
600         cmpb    $16,%cl
601         jl      100816f
602 201632:
603         movq    %r10,(%rdi)
604         movq    %r10,8(%rdi)
605         movq    %r10,-16(%rdi,%rcx)
606         movq    %r10,-8(%rdi,%rcx)
607         POP_FRAME_POINTER
608         ret
609         ALIGN_TEXT
610 100816:
611         cmpb    $8,%cl
612         jl      100408f
613         movq    %r10,(%rdi)
614         movq    %r10,-8(%rdi,%rcx)
615         POP_FRAME_POINTER
616         ret
617         ALIGN_TEXT
618 100408:
619         cmpb    $4,%cl
620         jl      100204f
621         movl    %r10d,(%rdi)
622         movl    %r10d,-4(%rdi,%rcx)
623         POP_FRAME_POINTER
624         ret
625         ALIGN_TEXT
626 100204:
627         cmpb    $2,%cl
628         jl      100001f
629         movw    %r10w,(%rdi)
630         movw    %r10w,-2(%rdi,%rcx)
631         POP_FRAME_POINTER
632         ret
633         ALIGN_TEXT
634 100001:
635         cmpb    $0,%cl
636         je      100000f
637         movb    %r10b,(%rdi)
638 100000:
639         POP_FRAME_POINTER
640         ret
641         ALIGN_TEXT
642 1256:
643         movq    %rdi,%r9
644         movq    %r10,%rax
645         testl   $15,%edi
646         jnz     3f
647 1:
648 .if \erms == 1
649         rep
650         stosb
651         movq    %r9,%rax
652 .else
653         movq    %rcx,%rdx
654         shrq    $3,%rcx
655         rep
656         stosq
657         movq    %r9,%rax
658         andl    $7,%edx
659         jnz     2f
660         POP_FRAME_POINTER
661         ret
662 2:
663         movq    %r10,-8(%rdi,%rdx)
664 .endif
665         POP_FRAME_POINTER
666         ret
667         ALIGN_TEXT
668 3:
669         movq    %r10,(%rdi)
670         movq    %r10,8(%rdi)
671         movq    %rdi,%r8
672         andq    $15,%r8
673         leaq    -16(%rcx,%r8),%rcx
674         neg     %r8
675         leaq    16(%rdi,%r8),%rdi
676         jmp     1b
677 .endm
678
679 ENTRY(memset_std)
680         MEMSET erms=0
681 END(memset_std)
682
683 ENTRY(memset_erms)
684         MEMSET erms=1
685 END(memset_erms)
686
687 /* fillw(pat, base, cnt) */
688 /*       %rdi,%rsi, %rdx */
689 ENTRY(fillw)
690         PUSH_FRAME_POINTER
691         movq    %rdi,%rax
692         movq    %rsi,%rdi
693         movq    %rdx,%rcx
694         rep
695         stosw
696         POP_FRAME_POINTER
697         ret
698 END(fillw)
699
700 /*****************************************************************************/
701 /* copyout and fubyte family                                                 */
702 /*****************************************************************************/
703 /*
704  * Access user memory from inside the kernel. These routines should be
705  * the only places that do this.
706  *
707  * These routines set curpcb->pcb_onfault for the time they execute. When a
708  * protection violation occurs inside the functions, the trap handler
709  * returns to *curpcb->pcb_onfault instead of the function.
710  */
711
712 .macro SMAP_DISABLE smap
713 .if     \smap
714         stac
715 .endif
716 .endm
717
718
719 .macro SMAP_ENABLE smap
720 .if     \smap
721         clac
722 .endif
723 .endm
724
725 .macro COPYINOUT_BEGIN
726 .endm
727
728 .macro COPYINOUT_END
729         movq    %rax,PCB_ONFAULT(%r11)
730         POP_FRAME_POINTER
731 .endm
732
733 .macro COPYINOUT_SMAP_END
734         SMAP_ENABLE smap=1
735         COPYINOUT_END
736 .endm
737
738 /*
739  * copyout(from_kernel, to_user, len)
740  *         %rdi,        %rsi,    %rdx
741  */
742 .macro  COPYOUT smap erms
743         PUSH_FRAME_POINTER
744         movq    PCPU(CURPCB),%r11
745         movq    $copy_fault,PCB_ONFAULT(%r11)
746
747         /*
748          * Check explicitly for non-user addresses.
749          * First, prevent address wrapping.
750          */
751         movq    %rsi,%rax
752         addq    %rdx,%rax
753         jc      copy_fault
754 /*
755  * XXX STOP USING VM_MAXUSER_ADDRESS.
756  * It is an end address, not a max, so every time it is used correctly it
757  * looks like there is an off by one error, and of course it caused an off
758  * by one error in several places.
759  */
760         movq    $VM_MAXUSER_ADDRESS,%rcx
761         cmpq    %rcx,%rax
762         ja      copy_fault
763
764         /*
765          * Set return value to zero. Remaining failure mode goes through
766          * copy_fault.
767          */
768         xorl    %eax,%eax
769
770         /*
771          * Set up arguments for MEMMOVE.
772          */
773         movq    %rdi,%r8
774         movq    %rsi,%rdi
775         movq    %r8,%rsi
776         movq    %rdx,%rcx
777
778
779         SMAP_DISABLE \smap
780 .if     \smap == 1
781         MEMMOVE erms=\erms overlap=0 begin=COPYINOUT_BEGIN end=COPYINOUT_SMAP_END
782 .else
783         MEMMOVE erms=\erms overlap=0 begin=COPYINOUT_BEGIN end=COPYINOUT_END
784 .endif
785         /* NOTREACHED */
786 .endm
787
788 ENTRY(copyout_nosmap_std)
789         COPYOUT smap=0 erms=0
790 END(copyout_nosmap_std)
791
792 ENTRY(copyout_smap_std)
793         COPYOUT smap=1 erms=0
794 END(copyout_smap_std)
795
796 ENTRY(copyout_nosmap_erms)
797         COPYOUT smap=0 erms=1
798 END(copyout_nosmap_erms)
799
800 ENTRY(copyout_smap_erms)
801         COPYOUT smap=1 erms=1
802 END(copyout_smap_erms)
803
804 /*
805  * copyin(from_user, to_kernel, len)
806  *        %rdi,      %rsi,      %rdx
807  */
808 .macro  COPYIN smap erms
809         PUSH_FRAME_POINTER
810         movq    PCPU(CURPCB),%r11
811         movq    $copy_fault,PCB_ONFAULT(%r11)
812
813         /*
814          * make sure address is valid
815          */
816         movq    %rdi,%rax
817         addq    %rdx,%rax
818         jc      copy_fault
819         movq    $VM_MAXUSER_ADDRESS,%rcx
820         cmpq    %rcx,%rax
821         ja      copy_fault
822
823         xorl    %eax,%eax
824
825         movq    %rdi,%r8
826         movq    %rsi,%rdi
827         movq    %r8,%rsi
828         movq    %rdx,%rcx
829
830         SMAP_DISABLE \smap
831 .if     \smap == 1
832         MEMMOVE erms=\erms overlap=0 begin=COPYINOUT_BEGIN end=COPYINOUT_SMAP_END
833 .else
834         MEMMOVE erms=\erms overlap=0 begin=COPYINOUT_BEGIN end=COPYINOUT_END
835 .endif
836         /* NOTREACHED */
837 .endm
838
839 ENTRY(copyin_nosmap_std)
840         COPYIN smap=0 erms=0
841 END(copyin_nosmap_std)
842
843 ENTRY(copyin_smap_std)
844         COPYIN smap=1 erms=0
845 END(copyin_smap_std)
846
847 ENTRY(copyin_nosmap_erms)
848         COPYIN smap=0 erms=1
849 END(copyin_nosmap_erms)
850
851 ENTRY(copyin_smap_erms)
852         COPYIN smap=1 erms=1
853 END(copyin_smap_erms)
854
855         ALIGN_TEXT
856         /* Trap entry clears PSL.AC */
857 copy_fault:
858         movq    $0,PCB_ONFAULT(%r11)
859         movl    $EFAULT,%eax
860         POP_FRAME_POINTER
861         ret
862
863 /*
864  * casueword32.  Compare and set user integer.  Returns -1 on fault,
865  *        0 if access was successful.  Old value is written to *oldp.
866  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
867  */
868 ENTRY(casueword32_nosmap)
869         PUSH_FRAME_POINTER
870         movq    PCPU(CURPCB),%r8
871         movq    $fusufault,PCB_ONFAULT(%r8)
872
873         movq    $VM_MAXUSER_ADDRESS-4,%rax
874         cmpq    %rax,%rdi                       /* verify address is valid */
875         ja      fusufault
876
877         movl    %esi,%eax                       /* old */
878 #ifdef SMP
879         lock
880 #endif
881         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
882         setne   %cl
883
884         /*
885          * The old value is in %eax.  If the store succeeded it will be the
886          * value we expected (old) from before the store, otherwise it will
887          * be the current value.  Save %eax into %esi to prepare the return
888          * value.
889          */
890         movl    %eax,%esi
891         xorl    %eax,%eax
892         movq    %rax,PCB_ONFAULT(%r8)
893
894         /*
895          * Access the oldp after the pcb_onfault is cleared, to correctly
896          * catch corrupted pointer.
897          */
898         movl    %esi,(%rdx)                     /* oldp = %rdx */
899         POP_FRAME_POINTER
900         movzbl  %cl, %eax
901         ret
902 END(casueword32_nosmap)
903
904 ENTRY(casueword32_smap)
905         PUSH_FRAME_POINTER
906         movq    PCPU(CURPCB),%r8
907         movq    $fusufault,PCB_ONFAULT(%r8)
908
909         movq    $VM_MAXUSER_ADDRESS-4,%rax
910         cmpq    %rax,%rdi                       /* verify address is valid */
911         ja      fusufault
912
913         movl    %esi,%eax                       /* old */
914         stac
915 #ifdef SMP
916         lock
917 #endif
918         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
919         clac
920         setne   %cl
921
922         /*
923          * The old value is in %eax.  If the store succeeded it will be the
924          * value we expected (old) from before the store, otherwise it will
925          * be the current value.  Save %eax into %esi to prepare the return
926          * value.
927          */
928         movl    %eax,%esi
929         xorl    %eax,%eax
930         movq    %rax,PCB_ONFAULT(%r8)
931
932         /*
933          * Access the oldp after the pcb_onfault is cleared, to correctly
934          * catch corrupted pointer.
935          */
936         movl    %esi,(%rdx)                     /* oldp = %rdx */
937         POP_FRAME_POINTER
938         movzbl  %cl, %eax
939         ret
940 END(casueword32_smap)
941
942 /*
943  * casueword.  Compare and set user long.  Returns -1 on fault,
944  *        0 if access was successful.  Old value is written to *oldp.
945  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
946  */
947 ENTRY(casueword_nosmap)
948         PUSH_FRAME_POINTER
949         movq    PCPU(CURPCB),%r8
950         movq    $fusufault,PCB_ONFAULT(%r8)
951
952         movq    $VM_MAXUSER_ADDRESS-4,%rax
953         cmpq    %rax,%rdi                       /* verify address is valid */
954         ja      fusufault
955
956         movq    %rsi,%rax                       /* old */
957 #ifdef SMP
958         lock
959 #endif
960         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
961         setne   %cl
962
963         /*
964          * The old value is in %rax.  If the store succeeded it will be the
965          * value we expected (old) from before the store, otherwise it will
966          * be the current value.
967          */
968         movq    %rax,%rsi
969         xorl    %eax,%eax
970         movq    %rax,PCB_ONFAULT(%r8)
971         movq    %rsi,(%rdx)
972         POP_FRAME_POINTER
973         movzbl  %cl, %eax
974         ret
975 END(casueword_nosmap)
976
977 ENTRY(casueword_smap)
978         PUSH_FRAME_POINTER
979         movq    PCPU(CURPCB),%r8
980         movq    $fusufault,PCB_ONFAULT(%r8)
981
982         movq    $VM_MAXUSER_ADDRESS-4,%rax
983         cmpq    %rax,%rdi                       /* verify address is valid */
984         ja      fusufault
985
986         movq    %rsi,%rax                       /* old */
987         stac
988 #ifdef SMP
989         lock
990 #endif
991         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
992         clac
993         setne   %cl
994
995         /*
996          * The old value is in %rax.  If the store succeeded it will be the
997          * value we expected (old) from before the store, otherwise it will
998          * be the current value.
999          */
1000         movq    %rax,%rsi
1001         xorl    %eax,%eax
1002         movq    %rax,PCB_ONFAULT(%r8)
1003         movq    %rsi,(%rdx)
1004         POP_FRAME_POINTER
1005         movzbl  %cl, %eax
1006         ret
1007 END(casueword_smap)
1008
1009 /*
1010  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
1011  * byte from user memory.
1012  * addr = %rdi, valp = %rsi
1013  */
1014
1015 ENTRY(fueword_nosmap)
1016         PUSH_FRAME_POINTER
1017         movq    PCPU(CURPCB),%rcx
1018         movq    $fusufault,PCB_ONFAULT(%rcx)
1019
1020         movq    $VM_MAXUSER_ADDRESS-8,%rax
1021         cmpq    %rax,%rdi                       /* verify address is valid */
1022         ja      fusufault
1023
1024         xorl    %eax,%eax
1025         movq    (%rdi),%r11
1026         movq    %rax,PCB_ONFAULT(%rcx)
1027         movq    %r11,(%rsi)
1028         POP_FRAME_POINTER
1029         ret
1030 END(fueword_nosmap)
1031
1032 ENTRY(fueword_smap)
1033         PUSH_FRAME_POINTER
1034         movq    PCPU(CURPCB),%rcx
1035         movq    $fusufault,PCB_ONFAULT(%rcx)
1036
1037         movq    $VM_MAXUSER_ADDRESS-8,%rax
1038         cmpq    %rax,%rdi                       /* verify address is valid */
1039         ja      fusufault
1040
1041         xorl    %eax,%eax
1042         stac
1043         movq    (%rdi),%r11
1044         clac
1045         movq    %rax,PCB_ONFAULT(%rcx)
1046         movq    %r11,(%rsi)
1047         POP_FRAME_POINTER
1048         ret
1049 END(fueword_smap)
1050
1051 ENTRY(fueword32_nosmap)
1052         PUSH_FRAME_POINTER
1053         movq    PCPU(CURPCB),%rcx
1054         movq    $fusufault,PCB_ONFAULT(%rcx)
1055
1056         movq    $VM_MAXUSER_ADDRESS-4,%rax
1057         cmpq    %rax,%rdi                       /* verify address is valid */
1058         ja      fusufault
1059
1060         xorl    %eax,%eax
1061         movl    (%rdi),%r11d
1062         movq    %rax,PCB_ONFAULT(%rcx)
1063         movl    %r11d,(%rsi)
1064         POP_FRAME_POINTER
1065         ret
1066 END(fueword32_nosmap)
1067
1068 ENTRY(fueword32_smap)
1069         PUSH_FRAME_POINTER
1070         movq    PCPU(CURPCB),%rcx
1071         movq    $fusufault,PCB_ONFAULT(%rcx)
1072
1073         movq    $VM_MAXUSER_ADDRESS-4,%rax
1074         cmpq    %rax,%rdi                       /* verify address is valid */
1075         ja      fusufault
1076
1077         xorl    %eax,%eax
1078         stac
1079         movl    (%rdi),%r11d
1080         clac
1081         movq    %rax,PCB_ONFAULT(%rcx)
1082         movl    %r11d,(%rsi)
1083         POP_FRAME_POINTER
1084         ret
1085 END(fueword32_smap)
1086
1087 ENTRY(fuword16_nosmap)
1088         PUSH_FRAME_POINTER
1089         movq    PCPU(CURPCB),%rcx
1090         movq    $fusufault,PCB_ONFAULT(%rcx)
1091
1092         movq    $VM_MAXUSER_ADDRESS-2,%rax
1093         cmpq    %rax,%rdi
1094         ja      fusufault
1095
1096         movzwl  (%rdi),%eax
1097         movq    $0,PCB_ONFAULT(%rcx)
1098         POP_FRAME_POINTER
1099         ret
1100 END(fuword16_nosmap)
1101
1102 ENTRY(fuword16_smap)
1103         PUSH_FRAME_POINTER
1104         movq    PCPU(CURPCB),%rcx
1105         movq    $fusufault,PCB_ONFAULT(%rcx)
1106
1107         movq    $VM_MAXUSER_ADDRESS-2,%rax
1108         cmpq    %rax,%rdi
1109         ja      fusufault
1110
1111         stac
1112         movzwl  (%rdi),%eax
1113         clac
1114         movq    $0,PCB_ONFAULT(%rcx)
1115         POP_FRAME_POINTER
1116         ret
1117 END(fuword16_smap)
1118
1119 ENTRY(fubyte_nosmap)
1120         PUSH_FRAME_POINTER
1121         movq    PCPU(CURPCB),%rcx
1122         movq    $fusufault,PCB_ONFAULT(%rcx)
1123
1124         movq    $VM_MAXUSER_ADDRESS-1,%rax
1125         cmpq    %rax,%rdi
1126         ja      fusufault
1127
1128         movzbl  (%rdi),%eax
1129         movq    $0,PCB_ONFAULT(%rcx)
1130         POP_FRAME_POINTER
1131         ret
1132 END(fubyte_nosmap)
1133
1134 ENTRY(fubyte_smap)
1135         PUSH_FRAME_POINTER
1136         movq    PCPU(CURPCB),%rcx
1137         movq    $fusufault,PCB_ONFAULT(%rcx)
1138
1139         movq    $VM_MAXUSER_ADDRESS-1,%rax
1140         cmpq    %rax,%rdi
1141         ja      fusufault
1142
1143         stac
1144         movzbl  (%rdi),%eax
1145         clac
1146         movq    $0,PCB_ONFAULT(%rcx)
1147         POP_FRAME_POINTER
1148         ret
1149 END(fubyte_smap)
1150
1151 /*
1152  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
1153  * user memory.
1154  * addr = %rdi, value = %rsi
1155  */
1156 ENTRY(suword_nosmap)
1157         PUSH_FRAME_POINTER
1158         movq    PCPU(CURPCB),%rcx
1159         movq    $fusufault,PCB_ONFAULT(%rcx)
1160
1161         movq    $VM_MAXUSER_ADDRESS-8,%rax
1162         cmpq    %rax,%rdi                       /* verify address validity */
1163         ja      fusufault
1164
1165         movq    %rsi,(%rdi)
1166         xorl    %eax,%eax
1167         movq    %rax,PCB_ONFAULT(%rcx)
1168         POP_FRAME_POINTER
1169         ret
1170 END(suword_nosmap)
1171
1172 ENTRY(suword_smap)
1173         PUSH_FRAME_POINTER
1174         movq    PCPU(CURPCB),%rcx
1175         movq    $fusufault,PCB_ONFAULT(%rcx)
1176
1177         movq    $VM_MAXUSER_ADDRESS-8,%rax
1178         cmpq    %rax,%rdi                       /* verify address validity */
1179         ja      fusufault
1180
1181         stac
1182         movq    %rsi,(%rdi)
1183         clac
1184         xorl    %eax,%eax
1185         movq    %rax,PCB_ONFAULT(%rcx)
1186         POP_FRAME_POINTER
1187         ret
1188 END(suword_smap)
1189
1190 ENTRY(suword32_nosmap)
1191         PUSH_FRAME_POINTER
1192         movq    PCPU(CURPCB),%rcx
1193         movq    $fusufault,PCB_ONFAULT(%rcx)
1194
1195         movq    $VM_MAXUSER_ADDRESS-4,%rax
1196         cmpq    %rax,%rdi                       /* verify address validity */
1197         ja      fusufault
1198
1199         movl    %esi,(%rdi)
1200         xorl    %eax,%eax
1201         movq    %rax,PCB_ONFAULT(%rcx)
1202         POP_FRAME_POINTER
1203         ret
1204 END(suword32_nosmap)
1205
1206 ENTRY(suword32_smap)
1207         PUSH_FRAME_POINTER
1208         movq    PCPU(CURPCB),%rcx
1209         movq    $fusufault,PCB_ONFAULT(%rcx)
1210
1211         movq    $VM_MAXUSER_ADDRESS-4,%rax
1212         cmpq    %rax,%rdi                       /* verify address validity */
1213         ja      fusufault
1214
1215         stac
1216         movl    %esi,(%rdi)
1217         clac
1218         xorl    %eax,%eax
1219         movq    %rax,PCB_ONFAULT(%rcx)
1220         POP_FRAME_POINTER
1221         ret
1222 END(suword32_smap)
1223
1224 ENTRY(suword16_nosmap)
1225         PUSH_FRAME_POINTER
1226         movq    PCPU(CURPCB),%rcx
1227         movq    $fusufault,PCB_ONFAULT(%rcx)
1228
1229         movq    $VM_MAXUSER_ADDRESS-2,%rax
1230         cmpq    %rax,%rdi                       /* verify address validity */
1231         ja      fusufault
1232
1233         movw    %si,(%rdi)
1234         xorl    %eax,%eax
1235         movq    %rax,PCB_ONFAULT(%rcx)
1236         POP_FRAME_POINTER
1237         ret
1238 END(suword16_nosmap)
1239
1240 ENTRY(suword16_smap)
1241         PUSH_FRAME_POINTER
1242         movq    PCPU(CURPCB),%rcx
1243         movq    $fusufault,PCB_ONFAULT(%rcx)
1244
1245         movq    $VM_MAXUSER_ADDRESS-2,%rax
1246         cmpq    %rax,%rdi                       /* verify address validity */
1247         ja      fusufault
1248
1249         stac
1250         movw    %si,(%rdi)
1251         clac
1252         xorl    %eax,%eax
1253         movq    %rax,PCB_ONFAULT(%rcx)
1254         POP_FRAME_POINTER
1255         ret
1256 END(suword16_smap)
1257
1258 ENTRY(subyte_nosmap)
1259         PUSH_FRAME_POINTER
1260         movq    PCPU(CURPCB),%rcx
1261         movq    $fusufault,PCB_ONFAULT(%rcx)
1262
1263         movq    $VM_MAXUSER_ADDRESS-1,%rax
1264         cmpq    %rax,%rdi                       /* verify address validity */
1265         ja      fusufault
1266
1267         movl    %esi,%eax
1268         movb    %al,(%rdi)
1269         xorl    %eax,%eax
1270         movq    %rax,PCB_ONFAULT(%rcx)
1271         POP_FRAME_POINTER
1272         ret
1273 END(subyte_nosmap)
1274
1275 ENTRY(subyte_smap)
1276         PUSH_FRAME_POINTER
1277         movq    PCPU(CURPCB),%rcx
1278         movq    $fusufault,PCB_ONFAULT(%rcx)
1279
1280         movq    $VM_MAXUSER_ADDRESS-1,%rax
1281         cmpq    %rax,%rdi                       /* verify address validity */
1282         ja      fusufault
1283
1284         movl    %esi,%eax
1285         stac
1286         movb    %al,(%rdi)
1287         clac
1288         xorl    %eax,%eax
1289         movq    %rax,PCB_ONFAULT(%rcx)
1290         POP_FRAME_POINTER
1291         ret
1292 END(subyte_smap)
1293
1294         ALIGN_TEXT
1295         /* Fault entry clears PSL.AC */
1296 fusufault:
1297         movq    PCPU(CURPCB),%rcx
1298         xorl    %eax,%eax
1299         movq    %rax,PCB_ONFAULT(%rcx)
1300         decq    %rax
1301         POP_FRAME_POINTER
1302         ret
1303
1304 /*
1305  * copyinstr(from, to, maxlen, int *lencopied)
1306  *           %rdi, %rsi, %rdx, %rcx
1307  *
1308  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
1309  *      return ENAMETOOLONG if string is longer than maxlen, and
1310  *      EFAULT on protection violations. If lencopied is non-zero,
1311  *      return the actual length in *lencopied.
1312  */
1313 .macro COPYINSTR smap
1314         PUSH_FRAME_POINTER
1315         movq    %rdx,%r8                        /* %r8 = maxlen */
1316         movq    PCPU(CURPCB),%r9
1317         movq    $cpystrflt,PCB_ONFAULT(%r9)
1318
1319         movq    $VM_MAXUSER_ADDRESS,%rax
1320
1321         /* make sure 'from' is within bounds */
1322         subq    %rdi,%rax
1323         jbe     cpystrflt
1324
1325         SMAP_DISABLE \smap
1326
1327         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1328         cmpq    %rdx,%rax
1329         jb      8f
1330 1:
1331         incq    %rdx
1332 2:
1333         decq    %rdx
1334 .if \smap == 0
1335         jz      copyinstr_toolong
1336 .else
1337         jz      copyinstr_toolong_smap
1338 .endif
1339
1340         movb    (%rdi),%al
1341         movb    %al,(%rsi)
1342         incq    %rsi
1343         incq    %rdi
1344         testb   %al,%al
1345         jnz     2b
1346
1347         SMAP_ENABLE \smap
1348
1349         /* Success -- 0 byte reached */
1350         decq    %rdx
1351         xorl    %eax,%eax
1352
1353         /* set *lencopied and return %eax */
1354         movq    %rax,PCB_ONFAULT(%r9)
1355
1356         testq   %rcx,%rcx
1357         jz      3f
1358         subq    %rdx,%r8
1359         movq    %r8,(%rcx)
1360 3:
1361         POP_FRAME_POINTER
1362         ret
1363         ALIGN_TEXT
1364 8:
1365         movq    %rax,%rdx
1366         movq    %rax,%r8
1367         jmp 1b
1368
1369 .endm
1370
1371 ENTRY(copyinstr_nosmap)
1372         COPYINSTR smap=0
1373 END(copyinstr_nosmap)
1374
1375 ENTRY(copyinstr_smap)
1376         COPYINSTR smap=1
1377 END(copyinstr_smap)
1378
1379 cpystrflt:
1380         /* Fault entry clears PSL.AC */
1381         movl    $EFAULT,%eax
1382 cpystrflt_x:
1383         /* set *lencopied and return %eax */
1384         movq    $0,PCB_ONFAULT(%r9)
1385
1386         testq   %rcx,%rcx
1387         jz      1f
1388         subq    %rdx,%r8
1389         movq    %r8,(%rcx)
1390 1:
1391         POP_FRAME_POINTER
1392         ret
1393
1394 copyinstr_toolong_smap:
1395         clac
1396 copyinstr_toolong:
1397         /* rdx is zero - return ENAMETOOLONG or EFAULT */
1398         movq    $VM_MAXUSER_ADDRESS,%rax
1399         cmpq    %rax,%rdi
1400         jae     cpystrflt
1401         movl    $ENAMETOOLONG,%eax
1402         jmp     cpystrflt_x
1403
1404 /*
1405  * Handling of special amd64 registers and descriptor tables etc
1406  */
1407 /* void lgdt(struct region_descriptor *rdp); */
1408 ENTRY(lgdt)
1409         /* reload the descriptor table */
1410         lgdt    (%rdi)
1411
1412         /* flush the prefetch q */
1413         jmp     1f
1414         nop
1415 1:
1416         movl    $KDSEL,%eax
1417         movl    %eax,%ds
1418         movl    %eax,%es
1419         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
1420         movl    %eax,%gs
1421         movl    %eax,%ss
1422
1423         /* reload code selector by turning return into intersegmental return */
1424         popq    %rax
1425         pushq   $KCSEL
1426         pushq   %rax
1427         MEXITCOUNT
1428         lretq
1429 END(lgdt)
1430
1431 /*****************************************************************************/
1432 /* setjump, longjump                                                         */
1433 /*****************************************************************************/
1434
1435 ENTRY(setjmp)
1436         movq    %rbx,0(%rdi)                    /* save rbx */
1437         movq    %rsp,8(%rdi)                    /* save rsp */
1438         movq    %rbp,16(%rdi)                   /* save rbp */
1439         movq    %r12,24(%rdi)                   /* save r12 */
1440         movq    %r13,32(%rdi)                   /* save r13 */
1441         movq    %r14,40(%rdi)                   /* save r14 */
1442         movq    %r15,48(%rdi)                   /* save r15 */
1443         movq    0(%rsp),%rdx                    /* get rta */
1444         movq    %rdx,56(%rdi)                   /* save rip */
1445         xorl    %eax,%eax                       /* return(0); */
1446         ret
1447 END(setjmp)
1448
1449 ENTRY(longjmp)
1450         movq    0(%rdi),%rbx                    /* restore rbx */
1451         movq    8(%rdi),%rsp                    /* restore rsp */
1452         movq    16(%rdi),%rbp                   /* restore rbp */
1453         movq    24(%rdi),%r12                   /* restore r12 */
1454         movq    32(%rdi),%r13                   /* restore r13 */
1455         movq    40(%rdi),%r14                   /* restore r14 */
1456         movq    48(%rdi),%r15                   /* restore r15 */
1457         movq    56(%rdi),%rdx                   /* get rta */
1458         movq    %rdx,0(%rsp)                    /* put in return frame */
1459         xorl    %eax,%eax                       /* return(1); */
1460         incl    %eax
1461         ret
1462 END(longjmp)
1463
1464 /*
1465  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
1466  * return an error.)
1467  */
1468 ENTRY(rdmsr_safe)
1469 /* int rdmsr_safe(u_int msr, uint64_t *data) */
1470         PUSH_FRAME_POINTER
1471         movq    PCPU(CURPCB),%r8
1472         movq    $msr_onfault,PCB_ONFAULT(%r8)
1473         movl    %edi,%ecx
1474         rdmsr                   /* Read MSR pointed by %ecx. Returns
1475                                    hi byte in edx, lo in %eax */
1476         salq    $32,%rdx        /* sign-shift %rdx left */
1477         movl    %eax,%eax       /* zero-extend %eax -> %rax */
1478         orq     %rdx,%rax
1479         movq    %rax,(%rsi)
1480         xorq    %rax,%rax
1481         movq    %rax,PCB_ONFAULT(%r8)
1482         POP_FRAME_POINTER
1483         ret
1484
1485 /*
1486  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
1487  * return an error.)
1488  */
1489 ENTRY(wrmsr_safe)
1490 /* int wrmsr_safe(u_int msr, uint64_t data) */
1491         PUSH_FRAME_POINTER
1492         movq    PCPU(CURPCB),%r8
1493         movq    $msr_onfault,PCB_ONFAULT(%r8)
1494         movl    %edi,%ecx
1495         movl    %esi,%eax
1496         sarq    $32,%rsi
1497         movl    %esi,%edx
1498         wrmsr                   /* Write MSR pointed by %ecx. Accepts
1499                                    hi byte in edx, lo in %eax. */
1500         xorq    %rax,%rax
1501         movq    %rax,PCB_ONFAULT(%r8)
1502         POP_FRAME_POINTER
1503         ret
1504
1505 /*
1506  * MSR operations fault handler
1507  */
1508         ALIGN_TEXT
1509 msr_onfault:
1510         movq    $0,PCB_ONFAULT(%r8)
1511         movl    $EFAULT,%eax
1512         POP_FRAME_POINTER
1513         ret
1514
1515 /*
1516  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
1517  * Invalidates address space addressed by ucr3, then returns to kcr3.
1518  * Done in assembler to ensure no other memory accesses happen while
1519  * on ucr3.
1520  */
1521         ALIGN_TEXT
1522 ENTRY(pmap_pti_pcid_invalidate)
1523         pushfq
1524         cli
1525         movq    %rdi,%cr3       /* to user page table */
1526         movq    %rsi,%cr3       /* back to kernel */
1527         popfq
1528         retq
1529
1530 /*
1531  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
1532  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
1533  */
1534         ALIGN_TEXT
1535 ENTRY(pmap_pti_pcid_invlpg)
1536         pushfq
1537         cli
1538         movq    %rdi,%cr3       /* to user page table */
1539         invlpg  (%rdx)
1540         movq    %rsi,%cr3       /* back to kernel */
1541         popfq
1542         retq
1543
1544 /*
1545  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
1546  *     vm_offset_t eva);
1547  * Invalidates virtual addresses between sva and eva in address space ucr3,
1548  * then returns to kcr3.
1549  */
1550         ALIGN_TEXT
1551 ENTRY(pmap_pti_pcid_invlrng)
1552         pushfq
1553         cli
1554         movq    %rdi,%cr3       /* to user page table */
1555 1:      invlpg  (%rdx)
1556         addq    $PAGE_SIZE,%rdx
1557         cmpq    %rdx,%rcx
1558         ja      1b
1559         movq    %rsi,%cr3       /* back to kernel */
1560         popfq
1561         retq
1562
1563         .altmacro
1564         .macro  rsb_seq_label l
1565 rsb_seq_\l:
1566         .endm
1567         .macro  rsb_call_label l
1568         call    rsb_seq_\l
1569         .endm
1570         .macro  rsb_seq count
1571         ll=1
1572         .rept   \count
1573         rsb_call_label  %(ll)
1574         nop
1575         rsb_seq_label %(ll)
1576         addq    $8,%rsp
1577         ll=ll+1
1578         .endr
1579         .endm
1580
1581 ENTRY(rsb_flush)
1582         rsb_seq 32
1583         ret
1584
1585 /* all callers already saved %rax, %rdx, and %rcx */
1586 ENTRY(handle_ibrs_entry)
1587         cmpb    $0,hw_ibrs_ibpb_active(%rip)
1588         je      1f
1589         movl    $MSR_IA32_SPEC_CTRL,%ecx
1590         rdmsr
1591         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1592         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
1593         wrmsr
1594         movb    $1,PCPU(IBPB_SET)
1595         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
1596         je      rsb_flush
1597 1:      ret
1598 END(handle_ibrs_entry)
1599
1600 ENTRY(handle_ibrs_exit)
1601         cmpb    $0,PCPU(IBPB_SET)
1602         je      1f
1603         movl    $MSR_IA32_SPEC_CTRL,%ecx
1604         rdmsr
1605         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1606         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1607         wrmsr
1608         movb    $0,PCPU(IBPB_SET)
1609 1:      ret
1610 END(handle_ibrs_exit)
1611
1612 /* registers-neutral version, but needs stack */
1613 ENTRY(handle_ibrs_exit_rs)
1614         cmpb    $0,PCPU(IBPB_SET)
1615         je      1f
1616         pushq   %rax
1617         pushq   %rdx
1618         pushq   %rcx
1619         movl    $MSR_IA32_SPEC_CTRL,%ecx
1620         rdmsr
1621         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1622         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1623         wrmsr
1624         popq    %rcx
1625         popq    %rdx
1626         popq    %rax
1627         movb    $0,PCPU(IBPB_SET)
1628 1:      ret
1629 END(handle_ibrs_exit_rs)
1630
1631         .noaltmacro
1632
1633 /*
1634  * Flush L1D cache.  Load enough of the data from the kernel text
1635  * to flush existing L1D content.
1636  *
1637  * N.B. The function does not follow ABI calling conventions, it corrupts %rbx.
1638  * The vmm.ko caller expects that only %rax, %rdx, %rbx, %rcx, %r9, and %rflags
1639  * registers are clobbered.  The NMI handler caller only needs %r13 and %r15
1640  * preserved.
1641  */
1642 ENTRY(flush_l1d_sw)
1643 #define L1D_FLUSH_SIZE  (64 * 1024)
1644         movq    $KERNBASE, %r9
1645         movq    $-L1D_FLUSH_SIZE, %rcx
1646         /*
1647          * pass 1: Preload TLB.
1648          * Kernel text is mapped using superpages.  TLB preload is
1649          * done for the benefit of older CPUs which split 2M page
1650          * into 4k TLB entries.
1651          */
1652 1:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1653         addq    $PAGE_SIZE, %rcx
1654         jne     1b
1655         xorl    %eax, %eax
1656         cpuid
1657         movq    $-L1D_FLUSH_SIZE, %rcx
1658         /* pass 2: Read each cache line. */
1659 2:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1660         addq    $64, %rcx
1661         jne     2b
1662         lfence
1663         ret
1664 #undef  L1D_FLUSH_SIZE
1665 END(flush_l1d_sw)
1666
1667 ENTRY(flush_l1d_sw_abi)
1668         pushq   %rbx
1669         call    flush_l1d_sw
1670         popq    %rbx
1671         ret
1672 END(flush_l1d_sw_abi)
1673
1674 ENTRY(mds_handler_void)
1675         retq
1676 END(mds_handler_void)
1677
1678 ENTRY(mds_handler_verw)
1679         subq    $8, %rsp
1680         movw    %ds, (%rsp)
1681         verw    (%rsp)
1682         addq    $8, %rsp
1683         retq
1684 END(mds_handler_verw)
1685
1686 ENTRY(mds_handler_ivb)
1687         pushq   %rax
1688         pushq   %rdx
1689         pushq   %rcx
1690
1691         movq    %cr0, %rax
1692         testb   $CR0_TS, %al
1693         je      1f
1694         clts
1695 1:      movq    PCPU(MDS_BUF), %rdx
1696         movdqa  %xmm0, PCPU(MDS_TMP)
1697         pxor    %xmm0, %xmm0
1698
1699         lfence
1700         orpd    (%rdx), %xmm0
1701         orpd    (%rdx), %xmm0
1702         mfence
1703         movl    $40, %ecx
1704         addq    $16, %rdx
1705 2:      movntdq %xmm0, (%rdx)
1706         addq    $16, %rdx
1707         decl    %ecx
1708         jnz     2b
1709         mfence
1710
1711         movdqa  PCPU(MDS_TMP),%xmm0
1712         testb   $CR0_TS, %al
1713         je      3f
1714         movq    %rax, %cr0
1715 3:      popq    %rcx
1716         popq    %rdx
1717         popq    %rax
1718         retq
1719 END(mds_handler_ivb)
1720
1721 ENTRY(mds_handler_bdw)
1722         pushq   %rax
1723         pushq   %rbx
1724         pushq   %rcx
1725         pushq   %rdi
1726         pushq   %rsi
1727
1728         movq    %cr0, %rax
1729         testb   $CR0_TS, %al
1730         je      1f
1731         clts
1732 1:      movq    PCPU(MDS_BUF), %rbx
1733         movdqa  %xmm0, PCPU(MDS_TMP)
1734         pxor    %xmm0, %xmm0
1735
1736         movq    %rbx, %rdi
1737         movq    %rbx, %rsi
1738         movl    $40, %ecx
1739 2:      movntdq %xmm0, (%rbx)
1740         addq    $16, %rbx
1741         decl    %ecx
1742         jnz     2b
1743         mfence
1744         movl    $1536, %ecx
1745         rep; movsb
1746         lfence
1747
1748         movdqa  PCPU(MDS_TMP),%xmm0
1749         testb   $CR0_TS, %al
1750         je      3f
1751         movq    %rax, %cr0
1752 3:      popq    %rsi
1753         popq    %rdi
1754         popq    %rcx
1755         popq    %rbx
1756         popq    %rax
1757         retq
1758 END(mds_handler_bdw)
1759
1760 ENTRY(mds_handler_skl_sse)
1761         pushq   %rax
1762         pushq   %rdx
1763         pushq   %rcx
1764         pushq   %rdi
1765
1766         movq    %cr0, %rax
1767         testb   $CR0_TS, %al
1768         je      1f
1769         clts
1770 1:      movq    PCPU(MDS_BUF), %rdi
1771         movq    PCPU(MDS_BUF64), %rdx
1772         movdqa  %xmm0, PCPU(MDS_TMP)
1773         pxor    %xmm0, %xmm0
1774
1775         lfence
1776         orpd    (%rdx), %xmm0
1777         orpd    (%rdx), %xmm0
1778         xorl    %eax, %eax
1779 2:      clflushopt      5376(%rdi, %rax, 8)
1780         addl    $8, %eax
1781         cmpl    $8 * 12, %eax
1782         jb      2b
1783         sfence
1784         movl    $6144, %ecx
1785         xorl    %eax, %eax
1786         rep; stosb
1787         mfence
1788
1789         movdqa  PCPU(MDS_TMP), %xmm0
1790         testb   $CR0_TS, %al
1791         je      3f
1792         movq    %rax, %cr0
1793 3:      popq    %rdi
1794         popq    %rcx
1795         popq    %rdx
1796         popq    %rax
1797         retq
1798 END(mds_handler_skl_sse)
1799
1800 ENTRY(mds_handler_skl_avx)
1801         pushq   %rax
1802         pushq   %rdx
1803         pushq   %rcx
1804         pushq   %rdi
1805
1806         movq    %cr0, %rax
1807         testb   $CR0_TS, %al
1808         je      1f
1809         clts
1810 1:      movq    PCPU(MDS_BUF), %rdi
1811         movq    PCPU(MDS_BUF64), %rdx
1812         vmovdqa %ymm0, PCPU(MDS_TMP)
1813         vpxor   %ymm0, %ymm0, %ymm0
1814
1815         lfence
1816         vorpd   (%rdx), %ymm0, %ymm0
1817         vorpd   (%rdx), %ymm0, %ymm0
1818         xorl    %eax, %eax
1819 2:      clflushopt      5376(%rdi, %rax, 8)
1820         addl    $8, %eax
1821         cmpl    $8 * 12, %eax
1822         jb      2b
1823         sfence
1824         movl    $6144, %ecx
1825         xorl    %eax, %eax
1826         rep; stosb
1827         mfence
1828
1829         vmovdqa PCPU(MDS_TMP), %ymm0
1830         testb   $CR0_TS, %al
1831         je      3f
1832         movq    %rax, %cr0
1833 3:      popq    %rdi
1834         popq    %rcx
1835         popq    %rdx
1836         popq    %rax
1837         retq
1838 END(mds_handler_skl_avx)
1839
1840 ENTRY(mds_handler_skl_avx512)
1841         pushq   %rax
1842         pushq   %rdx
1843         pushq   %rcx
1844         pushq   %rdi
1845
1846         movq    %cr0, %rax
1847         testb   $CR0_TS, %al
1848         je      1f
1849         clts
1850 1:      movq    PCPU(MDS_BUF), %rdi
1851         movq    PCPU(MDS_BUF64), %rdx
1852         vmovdqa64       %zmm0, PCPU(MDS_TMP)
1853         vpxord  %zmm0, %zmm0, %zmm0
1854
1855         lfence
1856         vorpd   (%rdx), %zmm0, %zmm0
1857         vorpd   (%rdx), %zmm0, %zmm0
1858         xorl    %eax, %eax
1859 2:      clflushopt      5376(%rdi, %rax, 8)
1860         addl    $8, %eax
1861         cmpl    $8 * 12, %eax
1862         jb      2b
1863         sfence
1864         movl    $6144, %ecx
1865         xorl    %eax, %eax
1866         rep; stosb
1867         mfence
1868
1869         vmovdqa64       PCPU(MDS_TMP), %zmm0
1870         testb   $CR0_TS, %al
1871         je      3f
1872         movq    %rax, %cr0
1873 3:      popq    %rdi
1874         popq    %rcx
1875         popq    %rdx
1876         popq    %rax
1877         retq
1878 END(mds_handler_skl_avx512)
1879
1880 ENTRY(mds_handler_silvermont)
1881         pushq   %rax
1882         pushq   %rdx
1883         pushq   %rcx
1884
1885         movq    %cr0, %rax
1886         testb   $CR0_TS, %al
1887         je      1f
1888         clts
1889 1:      movq    PCPU(MDS_BUF), %rdx
1890         movdqa  %xmm0, PCPU(MDS_TMP)
1891         pxor    %xmm0, %xmm0
1892
1893         movl    $16, %ecx
1894 2:      movntdq %xmm0, (%rdx)
1895         addq    $16, %rdx
1896         decl    %ecx
1897         jnz     2b
1898         mfence
1899
1900         movdqa  PCPU(MDS_TMP),%xmm0
1901         testb   $CR0_TS, %al
1902         je      3f
1903         movq    %rax, %cr0
1904 3:      popq    %rcx
1905         popq    %rdx
1906         popq    %rax
1907         retq
1908 END(mds_handler_silvermont)