]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
amd64: implement strlen in assembly, take 2
[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  * strlen(string)
702  *        %rdi
703  *
704  * Uses the ((x - 0x01....01) & ~x & 0x80....80) trick.
705  *
706  * 0x01....01 is replaced with 0x0 - 0x01....01 so that it can be added
707  * with leaq.
708  *
709  * For a description see either:
710  * - "Hacker's Delight" by Henry S. Warren, Jr.
711  * - "Optimizing subroutines in assembly language: An optimization guide for x86 platforms"
712  *   by Agner Fog
713  *
714  * The latter contains a 32-bit variant of the same algorithm coded in assembly for i386.
715  */
716 ENTRY(strlen)
717         PUSH_FRAME_POINTER
718         movabsq $0xfefefefefefefeff,%r8
719         movabsq $0x8080808080808080,%r9
720
721         movq    %rdi,%r10
722         movq    %rdi,%rcx
723         testb   $7,%dil
724         jz      2f
725
726         /*
727          * Handle misaligned reads: align to 8 and fill
728          * the spurious bytes.
729          */
730         andq    $~7,%rdi
731         movq    (%rdi),%r11
732         shlq    $3,%rcx
733         movq    $-1,%rdx
734         shlq    %cl,%rdx
735         notq    %rdx
736         orq     %rdx,%r11
737
738         leaq    (%r11,%r8),%rcx
739         notq    %r11
740         andq    %r11,%rcx
741         andq    %r9,%rcx
742         jnz     3f
743
744         /*
745          * Main loop.
746          */
747         ALIGN_TEXT
748 1:
749         leaq    8(%rdi),%rdi
750 2:
751         movq    (%rdi),%r11
752         leaq    (%r11,%r8),%rcx
753         notq    %r11
754         andq    %r11,%rcx
755         andq    %r9,%rcx
756         jz      1b
757 3:
758         bsfq    %rcx,%rcx
759         shrq    $3,%rcx
760         leaq    (%rcx,%rdi),%rax
761         subq    %r10,%rax
762         POP_FRAME_POINTER
763         ret
764 END(strlen)
765
766 /*****************************************************************************/
767 /* copyout and fubyte family                                                 */
768 /*****************************************************************************/
769 /*
770  * Access user memory from inside the kernel. These routines should be
771  * the only places that do this.
772  *
773  * These routines set curpcb->pcb_onfault for the time they execute. When a
774  * protection violation occurs inside the functions, the trap handler
775  * returns to *curpcb->pcb_onfault instead of the function.
776  */
777
778 .macro SMAP_DISABLE smap
779 .if     \smap
780         stac
781 .endif
782 .endm
783
784
785 .macro SMAP_ENABLE smap
786 .if     \smap
787         clac
788 .endif
789 .endm
790
791 .macro COPYINOUT_BEGIN
792 .endm
793
794 .macro COPYINOUT_END
795         movq    %rax,PCB_ONFAULT(%r11)
796         POP_FRAME_POINTER
797 .endm
798
799 .macro COPYINOUT_SMAP_END
800         SMAP_ENABLE smap=1
801         COPYINOUT_END
802 .endm
803
804 /*
805  * copyout(from_kernel, to_user, len)
806  *         %rdi,        %rsi,    %rdx
807  */
808 .macro  COPYOUT smap erms
809         PUSH_FRAME_POINTER
810         movq    PCPU(CURPCB),%r11
811         movq    $copy_fault,PCB_ONFAULT(%r11)
812
813         /*
814          * Check explicitly for non-user addresses.
815          * First, prevent address wrapping.
816          */
817         movq    %rsi,%rax
818         addq    %rdx,%rax
819         jc      copy_fault
820 /*
821  * XXX STOP USING VM_MAXUSER_ADDRESS.
822  * It is an end address, not a max, so every time it is used correctly it
823  * looks like there is an off by one error, and of course it caused an off
824  * by one error in several places.
825  */
826         movq    $VM_MAXUSER_ADDRESS,%rcx
827         cmpq    %rcx,%rax
828         ja      copy_fault
829
830         /*
831          * Set return value to zero. Remaining failure mode goes through
832          * copy_fault.
833          */
834         xorl    %eax,%eax
835
836         /*
837          * Set up arguments for MEMMOVE.
838          */
839         movq    %rdi,%r8
840         movq    %rsi,%rdi
841         movq    %r8,%rsi
842         movq    %rdx,%rcx
843
844
845         SMAP_DISABLE \smap
846 .if     \smap == 1
847         MEMMOVE erms=\erms overlap=0 begin=COPYINOUT_BEGIN end=COPYINOUT_SMAP_END
848 .else
849         MEMMOVE erms=\erms overlap=0 begin=COPYINOUT_BEGIN end=COPYINOUT_END
850 .endif
851         /* NOTREACHED */
852 .endm
853
854 ENTRY(copyout_nosmap_std)
855         COPYOUT smap=0 erms=0
856 END(copyout_nosmap_std)
857
858 ENTRY(copyout_smap_std)
859         COPYOUT smap=1 erms=0
860 END(copyout_smap_std)
861
862 ENTRY(copyout_nosmap_erms)
863         COPYOUT smap=0 erms=1
864 END(copyout_nosmap_erms)
865
866 ENTRY(copyout_smap_erms)
867         COPYOUT smap=1 erms=1
868 END(copyout_smap_erms)
869
870 /*
871  * copyin(from_user, to_kernel, len)
872  *        %rdi,      %rsi,      %rdx
873  */
874 .macro  COPYIN smap erms
875         PUSH_FRAME_POINTER
876         movq    PCPU(CURPCB),%r11
877         movq    $copy_fault,PCB_ONFAULT(%r11)
878
879         /*
880          * make sure address is valid
881          */
882         movq    %rdi,%rax
883         addq    %rdx,%rax
884         jc      copy_fault
885         movq    $VM_MAXUSER_ADDRESS,%rcx
886         cmpq    %rcx,%rax
887         ja      copy_fault
888
889         xorl    %eax,%eax
890
891         movq    %rdi,%r8
892         movq    %rsi,%rdi
893         movq    %r8,%rsi
894         movq    %rdx,%rcx
895
896         SMAP_DISABLE \smap
897 .if     \smap == 1
898         MEMMOVE erms=\erms overlap=0 begin=COPYINOUT_BEGIN end=COPYINOUT_SMAP_END
899 .else
900         MEMMOVE erms=\erms overlap=0 begin=COPYINOUT_BEGIN end=COPYINOUT_END
901 .endif
902         /* NOTREACHED */
903 .endm
904
905 ENTRY(copyin_nosmap_std)
906         COPYIN smap=0 erms=0
907 END(copyin_nosmap_std)
908
909 ENTRY(copyin_smap_std)
910         COPYIN smap=1 erms=0
911 END(copyin_smap_std)
912
913 ENTRY(copyin_nosmap_erms)
914         COPYIN smap=0 erms=1
915 END(copyin_nosmap_erms)
916
917 ENTRY(copyin_smap_erms)
918         COPYIN smap=1 erms=1
919 END(copyin_smap_erms)
920
921         ALIGN_TEXT
922         /* Trap entry clears PSL.AC */
923 copy_fault:
924         movq    $0,PCB_ONFAULT(%r11)
925         movl    $EFAULT,%eax
926         POP_FRAME_POINTER
927         ret
928
929 /*
930  * casueword32.  Compare and set user integer.  Returns -1 on fault,
931  *        0 if access was successful.  Old value is written to *oldp.
932  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
933  */
934 ENTRY(casueword32_nosmap)
935         PUSH_FRAME_POINTER
936         movq    PCPU(CURPCB),%r8
937         movq    $fusufault,PCB_ONFAULT(%r8)
938
939         movq    $VM_MAXUSER_ADDRESS-4,%rax
940         cmpq    %rax,%rdi                       /* verify address is valid */
941         ja      fusufault
942
943         movl    %esi,%eax                       /* old */
944 #ifdef SMP
945         lock
946 #endif
947         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
948         setne   %cl
949
950         /*
951          * The old value is in %eax.  If the store succeeded it will be the
952          * value we expected (old) from before the store, otherwise it will
953          * be the current value.  Save %eax into %esi to prepare the return
954          * value.
955          */
956         movl    %eax,%esi
957         xorl    %eax,%eax
958         movq    %rax,PCB_ONFAULT(%r8)
959
960         /*
961          * Access the oldp after the pcb_onfault is cleared, to correctly
962          * catch corrupted pointer.
963          */
964         movl    %esi,(%rdx)                     /* oldp = %rdx */
965         POP_FRAME_POINTER
966         movzbl  %cl, %eax
967         ret
968 END(casueword32_nosmap)
969
970 ENTRY(casueword32_smap)
971         PUSH_FRAME_POINTER
972         movq    PCPU(CURPCB),%r8
973         movq    $fusufault,PCB_ONFAULT(%r8)
974
975         movq    $VM_MAXUSER_ADDRESS-4,%rax
976         cmpq    %rax,%rdi                       /* verify address is valid */
977         ja      fusufault
978
979         movl    %esi,%eax                       /* old */
980         stac
981 #ifdef SMP
982         lock
983 #endif
984         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
985         clac
986         setne   %cl
987
988         /*
989          * The old value is in %eax.  If the store succeeded it will be the
990          * value we expected (old) from before the store, otherwise it will
991          * be the current value.  Save %eax into %esi to prepare the return
992          * value.
993          */
994         movl    %eax,%esi
995         xorl    %eax,%eax
996         movq    %rax,PCB_ONFAULT(%r8)
997
998         /*
999          * Access the oldp after the pcb_onfault is cleared, to correctly
1000          * catch corrupted pointer.
1001          */
1002         movl    %esi,(%rdx)                     /* oldp = %rdx */
1003         POP_FRAME_POINTER
1004         movzbl  %cl, %eax
1005         ret
1006 END(casueword32_smap)
1007
1008 /*
1009  * casueword.  Compare and set user long.  Returns -1 on fault,
1010  *        0 if access was successful.  Old value is written to *oldp.
1011  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
1012  */
1013 ENTRY(casueword_nosmap)
1014         PUSH_FRAME_POINTER
1015         movq    PCPU(CURPCB),%r8
1016         movq    $fusufault,PCB_ONFAULT(%r8)
1017
1018         movq    $VM_MAXUSER_ADDRESS-4,%rax
1019         cmpq    %rax,%rdi                       /* verify address is valid */
1020         ja      fusufault
1021
1022         movq    %rsi,%rax                       /* old */
1023 #ifdef SMP
1024         lock
1025 #endif
1026         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
1027         setne   %cl
1028
1029         /*
1030          * The old value is in %rax.  If the store succeeded it will be the
1031          * value we expected (old) from before the store, otherwise it will
1032          * be the current value.
1033          */
1034         movq    %rax,%rsi
1035         xorl    %eax,%eax
1036         movq    %rax,PCB_ONFAULT(%r8)
1037         movq    %rsi,(%rdx)
1038         POP_FRAME_POINTER
1039         movzbl  %cl, %eax
1040         ret
1041 END(casueword_nosmap)
1042
1043 ENTRY(casueword_smap)
1044         PUSH_FRAME_POINTER
1045         movq    PCPU(CURPCB),%r8
1046         movq    $fusufault,PCB_ONFAULT(%r8)
1047
1048         movq    $VM_MAXUSER_ADDRESS-4,%rax
1049         cmpq    %rax,%rdi                       /* verify address is valid */
1050         ja      fusufault
1051
1052         movq    %rsi,%rax                       /* old */
1053         stac
1054 #ifdef SMP
1055         lock
1056 #endif
1057         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
1058         clac
1059         setne   %cl
1060
1061         /*
1062          * The old value is in %rax.  If the store succeeded it will be the
1063          * value we expected (old) from before the store, otherwise it will
1064          * be the current value.
1065          */
1066         movq    %rax,%rsi
1067         xorl    %eax,%eax
1068         movq    %rax,PCB_ONFAULT(%r8)
1069         movq    %rsi,(%rdx)
1070         POP_FRAME_POINTER
1071         movzbl  %cl, %eax
1072         ret
1073 END(casueword_smap)
1074
1075 /*
1076  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
1077  * byte from user memory.
1078  * addr = %rdi, valp = %rsi
1079  */
1080
1081 ENTRY(fueword_nosmap)
1082         PUSH_FRAME_POINTER
1083         movq    PCPU(CURPCB),%rcx
1084         movq    $fusufault,PCB_ONFAULT(%rcx)
1085
1086         movq    $VM_MAXUSER_ADDRESS-8,%rax
1087         cmpq    %rax,%rdi                       /* verify address is valid */
1088         ja      fusufault
1089
1090         xorl    %eax,%eax
1091         movq    (%rdi),%r11
1092         movq    %rax,PCB_ONFAULT(%rcx)
1093         movq    %r11,(%rsi)
1094         POP_FRAME_POINTER
1095         ret
1096 END(fueword_nosmap)
1097
1098 ENTRY(fueword_smap)
1099         PUSH_FRAME_POINTER
1100         movq    PCPU(CURPCB),%rcx
1101         movq    $fusufault,PCB_ONFAULT(%rcx)
1102
1103         movq    $VM_MAXUSER_ADDRESS-8,%rax
1104         cmpq    %rax,%rdi                       /* verify address is valid */
1105         ja      fusufault
1106
1107         xorl    %eax,%eax
1108         stac
1109         movq    (%rdi),%r11
1110         clac
1111         movq    %rax,PCB_ONFAULT(%rcx)
1112         movq    %r11,(%rsi)
1113         POP_FRAME_POINTER
1114         ret
1115 END(fueword_smap)
1116
1117 ENTRY(fueword32_nosmap)
1118         PUSH_FRAME_POINTER
1119         movq    PCPU(CURPCB),%rcx
1120         movq    $fusufault,PCB_ONFAULT(%rcx)
1121
1122         movq    $VM_MAXUSER_ADDRESS-4,%rax
1123         cmpq    %rax,%rdi                       /* verify address is valid */
1124         ja      fusufault
1125
1126         xorl    %eax,%eax
1127         movl    (%rdi),%r11d
1128         movq    %rax,PCB_ONFAULT(%rcx)
1129         movl    %r11d,(%rsi)
1130         POP_FRAME_POINTER
1131         ret
1132 END(fueword32_nosmap)
1133
1134 ENTRY(fueword32_smap)
1135         PUSH_FRAME_POINTER
1136         movq    PCPU(CURPCB),%rcx
1137         movq    $fusufault,PCB_ONFAULT(%rcx)
1138
1139         movq    $VM_MAXUSER_ADDRESS-4,%rax
1140         cmpq    %rax,%rdi                       /* verify address is valid */
1141         ja      fusufault
1142
1143         xorl    %eax,%eax
1144         stac
1145         movl    (%rdi),%r11d
1146         clac
1147         movq    %rax,PCB_ONFAULT(%rcx)
1148         movl    %r11d,(%rsi)
1149         POP_FRAME_POINTER
1150         ret
1151 END(fueword32_smap)
1152
1153 ENTRY(fuword16_nosmap)
1154         PUSH_FRAME_POINTER
1155         movq    PCPU(CURPCB),%rcx
1156         movq    $fusufault,PCB_ONFAULT(%rcx)
1157
1158         movq    $VM_MAXUSER_ADDRESS-2,%rax
1159         cmpq    %rax,%rdi
1160         ja      fusufault
1161
1162         movzwl  (%rdi),%eax
1163         movq    $0,PCB_ONFAULT(%rcx)
1164         POP_FRAME_POINTER
1165         ret
1166 END(fuword16_nosmap)
1167
1168 ENTRY(fuword16_smap)
1169         PUSH_FRAME_POINTER
1170         movq    PCPU(CURPCB),%rcx
1171         movq    $fusufault,PCB_ONFAULT(%rcx)
1172
1173         movq    $VM_MAXUSER_ADDRESS-2,%rax
1174         cmpq    %rax,%rdi
1175         ja      fusufault
1176
1177         stac
1178         movzwl  (%rdi),%eax
1179         clac
1180         movq    $0,PCB_ONFAULT(%rcx)
1181         POP_FRAME_POINTER
1182         ret
1183 END(fuword16_smap)
1184
1185 ENTRY(fubyte_nosmap)
1186         PUSH_FRAME_POINTER
1187         movq    PCPU(CURPCB),%rcx
1188         movq    $fusufault,PCB_ONFAULT(%rcx)
1189
1190         movq    $VM_MAXUSER_ADDRESS-1,%rax
1191         cmpq    %rax,%rdi
1192         ja      fusufault
1193
1194         movzbl  (%rdi),%eax
1195         movq    $0,PCB_ONFAULT(%rcx)
1196         POP_FRAME_POINTER
1197         ret
1198 END(fubyte_nosmap)
1199
1200 ENTRY(fubyte_smap)
1201         PUSH_FRAME_POINTER
1202         movq    PCPU(CURPCB),%rcx
1203         movq    $fusufault,PCB_ONFAULT(%rcx)
1204
1205         movq    $VM_MAXUSER_ADDRESS-1,%rax
1206         cmpq    %rax,%rdi
1207         ja      fusufault
1208
1209         stac
1210         movzbl  (%rdi),%eax
1211         clac
1212         movq    $0,PCB_ONFAULT(%rcx)
1213         POP_FRAME_POINTER
1214         ret
1215 END(fubyte_smap)
1216
1217 /*
1218  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
1219  * user memory.
1220  * addr = %rdi, value = %rsi
1221  */
1222 ENTRY(suword_nosmap)
1223         PUSH_FRAME_POINTER
1224         movq    PCPU(CURPCB),%rcx
1225         movq    $fusufault,PCB_ONFAULT(%rcx)
1226
1227         movq    $VM_MAXUSER_ADDRESS-8,%rax
1228         cmpq    %rax,%rdi                       /* verify address validity */
1229         ja      fusufault
1230
1231         movq    %rsi,(%rdi)
1232         xorl    %eax,%eax
1233         movq    %rax,PCB_ONFAULT(%rcx)
1234         POP_FRAME_POINTER
1235         ret
1236 END(suword_nosmap)
1237
1238 ENTRY(suword_smap)
1239         PUSH_FRAME_POINTER
1240         movq    PCPU(CURPCB),%rcx
1241         movq    $fusufault,PCB_ONFAULT(%rcx)
1242
1243         movq    $VM_MAXUSER_ADDRESS-8,%rax
1244         cmpq    %rax,%rdi                       /* verify address validity */
1245         ja      fusufault
1246
1247         stac
1248         movq    %rsi,(%rdi)
1249         clac
1250         xorl    %eax,%eax
1251         movq    %rax,PCB_ONFAULT(%rcx)
1252         POP_FRAME_POINTER
1253         ret
1254 END(suword_smap)
1255
1256 ENTRY(suword32_nosmap)
1257         PUSH_FRAME_POINTER
1258         movq    PCPU(CURPCB),%rcx
1259         movq    $fusufault,PCB_ONFAULT(%rcx)
1260
1261         movq    $VM_MAXUSER_ADDRESS-4,%rax
1262         cmpq    %rax,%rdi                       /* verify address validity */
1263         ja      fusufault
1264
1265         movl    %esi,(%rdi)
1266         xorl    %eax,%eax
1267         movq    %rax,PCB_ONFAULT(%rcx)
1268         POP_FRAME_POINTER
1269         ret
1270 END(suword32_nosmap)
1271
1272 ENTRY(suword32_smap)
1273         PUSH_FRAME_POINTER
1274         movq    PCPU(CURPCB),%rcx
1275         movq    $fusufault,PCB_ONFAULT(%rcx)
1276
1277         movq    $VM_MAXUSER_ADDRESS-4,%rax
1278         cmpq    %rax,%rdi                       /* verify address validity */
1279         ja      fusufault
1280
1281         stac
1282         movl    %esi,(%rdi)
1283         clac
1284         xorl    %eax,%eax
1285         movq    %rax,PCB_ONFAULT(%rcx)
1286         POP_FRAME_POINTER
1287         ret
1288 END(suword32_smap)
1289
1290 ENTRY(suword16_nosmap)
1291         PUSH_FRAME_POINTER
1292         movq    PCPU(CURPCB),%rcx
1293         movq    $fusufault,PCB_ONFAULT(%rcx)
1294
1295         movq    $VM_MAXUSER_ADDRESS-2,%rax
1296         cmpq    %rax,%rdi                       /* verify address validity */
1297         ja      fusufault
1298
1299         movw    %si,(%rdi)
1300         xorl    %eax,%eax
1301         movq    %rax,PCB_ONFAULT(%rcx)
1302         POP_FRAME_POINTER
1303         ret
1304 END(suword16_nosmap)
1305
1306 ENTRY(suword16_smap)
1307         PUSH_FRAME_POINTER
1308         movq    PCPU(CURPCB),%rcx
1309         movq    $fusufault,PCB_ONFAULT(%rcx)
1310
1311         movq    $VM_MAXUSER_ADDRESS-2,%rax
1312         cmpq    %rax,%rdi                       /* verify address validity */
1313         ja      fusufault
1314
1315         stac
1316         movw    %si,(%rdi)
1317         clac
1318         xorl    %eax,%eax
1319         movq    %rax,PCB_ONFAULT(%rcx)
1320         POP_FRAME_POINTER
1321         ret
1322 END(suword16_smap)
1323
1324 ENTRY(subyte_nosmap)
1325         PUSH_FRAME_POINTER
1326         movq    PCPU(CURPCB),%rcx
1327         movq    $fusufault,PCB_ONFAULT(%rcx)
1328
1329         movq    $VM_MAXUSER_ADDRESS-1,%rax
1330         cmpq    %rax,%rdi                       /* verify address validity */
1331         ja      fusufault
1332
1333         movl    %esi,%eax
1334         movb    %al,(%rdi)
1335         xorl    %eax,%eax
1336         movq    %rax,PCB_ONFAULT(%rcx)
1337         POP_FRAME_POINTER
1338         ret
1339 END(subyte_nosmap)
1340
1341 ENTRY(subyte_smap)
1342         PUSH_FRAME_POINTER
1343         movq    PCPU(CURPCB),%rcx
1344         movq    $fusufault,PCB_ONFAULT(%rcx)
1345
1346         movq    $VM_MAXUSER_ADDRESS-1,%rax
1347         cmpq    %rax,%rdi                       /* verify address validity */
1348         ja      fusufault
1349
1350         movl    %esi,%eax
1351         stac
1352         movb    %al,(%rdi)
1353         clac
1354         xorl    %eax,%eax
1355         movq    %rax,PCB_ONFAULT(%rcx)
1356         POP_FRAME_POINTER
1357         ret
1358 END(subyte_smap)
1359
1360         ALIGN_TEXT
1361         /* Fault entry clears PSL.AC */
1362 fusufault:
1363         movq    PCPU(CURPCB),%rcx
1364         xorl    %eax,%eax
1365         movq    %rax,PCB_ONFAULT(%rcx)
1366         decq    %rax
1367         POP_FRAME_POINTER
1368         ret
1369
1370 /*
1371  * copyinstr(from, to, maxlen, int *lencopied)
1372  *           %rdi, %rsi, %rdx, %rcx
1373  *
1374  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
1375  *      return ENAMETOOLONG if string is longer than maxlen, and
1376  *      EFAULT on protection violations. If lencopied is non-zero,
1377  *      return the actual length in *lencopied.
1378  */
1379 .macro COPYINSTR smap
1380         PUSH_FRAME_POINTER
1381         movq    %rdx,%r8                        /* %r8 = maxlen */
1382         movq    PCPU(CURPCB),%r9
1383         movq    $cpystrflt,PCB_ONFAULT(%r9)
1384
1385         movq    $VM_MAXUSER_ADDRESS,%rax
1386
1387         /* make sure 'from' is within bounds */
1388         subq    %rdi,%rax
1389         jbe     cpystrflt
1390
1391         SMAP_DISABLE \smap
1392
1393         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
1394         cmpq    %rdx,%rax
1395         jb      8f
1396 1:
1397         incq    %rdx
1398 2:
1399         decq    %rdx
1400 .if \smap == 0
1401         jz      copyinstr_toolong
1402 .else
1403         jz      copyinstr_toolong_smap
1404 .endif
1405
1406         movb    (%rdi),%al
1407         movb    %al,(%rsi)
1408         incq    %rsi
1409         incq    %rdi
1410         testb   %al,%al
1411         jnz     2b
1412
1413         SMAP_ENABLE \smap
1414
1415         /* Success -- 0 byte reached */
1416         decq    %rdx
1417         xorl    %eax,%eax
1418
1419         /* set *lencopied and return %eax */
1420         movq    %rax,PCB_ONFAULT(%r9)
1421
1422         testq   %rcx,%rcx
1423         jz      3f
1424         subq    %rdx,%r8
1425         movq    %r8,(%rcx)
1426 3:
1427         POP_FRAME_POINTER
1428         ret
1429         ALIGN_TEXT
1430 8:
1431         movq    %rax,%rdx
1432         movq    %rax,%r8
1433         jmp 1b
1434
1435 .endm
1436
1437 ENTRY(copyinstr_nosmap)
1438         COPYINSTR smap=0
1439 END(copyinstr_nosmap)
1440
1441 ENTRY(copyinstr_smap)
1442         COPYINSTR smap=1
1443 END(copyinstr_smap)
1444
1445 cpystrflt:
1446         /* Fault entry clears PSL.AC */
1447         movl    $EFAULT,%eax
1448 cpystrflt_x:
1449         /* set *lencopied and return %eax */
1450         movq    $0,PCB_ONFAULT(%r9)
1451
1452         testq   %rcx,%rcx
1453         jz      1f
1454         subq    %rdx,%r8
1455         movq    %r8,(%rcx)
1456 1:
1457         POP_FRAME_POINTER
1458         ret
1459
1460 copyinstr_toolong_smap:
1461         clac
1462 copyinstr_toolong:
1463         /* rdx is zero - return ENAMETOOLONG or EFAULT */
1464         movq    $VM_MAXUSER_ADDRESS,%rax
1465         cmpq    %rax,%rdi
1466         jae     cpystrflt
1467         movl    $ENAMETOOLONG,%eax
1468         jmp     cpystrflt_x
1469
1470 /*
1471  * Handling of special amd64 registers and descriptor tables etc
1472  */
1473 /* void lgdt(struct region_descriptor *rdp); */
1474 ENTRY(lgdt)
1475         /* reload the descriptor table */
1476         lgdt    (%rdi)
1477
1478         /* flush the prefetch q */
1479         jmp     1f
1480         nop
1481 1:
1482         movl    $KDSEL,%eax
1483         movl    %eax,%ds
1484         movl    %eax,%es
1485         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
1486         movl    %eax,%gs
1487         movl    %eax,%ss
1488
1489         /* reload code selector by turning return into intersegmental return */
1490         popq    %rax
1491         pushq   $KCSEL
1492         pushq   %rax
1493         MEXITCOUNT
1494         lretq
1495 END(lgdt)
1496
1497 /*****************************************************************************/
1498 /* setjump, longjump                                                         */
1499 /*****************************************************************************/
1500
1501 ENTRY(setjmp)
1502         movq    %rbx,0(%rdi)                    /* save rbx */
1503         movq    %rsp,8(%rdi)                    /* save rsp */
1504         movq    %rbp,16(%rdi)                   /* save rbp */
1505         movq    %r12,24(%rdi)                   /* save r12 */
1506         movq    %r13,32(%rdi)                   /* save r13 */
1507         movq    %r14,40(%rdi)                   /* save r14 */
1508         movq    %r15,48(%rdi)                   /* save r15 */
1509         movq    0(%rsp),%rdx                    /* get rta */
1510         movq    %rdx,56(%rdi)                   /* save rip */
1511         xorl    %eax,%eax                       /* return(0); */
1512         ret
1513 END(setjmp)
1514
1515 ENTRY(longjmp)
1516         movq    0(%rdi),%rbx                    /* restore rbx */
1517         movq    8(%rdi),%rsp                    /* restore rsp */
1518         movq    16(%rdi),%rbp                   /* restore rbp */
1519         movq    24(%rdi),%r12                   /* restore r12 */
1520         movq    32(%rdi),%r13                   /* restore r13 */
1521         movq    40(%rdi),%r14                   /* restore r14 */
1522         movq    48(%rdi),%r15                   /* restore r15 */
1523         movq    56(%rdi),%rdx                   /* get rta */
1524         movq    %rdx,0(%rsp)                    /* put in return frame */
1525         xorl    %eax,%eax                       /* return(1); */
1526         incl    %eax
1527         ret
1528 END(longjmp)
1529
1530 /*
1531  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
1532  * return an error.)
1533  */
1534 ENTRY(rdmsr_safe)
1535 /* int rdmsr_safe(u_int msr, uint64_t *data) */
1536         PUSH_FRAME_POINTER
1537         movq    PCPU(CURPCB),%r8
1538         movq    $msr_onfault,PCB_ONFAULT(%r8)
1539         movl    %edi,%ecx
1540         rdmsr                   /* Read MSR pointed by %ecx. Returns
1541                                    hi byte in edx, lo in %eax */
1542         salq    $32,%rdx        /* sign-shift %rdx left */
1543         movl    %eax,%eax       /* zero-extend %eax -> %rax */
1544         orq     %rdx,%rax
1545         movq    %rax,(%rsi)
1546         xorq    %rax,%rax
1547         movq    %rax,PCB_ONFAULT(%r8)
1548         POP_FRAME_POINTER
1549         ret
1550
1551 /*
1552  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
1553  * return an error.)
1554  */
1555 ENTRY(wrmsr_safe)
1556 /* int wrmsr_safe(u_int msr, uint64_t data) */
1557         PUSH_FRAME_POINTER
1558         movq    PCPU(CURPCB),%r8
1559         movq    $msr_onfault,PCB_ONFAULT(%r8)
1560         movl    %edi,%ecx
1561         movl    %esi,%eax
1562         sarq    $32,%rsi
1563         movl    %esi,%edx
1564         wrmsr                   /* Write MSR pointed by %ecx. Accepts
1565                                    hi byte in edx, lo in %eax. */
1566         xorq    %rax,%rax
1567         movq    %rax,PCB_ONFAULT(%r8)
1568         POP_FRAME_POINTER
1569         ret
1570
1571 /*
1572  * MSR operations fault handler
1573  */
1574         ALIGN_TEXT
1575 msr_onfault:
1576         movq    $0,PCB_ONFAULT(%r8)
1577         movl    $EFAULT,%eax
1578         POP_FRAME_POINTER
1579         ret
1580
1581 /*
1582  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
1583  * Invalidates address space addressed by ucr3, then returns to kcr3.
1584  * Done in assembler to ensure no other memory accesses happen while
1585  * on ucr3.
1586  */
1587         ALIGN_TEXT
1588 ENTRY(pmap_pti_pcid_invalidate)
1589         pushfq
1590         cli
1591         movq    %rdi,%cr3       /* to user page table */
1592         movq    %rsi,%cr3       /* back to kernel */
1593         popfq
1594         retq
1595
1596 /*
1597  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
1598  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
1599  */
1600         ALIGN_TEXT
1601 ENTRY(pmap_pti_pcid_invlpg)
1602         pushfq
1603         cli
1604         movq    %rdi,%cr3       /* to user page table */
1605         invlpg  (%rdx)
1606         movq    %rsi,%cr3       /* back to kernel */
1607         popfq
1608         retq
1609
1610 /*
1611  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
1612  *     vm_offset_t eva);
1613  * Invalidates virtual addresses between sva and eva in address space ucr3,
1614  * then returns to kcr3.
1615  */
1616         ALIGN_TEXT
1617 ENTRY(pmap_pti_pcid_invlrng)
1618         pushfq
1619         cli
1620         movq    %rdi,%cr3       /* to user page table */
1621 1:      invlpg  (%rdx)
1622         addq    $PAGE_SIZE,%rdx
1623         cmpq    %rdx,%rcx
1624         ja      1b
1625         movq    %rsi,%cr3       /* back to kernel */
1626         popfq
1627         retq
1628
1629         .altmacro
1630         .macro  rsb_seq_label l
1631 rsb_seq_\l:
1632         .endm
1633         .macro  rsb_call_label l
1634         call    rsb_seq_\l
1635         .endm
1636         .macro  rsb_seq count
1637         ll=1
1638         .rept   \count
1639         rsb_call_label  %(ll)
1640         nop
1641         rsb_seq_label %(ll)
1642         addq    $8,%rsp
1643         ll=ll+1
1644         .endr
1645         .endm
1646
1647 ENTRY(rsb_flush)
1648         rsb_seq 32
1649         ret
1650
1651 /* all callers already saved %rax, %rdx, and %rcx */
1652 ENTRY(handle_ibrs_entry)
1653         cmpb    $0,hw_ibrs_ibpb_active(%rip)
1654         je      1f
1655         movl    $MSR_IA32_SPEC_CTRL,%ecx
1656         rdmsr
1657         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1658         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
1659         wrmsr
1660         movb    $1,PCPU(IBPB_SET)
1661         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
1662         je      rsb_flush
1663 1:      ret
1664 END(handle_ibrs_entry)
1665
1666 ENTRY(handle_ibrs_exit)
1667         cmpb    $0,PCPU(IBPB_SET)
1668         je      1f
1669         movl    $MSR_IA32_SPEC_CTRL,%ecx
1670         rdmsr
1671         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1672         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1673         wrmsr
1674         movb    $0,PCPU(IBPB_SET)
1675 1:      ret
1676 END(handle_ibrs_exit)
1677
1678 /* registers-neutral version, but needs stack */
1679 ENTRY(handle_ibrs_exit_rs)
1680         cmpb    $0,PCPU(IBPB_SET)
1681         je      1f
1682         pushq   %rax
1683         pushq   %rdx
1684         pushq   %rcx
1685         movl    $MSR_IA32_SPEC_CTRL,%ecx
1686         rdmsr
1687         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
1688         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
1689         wrmsr
1690         popq    %rcx
1691         popq    %rdx
1692         popq    %rax
1693         movb    $0,PCPU(IBPB_SET)
1694 1:      ret
1695 END(handle_ibrs_exit_rs)
1696
1697         .noaltmacro
1698
1699 /*
1700  * Flush L1D cache.  Load enough of the data from the kernel text
1701  * to flush existing L1D content.
1702  *
1703  * N.B. The function does not follow ABI calling conventions, it corrupts %rbx.
1704  * The vmm.ko caller expects that only %rax, %rdx, %rbx, %rcx, %r9, and %rflags
1705  * registers are clobbered.  The NMI handler caller only needs %r13 and %r15
1706  * preserved.
1707  */
1708 ENTRY(flush_l1d_sw)
1709 #define L1D_FLUSH_SIZE  (64 * 1024)
1710         movq    $KERNBASE, %r9
1711         movq    $-L1D_FLUSH_SIZE, %rcx
1712         /*
1713          * pass 1: Preload TLB.
1714          * Kernel text is mapped using superpages.  TLB preload is
1715          * done for the benefit of older CPUs which split 2M page
1716          * into 4k TLB entries.
1717          */
1718 1:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1719         addq    $PAGE_SIZE, %rcx
1720         jne     1b
1721         xorl    %eax, %eax
1722         cpuid
1723         movq    $-L1D_FLUSH_SIZE, %rcx
1724         /* pass 2: Read each cache line. */
1725 2:      movb    L1D_FLUSH_SIZE(%r9, %rcx), %al
1726         addq    $64, %rcx
1727         jne     2b
1728         lfence
1729         ret
1730 #undef  L1D_FLUSH_SIZE
1731 END(flush_l1d_sw)
1732
1733 ENTRY(flush_l1d_sw_abi)
1734         pushq   %rbx
1735         call    flush_l1d_sw
1736         popq    %rbx
1737         ret
1738 END(flush_l1d_sw_abi)
1739
1740 ENTRY(mds_handler_void)
1741         retq
1742 END(mds_handler_void)
1743
1744 ENTRY(mds_handler_verw)
1745         subq    $8, %rsp
1746         movw    %ds, (%rsp)
1747         verw    (%rsp)
1748         addq    $8, %rsp
1749         retq
1750 END(mds_handler_verw)
1751
1752 ENTRY(mds_handler_ivb)
1753         pushq   %rax
1754         pushq   %rdx
1755         pushq   %rcx
1756
1757         movq    %cr0, %rax
1758         testb   $CR0_TS, %al
1759         je      1f
1760         clts
1761 1:      movq    PCPU(MDS_BUF), %rdx
1762         movdqa  %xmm0, PCPU(MDS_TMP)
1763         pxor    %xmm0, %xmm0
1764
1765         lfence
1766         orpd    (%rdx), %xmm0
1767         orpd    (%rdx), %xmm0
1768         mfence
1769         movl    $40, %ecx
1770         addq    $16, %rdx
1771 2:      movntdq %xmm0, (%rdx)
1772         addq    $16, %rdx
1773         decl    %ecx
1774         jnz     2b
1775         mfence
1776
1777         movdqa  PCPU(MDS_TMP),%xmm0
1778         testb   $CR0_TS, %al
1779         je      3f
1780         movq    %rax, %cr0
1781 3:      popq    %rcx
1782         popq    %rdx
1783         popq    %rax
1784         retq
1785 END(mds_handler_ivb)
1786
1787 ENTRY(mds_handler_bdw)
1788         pushq   %rax
1789         pushq   %rbx
1790         pushq   %rcx
1791         pushq   %rdi
1792         pushq   %rsi
1793
1794         movq    %cr0, %rax
1795         testb   $CR0_TS, %al
1796         je      1f
1797         clts
1798 1:      movq    PCPU(MDS_BUF), %rbx
1799         movdqa  %xmm0, PCPU(MDS_TMP)
1800         pxor    %xmm0, %xmm0
1801
1802         movq    %rbx, %rdi
1803         movq    %rbx, %rsi
1804         movl    $40, %ecx
1805 2:      movntdq %xmm0, (%rbx)
1806         addq    $16, %rbx
1807         decl    %ecx
1808         jnz     2b
1809         mfence
1810         movl    $1536, %ecx
1811         rep; movsb
1812         lfence
1813
1814         movdqa  PCPU(MDS_TMP),%xmm0
1815         testb   $CR0_TS, %al
1816         je      3f
1817         movq    %rax, %cr0
1818 3:      popq    %rsi
1819         popq    %rdi
1820         popq    %rcx
1821         popq    %rbx
1822         popq    %rax
1823         retq
1824 END(mds_handler_bdw)
1825
1826 ENTRY(mds_handler_skl_sse)
1827         pushq   %rax
1828         pushq   %rdx
1829         pushq   %rcx
1830         pushq   %rdi
1831
1832         movq    %cr0, %rax
1833         testb   $CR0_TS, %al
1834         je      1f
1835         clts
1836 1:      movq    PCPU(MDS_BUF), %rdi
1837         movq    PCPU(MDS_BUF64), %rdx
1838         movdqa  %xmm0, PCPU(MDS_TMP)
1839         pxor    %xmm0, %xmm0
1840
1841         lfence
1842         orpd    (%rdx), %xmm0
1843         orpd    (%rdx), %xmm0
1844         xorl    %eax, %eax
1845 2:      clflushopt      5376(%rdi, %rax, 8)
1846         addl    $8, %eax
1847         cmpl    $8 * 12, %eax
1848         jb      2b
1849         sfence
1850         movl    $6144, %ecx
1851         xorl    %eax, %eax
1852         rep; stosb
1853         mfence
1854
1855         movdqa  PCPU(MDS_TMP), %xmm0
1856         testb   $CR0_TS, %al
1857         je      3f
1858         movq    %rax, %cr0
1859 3:      popq    %rdi
1860         popq    %rcx
1861         popq    %rdx
1862         popq    %rax
1863         retq
1864 END(mds_handler_skl_sse)
1865
1866 ENTRY(mds_handler_skl_avx)
1867         pushq   %rax
1868         pushq   %rdx
1869         pushq   %rcx
1870         pushq   %rdi
1871
1872         movq    %cr0, %rax
1873         testb   $CR0_TS, %al
1874         je      1f
1875         clts
1876 1:      movq    PCPU(MDS_BUF), %rdi
1877         movq    PCPU(MDS_BUF64), %rdx
1878         vmovdqa %ymm0, PCPU(MDS_TMP)
1879         vpxor   %ymm0, %ymm0, %ymm0
1880
1881         lfence
1882         vorpd   (%rdx), %ymm0, %ymm0
1883         vorpd   (%rdx), %ymm0, %ymm0
1884         xorl    %eax, %eax
1885 2:      clflushopt      5376(%rdi, %rax, 8)
1886         addl    $8, %eax
1887         cmpl    $8 * 12, %eax
1888         jb      2b
1889         sfence
1890         movl    $6144, %ecx
1891         xorl    %eax, %eax
1892         rep; stosb
1893         mfence
1894
1895         vmovdqa PCPU(MDS_TMP), %ymm0
1896         testb   $CR0_TS, %al
1897         je      3f
1898         movq    %rax, %cr0
1899 3:      popq    %rdi
1900         popq    %rcx
1901         popq    %rdx
1902         popq    %rax
1903         retq
1904 END(mds_handler_skl_avx)
1905
1906 ENTRY(mds_handler_skl_avx512)
1907         pushq   %rax
1908         pushq   %rdx
1909         pushq   %rcx
1910         pushq   %rdi
1911
1912         movq    %cr0, %rax
1913         testb   $CR0_TS, %al
1914         je      1f
1915         clts
1916 1:      movq    PCPU(MDS_BUF), %rdi
1917         movq    PCPU(MDS_BUF64), %rdx
1918         vmovdqa64       %zmm0, PCPU(MDS_TMP)
1919         vpxord  %zmm0, %zmm0, %zmm0
1920
1921         lfence
1922         vorpd   (%rdx), %zmm0, %zmm0
1923         vorpd   (%rdx), %zmm0, %zmm0
1924         xorl    %eax, %eax
1925 2:      clflushopt      5376(%rdi, %rax, 8)
1926         addl    $8, %eax
1927         cmpl    $8 * 12, %eax
1928         jb      2b
1929         sfence
1930         movl    $6144, %ecx
1931         xorl    %eax, %eax
1932         rep; stosb
1933         mfence
1934
1935         vmovdqa64       PCPU(MDS_TMP), %zmm0
1936         testb   $CR0_TS, %al
1937         je      3f
1938         movq    %rax, %cr0
1939 3:      popq    %rdi
1940         popq    %rcx
1941         popq    %rdx
1942         popq    %rax
1943         retq
1944 END(mds_handler_skl_avx512)
1945
1946 ENTRY(mds_handler_silvermont)
1947         pushq   %rax
1948         pushq   %rdx
1949         pushq   %rcx
1950
1951         movq    %cr0, %rax
1952         testb   $CR0_TS, %al
1953         je      1f
1954         clts
1955 1:      movq    PCPU(MDS_BUF), %rdx
1956         movdqa  %xmm0, PCPU(MDS_TMP)
1957         pxor    %xmm0, %xmm0
1958
1959         movl    $16, %ecx
1960 2:      movntdq %xmm0, (%rdx)
1961         addq    $16, %rdx
1962         decl    %ecx
1963         jnz     2b
1964         mfence
1965
1966         movdqa  PCPU(MDS_TMP),%xmm0
1967         testb   $CR0_TS, %al
1968         je      3f
1969         movq    %rax, %cr0
1970 3:      popq    %rcx
1971         popq    %rdx
1972         popq    %rax
1973         retq
1974 END(mds_handler_silvermont)