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