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