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