]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
Mitigations for Microarchitectural Data Sampling.
[FreeBSD/FreeBSD.git] / sys / amd64 / amd64 / support.S
1 /*-
2  * Copyright (c) 2018-2019 The FreeBSD Foundation
3  * Copyright (c) 2003 Peter Wemm.
4  * Copyright (c) 1993 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * Portions of this software were developed by
8  * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from
9  * the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $FreeBSD$
36  */
37
38 #include "opt_ddb.h"
39
40 #include <machine/asmacros.h>
41 #include <machine/specialreg.h>
42 #include <machine/pmap.h>
43
44 #include "assym.s"
45
46         .text
47
48 /*
49  * bcopy family
50  * void bzero(void *buf, u_int len)
51  */
52
53 /* done */
54 ENTRY(bzero)
55         PUSH_FRAME_POINTER
56         movq    %rsi,%rcx
57         xorl    %eax,%eax
58         shrq    $3,%rcx
59         rep
60         stosq
61         movq    %rsi,%rcx
62         andq    $7,%rcx
63         rep
64         stosb
65         POP_FRAME_POINTER
66         ret
67 END(bzero)
68
69 /* Address: %rdi */
70 ENTRY(pagezero)
71         PUSH_FRAME_POINTER
72         movq    $PAGE_SIZE/8,%rcx
73         xorl    %eax,%eax
74         rep
75         stosq
76         POP_FRAME_POINTER
77         ret
78 END(pagezero)
79
80 ENTRY(bcmp)
81         PUSH_FRAME_POINTER
82         movq    %rdx,%rcx
83         shrq    $3,%rcx
84         repe
85         cmpsq
86         jne     1f
87
88         movq    %rdx,%rcx
89         andq    $7,%rcx
90         repe
91         cmpsb
92 1:
93         setne   %al
94         movsbl  %al,%eax
95         POP_FRAME_POINTER
96         ret
97 END(bcmp)
98
99 /*
100  * bcopy(src, dst, cnt)
101  *       rdi, rsi, rdx
102  *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
103  */
104 ENTRY(bcopy)
105         PUSH_FRAME_POINTER
106         xchgq   %rsi,%rdi
107         movq    %rdx,%rcx
108
109         movq    %rdi,%rax
110         subq    %rsi,%rax
111         cmpq    %rcx,%rax                       /* overlapping && src < dst? */
112         jb      1f
113
114         shrq    $3,%rcx                         /* copy by 64-bit words */
115         rep
116         movsq
117         movq    %rdx,%rcx
118         andq    $7,%rcx                         /* any bytes left? */
119         rep
120         movsb
121         POP_FRAME_POINTER
122         ret
123
124         /* ALIGN_TEXT */
125 1:
126         addq    %rcx,%rdi                       /* copy backwards */
127         addq    %rcx,%rsi
128         decq    %rdi
129         decq    %rsi
130         andq    $7,%rcx                         /* any fractional bytes? */
131         std
132         rep
133         movsb
134         movq    %rdx,%rcx                       /* copy remainder by 32-bit words */
135         shrq    $3,%rcx
136         subq    $7,%rsi
137         subq    $7,%rdi
138         rep
139         movsq
140         cld
141         POP_FRAME_POINTER
142         ret
143 END(bcopy)
144
145 /*
146  * Note: memcpy does not support overlapping copies
147  */
148 ENTRY(memcpy)
149         PUSH_FRAME_POINTER
150         movq    %rdi,%rax
151         movq    %rdx,%rcx
152         shrq    $3,%rcx                         /* copy by 64-bit words */
153         rep
154         movsq
155         movq    %rdx,%rcx
156         andq    $7,%rcx                         /* any bytes left? */
157         rep
158         movsb
159         POP_FRAME_POINTER
160         ret
161 END(memcpy)
162
163 /*
164  * pagecopy(%rdi=from, %rsi=to)
165  */
166 ENTRY(pagecopy)
167         PUSH_FRAME_POINTER
168         movq    $-PAGE_SIZE,%rax
169         movq    %rax,%rdx
170         subq    %rax,%rdi
171         subq    %rax,%rsi
172 1:
173         prefetchnta (%rdi,%rax)
174         addq    $64,%rax
175         jne     1b
176 2:
177         movq    (%rdi,%rdx),%rax
178         movnti  %rax,(%rsi,%rdx)
179         movq    8(%rdi,%rdx),%rax
180         movnti  %rax,8(%rsi,%rdx)
181         movq    16(%rdi,%rdx),%rax
182         movnti  %rax,16(%rsi,%rdx)
183         movq    24(%rdi,%rdx),%rax
184         movnti  %rax,24(%rsi,%rdx)
185         addq    $32,%rdx
186         jne     2b
187         sfence
188         POP_FRAME_POINTER
189         ret
190 END(pagecopy)
191
192 /* fillw(pat, base, cnt) */
193 /*       %rdi,%rsi, %rdx */
194 ENTRY(fillw)
195         PUSH_FRAME_POINTER
196         movq    %rdi,%rax
197         movq    %rsi,%rdi
198         movq    %rdx,%rcx
199         rep
200         stosw
201         POP_FRAME_POINTER
202         ret
203 END(fillw)
204
205 /*****************************************************************************/
206 /* copyout and fubyte family                                                 */
207 /*****************************************************************************/
208 /*
209  * Access user memory from inside the kernel. These routines should be
210  * the only places that do this.
211  *
212  * These routines set curpcb->pcb_onfault for the time they execute. When a
213  * protection violation occurs inside the functions, the trap handler
214  * returns to *curpcb->pcb_onfault instead of the function.
215  */
216
217 /*
218  * copyout(from_kernel, to_user, len)
219  *         %rdi,        %rsi,    %rdx
220  */
221 ENTRY(copyout)
222         PUSH_FRAME_POINTER
223         movq    PCPU(CURPCB),%rax
224         movq    $copyout_fault,PCB_ONFAULT(%rax)
225         testq   %rdx,%rdx                       /* anything to do? */
226         jz      done_copyout
227
228         /*
229          * Check explicitly for non-user addresses.  This check is essential
230          * because it prevents usermode from writing into the kernel.  We do
231          * not verify anywhere else that the user did not specify a rogue
232          * address.
233          */
234         /*
235          * First, prevent address wrapping.
236          */
237         movq    %rsi,%rax
238         addq    %rdx,%rax
239         jc      copyout_fault
240 /*
241  * XXX STOP USING VM_MAXUSER_ADDRESS.
242  * It is an end address, not a max, so every time it is used correctly it
243  * looks like there is an off by one error, and of course it caused an off
244  * by one error in several places.
245  */
246         movq    $VM_MAXUSER_ADDRESS,%rcx
247         cmpq    %rcx,%rax
248         ja      copyout_fault
249
250         xchgq   %rdi,%rsi
251         /* bcopy(%rsi, %rdi, %rdx) */
252         movq    %rdx,%rcx
253
254         shrq    $3,%rcx
255         rep
256         movsq
257         movb    %dl,%cl
258         andb    $7,%cl
259         rep
260         movsb
261
262 done_copyout:
263         xorl    %eax,%eax
264         movq    PCPU(CURPCB),%rdx
265         movq    %rax,PCB_ONFAULT(%rdx)
266         POP_FRAME_POINTER
267         ret
268
269         ALIGN_TEXT
270 copyout_fault:
271         movq    PCPU(CURPCB),%rdx
272         movq    $0,PCB_ONFAULT(%rdx)
273         movq    $EFAULT,%rax
274         POP_FRAME_POINTER
275         ret
276 END(copyout)
277
278 /*
279  * copyin(from_user, to_kernel, len)
280  *        %rdi,      %rsi,      %rdx
281  */
282 ENTRY(copyin)
283         PUSH_FRAME_POINTER
284         movq    PCPU(CURPCB),%rax
285         movq    $copyin_fault,PCB_ONFAULT(%rax)
286         testq   %rdx,%rdx                       /* anything to do? */
287         jz      done_copyin
288
289         /*
290          * make sure address is valid
291          */
292         movq    %rdi,%rax
293         addq    %rdx,%rax
294         jc      copyin_fault
295         movq    $VM_MAXUSER_ADDRESS,%rcx
296         cmpq    %rcx,%rax
297         ja      copyin_fault
298
299         xchgq   %rdi,%rsi
300         movq    %rdx,%rcx
301         movb    %cl,%al
302         shrq    $3,%rcx                         /* copy longword-wise */
303         rep
304         movsq
305         movb    %al,%cl
306         andb    $7,%cl                          /* copy remaining bytes */
307         rep
308         movsb
309
310 done_copyin:
311         xorl    %eax,%eax
312         movq    PCPU(CURPCB),%rdx
313         movq    %rax,PCB_ONFAULT(%rdx)
314         POP_FRAME_POINTER
315         ret
316
317         ALIGN_TEXT
318 copyin_fault:
319         movq    PCPU(CURPCB),%rdx
320         movq    $0,PCB_ONFAULT(%rdx)
321         movq    $EFAULT,%rax
322         POP_FRAME_POINTER
323         ret
324 END(copyin)
325
326 /*
327  * casueword32.  Compare and set user integer.  Returns -1 on fault,
328  *        0 if access was successful.  Old value is written to *oldp.
329  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
330  */
331 ENTRY(casueword32)
332         PUSH_FRAME_POINTER
333         movq    PCPU(CURPCB),%r8
334         movq    $fusufault,PCB_ONFAULT(%r8)
335
336         movq    $VM_MAXUSER_ADDRESS-4,%rax
337         cmpq    %rax,%rdi                       /* verify address is valid */
338         ja      fusufault
339
340         movl    %esi,%eax                       /* old */
341 #ifdef SMP
342         lock
343 #endif
344         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
345
346         /*
347          * The old value is in %eax.  If the store succeeded it will be the
348          * value we expected (old) from before the store, otherwise it will
349          * be the current value.  Save %eax into %esi to prepare the return
350          * value.
351          */
352         movl    %eax,%esi
353         xorl    %eax,%eax
354         movq    %rax,PCB_ONFAULT(%r8)
355
356         /*
357          * Access the oldp after the pcb_onfault is cleared, to correctly
358          * catch corrupted pointer.
359          */
360         movl    %esi,(%rdx)                     /* oldp = %rdx */
361         POP_FRAME_POINTER
362         ret
363 END(casueword32)
364
365 /*
366  * casueword.  Compare and set user long.  Returns -1 on fault,
367  *        0 if access was successful.  Old value is written to *oldp.
368  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
369  */
370 ENTRY(casueword)
371         PUSH_FRAME_POINTER
372         movq    PCPU(CURPCB),%r8
373         movq    $fusufault,PCB_ONFAULT(%r8)
374
375         movq    $VM_MAXUSER_ADDRESS-4,%rax
376         cmpq    %rax,%rdi                       /* verify address is valid */
377         ja      fusufault
378
379         movq    %rsi,%rax                       /* old */
380 #ifdef SMP
381         lock
382 #endif
383         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
384
385         /*
386          * The old value is in %rax.  If the store succeeded it will be the
387          * value we expected (old) from before the store, otherwise it will
388          * be the current value.
389          */
390         movq    %rax,%rsi
391         xorl    %eax,%eax
392         movq    %rax,PCB_ONFAULT(%r8)
393         movq    %rsi,(%rdx)
394         POP_FRAME_POINTER
395         ret
396 END(casueword)
397
398 /*
399  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
400  * byte from user memory.
401  * addr = %rdi, valp = %rsi
402  */
403
404 ALTENTRY(fueword64)
405 ENTRY(fueword)
406         PUSH_FRAME_POINTER
407         movq    PCPU(CURPCB),%rcx
408         movq    $fusufault,PCB_ONFAULT(%rcx)
409
410         movq    $VM_MAXUSER_ADDRESS-8,%rax
411         cmpq    %rax,%rdi                       /* verify address is valid */
412         ja      fusufault
413
414         xorl    %eax,%eax
415         movq    (%rdi),%r11
416         movq    %rax,PCB_ONFAULT(%rcx)
417         movq    %r11,(%rsi)
418         POP_FRAME_POINTER
419         ret
420 END(fueword64)
421 END(fueword)
422
423 ENTRY(fueword32)
424         PUSH_FRAME_POINTER
425         movq    PCPU(CURPCB),%rcx
426         movq    $fusufault,PCB_ONFAULT(%rcx)
427
428         movq    $VM_MAXUSER_ADDRESS-4,%rax
429         cmpq    %rax,%rdi                       /* verify address is valid */
430         ja      fusufault
431
432         xorl    %eax,%eax
433         movl    (%rdi),%r11d
434         movq    %rax,PCB_ONFAULT(%rcx)
435         movl    %r11d,(%rsi)
436         POP_FRAME_POINTER
437         ret
438 END(fueword32)
439
440 /*
441  * fuswintr() and suswintr() are specialized variants of fuword16() and
442  * suword16(), respectively.  They are called from the profiling code,
443  * potentially at interrupt time.  If they fail, that's okay; good things
444  * will happen later.  They always fail for now, until the trap code is
445  * able to deal with this.
446  */
447 ALTENTRY(suswintr)
448 ENTRY(fuswintr)
449         movq    $-1,%rax
450         ret
451 END(suswintr)
452 END(fuswintr)
453
454 ENTRY(fuword16)
455         PUSH_FRAME_POINTER
456         movq    PCPU(CURPCB),%rcx
457         movq    $fusufault,PCB_ONFAULT(%rcx)
458
459         movq    $VM_MAXUSER_ADDRESS-2,%rax
460         cmpq    %rax,%rdi
461         ja      fusufault
462
463         movzwl  (%rdi),%eax
464         movq    $0,PCB_ONFAULT(%rcx)
465         POP_FRAME_POINTER
466         ret
467 END(fuword16)
468
469 ENTRY(fubyte)
470         PUSH_FRAME_POINTER
471         movq    PCPU(CURPCB),%rcx
472         movq    $fusufault,PCB_ONFAULT(%rcx)
473
474         movq    $VM_MAXUSER_ADDRESS-1,%rax
475         cmpq    %rax,%rdi
476         ja      fusufault
477
478         movzbl  (%rdi),%eax
479         movq    $0,PCB_ONFAULT(%rcx)
480         POP_FRAME_POINTER
481         ret
482 END(fubyte)
483
484         ALIGN_TEXT
485 fusufault:
486         movq    PCPU(CURPCB),%rcx
487         xorl    %eax,%eax
488         movq    %rax,PCB_ONFAULT(%rcx)
489         decq    %rax
490         POP_FRAME_POINTER
491         ret
492
493 /*
494  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
495  * user memory.
496  * addr = %rdi, value = %rsi
497  */
498 ALTENTRY(suword64)
499 ENTRY(suword)
500         PUSH_FRAME_POINTER
501         movq    PCPU(CURPCB),%rcx
502         movq    $fusufault,PCB_ONFAULT(%rcx)
503
504         movq    $VM_MAXUSER_ADDRESS-8,%rax
505         cmpq    %rax,%rdi                       /* verify address validity */
506         ja      fusufault
507
508         movq    %rsi,(%rdi)
509         xorl    %eax,%eax
510         movq    PCPU(CURPCB),%rcx
511         movq    %rax,PCB_ONFAULT(%rcx)
512         POP_FRAME_POINTER
513         ret
514 END(suword64)
515 END(suword)
516
517 ENTRY(suword32)
518         PUSH_FRAME_POINTER
519         movq    PCPU(CURPCB),%rcx
520         movq    $fusufault,PCB_ONFAULT(%rcx)
521
522         movq    $VM_MAXUSER_ADDRESS-4,%rax
523         cmpq    %rax,%rdi                       /* verify address validity */
524         ja      fusufault
525
526         movl    %esi,(%rdi)
527         xorl    %eax,%eax
528         movq    PCPU(CURPCB),%rcx
529         movq    %rax,PCB_ONFAULT(%rcx)
530         POP_FRAME_POINTER
531         ret
532 END(suword32)
533
534 ENTRY(suword16)
535         PUSH_FRAME_POINTER
536         movq    PCPU(CURPCB),%rcx
537         movq    $fusufault,PCB_ONFAULT(%rcx)
538
539         movq    $VM_MAXUSER_ADDRESS-2,%rax
540         cmpq    %rax,%rdi                       /* verify address validity */
541         ja      fusufault
542
543         movw    %si,(%rdi)
544         xorl    %eax,%eax
545         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
546         movq    %rax,PCB_ONFAULT(%rcx)
547         POP_FRAME_POINTER
548         ret
549 END(suword16)
550
551 ENTRY(subyte)
552         PUSH_FRAME_POINTER
553         movq    PCPU(CURPCB),%rcx
554         movq    $fusufault,PCB_ONFAULT(%rcx)
555
556         movq    $VM_MAXUSER_ADDRESS-1,%rax
557         cmpq    %rax,%rdi                       /* verify address validity */
558         ja      fusufault
559
560         movl    %esi,%eax
561         movb    %al,(%rdi)
562         xorl    %eax,%eax
563         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
564         movq    %rax,PCB_ONFAULT(%rcx)
565         POP_FRAME_POINTER
566         ret
567 END(subyte)
568
569 /*
570  * copyinstr(from, to, maxlen, int *lencopied)
571  *           %rdi, %rsi, %rdx, %rcx
572  *
573  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
574  *      return ENAMETOOLONG if string is longer than maxlen, and
575  *      EFAULT on protection violations. If lencopied is non-zero,
576  *      return the actual length in *lencopied.
577  */
578 ENTRY(copyinstr)
579         PUSH_FRAME_POINTER
580         movq    %rdx,%r8                        /* %r8 = maxlen */
581         movq    %rcx,%r9                        /* %r9 = *len */
582         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
583         movq    PCPU(CURPCB),%rcx
584         movq    $cpystrflt,PCB_ONFAULT(%rcx)
585
586         movq    $VM_MAXUSER_ADDRESS,%rax
587
588         /* make sure 'from' is within bounds */
589         subq    %rsi,%rax
590         jbe     cpystrflt
591
592         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
593         cmpq    %rdx,%rax
594         jae     1f
595         movq    %rax,%rdx
596         movq    %rax,%r8
597 1:
598         incq    %rdx
599
600 2:
601         decq    %rdx
602         jz      3f
603
604         lodsb
605         stosb
606         orb     %al,%al
607         jnz     2b
608
609         /* Success -- 0 byte reached */
610         decq    %rdx
611         xorl    %eax,%eax
612         jmp     cpystrflt_x
613 3:
614         /* rdx is zero - return ENAMETOOLONG or EFAULT */
615         movq    $VM_MAXUSER_ADDRESS,%rax
616         cmpq    %rax,%rsi
617         jae     cpystrflt
618 4:
619         movq    $ENAMETOOLONG,%rax
620         jmp     cpystrflt_x
621
622 cpystrflt:
623         movq    $EFAULT,%rax
624
625 cpystrflt_x:
626         /* set *lencopied and return %eax */
627         movq    PCPU(CURPCB),%rcx
628         movq    $0,PCB_ONFAULT(%rcx)
629
630         testq   %r9,%r9
631         jz      1f
632         subq    %rdx,%r8
633         movq    %r8,(%r9)
634 1:
635         POP_FRAME_POINTER
636         ret
637 END(copyinstr)
638
639 /*
640  * copystr(from, to, maxlen, int *lencopied)
641  *         %rdi, %rsi, %rdx, %rcx
642  */
643 ENTRY(copystr)
644         PUSH_FRAME_POINTER
645         movq    %rdx,%r8                        /* %r8 = maxlen */
646
647         xchgq   %rdi,%rsi
648         incq    %rdx
649 1:
650         decq    %rdx
651         jz      4f
652         lodsb
653         stosb
654         orb     %al,%al
655         jnz     1b
656
657         /* Success -- 0 byte reached */
658         decq    %rdx
659         xorl    %eax,%eax
660         jmp     6f
661 4:
662         /* rdx is zero -- return ENAMETOOLONG */
663         movq    $ENAMETOOLONG,%rax
664
665 6:
666
667         testq   %rcx,%rcx
668         jz      7f
669         /* set *lencopied and return %rax */
670         subq    %rdx,%r8
671         movq    %r8,(%rcx)
672 7:
673         POP_FRAME_POINTER
674         ret
675 END(copystr)
676
677 /*
678  * Handling of special amd64 registers and descriptor tables etc
679  */
680 /* void lgdt(struct region_descriptor *rdp); */
681 ENTRY(lgdt)
682         /* reload the descriptor table */
683         lgdt    (%rdi)
684
685         /* flush the prefetch q */
686         jmp     1f
687         nop
688 1:
689         movl    $KDSEL,%eax
690         movl    %eax,%ds
691         movl    %eax,%es
692         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
693         movl    %eax,%gs
694         movl    %eax,%ss
695
696         /* reload code selector by turning return into intersegmental return */
697         popq    %rax
698         pushq   $KCSEL
699         pushq   %rax
700         MEXITCOUNT
701         lretq
702 END(lgdt)
703
704 /*****************************************************************************/
705 /* setjump, longjump                                                         */
706 /*****************************************************************************/
707
708 ENTRY(setjmp)
709         movq    %rbx,0(%rdi)                    /* save rbx */
710         movq    %rsp,8(%rdi)                    /* save rsp */
711         movq    %rbp,16(%rdi)                   /* save rbp */
712         movq    %r12,24(%rdi)                   /* save r12 */
713         movq    %r13,32(%rdi)                   /* save r13 */
714         movq    %r14,40(%rdi)                   /* save r14 */
715         movq    %r15,48(%rdi)                   /* save r15 */
716         movq    0(%rsp),%rdx                    /* get rta */
717         movq    %rdx,56(%rdi)                   /* save rip */
718         xorl    %eax,%eax                       /* return(0); */
719         ret
720 END(setjmp)
721
722 ENTRY(longjmp)
723         movq    0(%rdi),%rbx                    /* restore rbx */
724         movq    8(%rdi),%rsp                    /* restore rsp */
725         movq    16(%rdi),%rbp                   /* restore rbp */
726         movq    24(%rdi),%r12                   /* restore r12 */
727         movq    32(%rdi),%r13                   /* restore r13 */
728         movq    40(%rdi),%r14                   /* restore r14 */
729         movq    48(%rdi),%r15                   /* restore r15 */
730         movq    56(%rdi),%rdx                   /* get rta */
731         movq    %rdx,0(%rsp)                    /* put in return frame */
732         xorl    %eax,%eax                       /* return(1); */
733         incl    %eax
734         ret
735 END(longjmp)
736
737 /*
738  * Support for reading MSRs in the safe manner.
739  */
740 ENTRY(rdmsr_safe)
741 /* int rdmsr_safe(u_int msr, uint64_t *data) */
742         PUSH_FRAME_POINTER
743         movq    PCPU(CURPCB),%r8
744         movq    $msr_onfault,PCB_ONFAULT(%r8)
745         movl    %edi,%ecx
746         rdmsr                   /* Read MSR pointed by %ecx. Returns
747                                    hi byte in edx, lo in %eax */
748         salq    $32,%rdx        /* sign-shift %rdx left */
749         movl    %eax,%eax       /* zero-extend %eax -> %rax */
750         orq     %rdx,%rax
751         movq    %rax,(%rsi)
752         xorq    %rax,%rax
753         movq    %rax,PCB_ONFAULT(%r8)
754         POP_FRAME_POINTER
755         ret
756
757 /*
758  * Support for writing MSRs in the safe manner.
759  */
760 ENTRY(wrmsr_safe)
761 /* int wrmsr_safe(u_int msr, uint64_t data) */
762         PUSH_FRAME_POINTER
763         movq    PCPU(CURPCB),%r8
764         movq    $msr_onfault,PCB_ONFAULT(%r8)
765         movl    %edi,%ecx
766         movl    %esi,%eax
767         sarq    $32,%rsi
768         movl    %esi,%edx
769         wrmsr                   /* Write MSR pointed by %ecx. Accepts
770                                    hi byte in edx, lo in %eax. */
771         xorq    %rax,%rax
772         movq    %rax,PCB_ONFAULT(%r8)
773         POP_FRAME_POINTER
774         ret
775
776 /*
777  * MSR operations fault handler
778  */
779         ALIGN_TEXT
780 msr_onfault:
781         movq    $0,PCB_ONFAULT(%r8)
782         movl    $EFAULT,%eax
783         POP_FRAME_POINTER
784         ret
785
786 /*
787  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
788  * Invalidates address space addressed by ucr3, then returns to kcr3.
789  * Done in assembler to ensure no other memory accesses happen while
790  * on ucr3.
791  */
792         ALIGN_TEXT
793 ENTRY(pmap_pti_pcid_invalidate)
794         pushfq
795         cli
796         movq    %rdi,%cr3       /* to user page table */
797         movq    %rsi,%cr3       /* back to kernel */
798         popfq
799         retq
800
801 /*
802  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
803  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
804  */
805         ALIGN_TEXT
806 ENTRY(pmap_pti_pcid_invlpg)
807         pushfq
808         cli
809         movq    %rdi,%cr3       /* to user page table */
810         invlpg  (%rdx)
811         movq    %rsi,%cr3       /* back to kernel */
812         popfq
813         retq
814
815 /*
816  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
817  *     vm_offset_t eva);
818  * Invalidates virtual addresses between sva and eva in address space ucr3,
819  * then returns to kcr3.
820  */
821         ALIGN_TEXT
822 ENTRY(pmap_pti_pcid_invlrng)
823         pushfq
824         cli
825         movq    %rdi,%cr3       /* to user page table */
826 1:      invlpg  (%rdx)
827         addq    $PAGE_SIZE,%rdx
828         cmpq    %rdx,%rcx
829         ja      1b
830         movq    %rsi,%cr3       /* back to kernel */
831         popfq
832         retq
833
834         .altmacro
835         .macro  ibrs_seq_label l
836 handle_ibrs_\l:
837         .endm
838         .macro  ibrs_call_label l
839         call    handle_ibrs_\l
840         .endm
841         .macro  ibrs_seq count
842         ll=1
843         .rept   \count
844         ibrs_call_label %(ll)
845         nop
846         ibrs_seq_label %(ll)
847         addq    $8,%rsp
848         ll=ll+1
849         .endr
850         .endm
851
852 /* all callers already saved %rax, %rdx, and %rcx */
853 ENTRY(handle_ibrs_entry)
854         cmpb    $0,hw_ibrs_active(%rip)
855         je      1f
856         movl    $MSR_IA32_SPEC_CTRL,%ecx
857         rdmsr
858         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
859         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
860         wrmsr
861         movb    $1,PCPU(IBPB_SET)
862         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
863         jne     1f
864         ibrs_seq 32
865 1:      ret
866 END(handle_ibrs_entry)
867
868 ENTRY(handle_ibrs_exit)
869         cmpb    $0,PCPU(IBPB_SET)
870         je      1f
871         movl    $MSR_IA32_SPEC_CTRL,%ecx
872         rdmsr
873         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
874         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
875         wrmsr
876         movb    $0,PCPU(IBPB_SET)
877 1:      ret
878 END(handle_ibrs_exit)
879
880 /* registers-neutral version, but needs stack */
881 ENTRY(handle_ibrs_exit_rs)
882         cmpb    $0,PCPU(IBPB_SET)
883         je      1f
884         pushq   %rax
885         pushq   %rdx
886         pushq   %rcx
887         movl    $MSR_IA32_SPEC_CTRL,%ecx
888         rdmsr
889         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
890         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
891         wrmsr
892         popq    %rcx
893         popq    %rdx
894         popq    %rax
895         movb    $0,PCPU(IBPB_SET)
896 1:      ret
897 END(handle_ibrs_exit_rs)
898
899         .noaltmacro
900
901 ENTRY(mds_handler_void)
902         retq
903 END(mds_handler_void)
904
905 ENTRY(mds_handler_verw)
906         subq    $8, %rsp
907         movw    %ds, (%rsp)
908         verw    (%rsp)
909         addq    $8, %rsp
910         retq
911 END(mds_handler_verw)
912
913 ENTRY(mds_handler_ivb)
914         pushq   %rax
915         pushq   %rdx
916         pushq   %rcx
917
918         movq    %cr0, %rax
919         testb   $CR0_TS, %al
920         je      1f
921         clts
922 1:      movq    PCPU(MDS_BUF), %rdx
923         movdqa  %xmm0, PCPU(MDS_TMP)
924         pxor    %xmm0, %xmm0
925
926         lfence
927         orpd    (%rdx), %xmm0
928         orpd    (%rdx), %xmm0
929         mfence
930         movl    $40, %ecx
931         addq    $16, %rdx
932 2:      movntdq %xmm0, (%rdx)
933         addq    $16, %rdx
934         decl    %ecx
935         jnz     2b
936         mfence
937
938         movdqa  PCPU(MDS_TMP),%xmm0
939         testb   $CR0_TS, %al
940         je      3f
941         movq    %rax, %cr0
942 3:      popq    %rcx
943         popq    %rdx
944         popq    %rax
945         retq
946 END(mds_handler_ivb)
947
948 ENTRY(mds_handler_bdw)
949         pushq   %rax
950         pushq   %rbx
951         pushq   %rcx
952         pushq   %rdi
953         pushq   %rsi
954
955         movq    %cr0, %rax
956         testb   $CR0_TS, %al
957         je      1f
958         clts
959 1:      movq    PCPU(MDS_BUF), %rbx
960         movdqa  %xmm0, PCPU(MDS_TMP)
961         pxor    %xmm0, %xmm0
962
963         movq    %rbx, %rdi
964         movq    %rbx, %rsi
965         movl    $40, %ecx
966 2:      movntdq %xmm0, (%rbx)
967         addq    $16, %rbx
968         decl    %ecx
969         jnz     2b
970         mfence
971         movl    $1536, %ecx
972         rep; movsb
973         lfence
974
975         movdqa  PCPU(MDS_TMP),%xmm0
976         testb   $CR0_TS, %al
977         je      3f
978         movq    %rax, %cr0
979 3:      popq    %rsi
980         popq    %rdi
981         popq    %rcx
982         popq    %rbx
983         popq    %rax
984         retq
985 END(mds_handler_bdw)
986
987 ENTRY(mds_handler_skl_sse)
988         pushq   %rax
989         pushq   %rdx
990         pushq   %rcx
991         pushq   %rdi
992
993         movq    %cr0, %rax
994         testb   $CR0_TS, %al
995         je      1f
996         clts
997 1:      movq    PCPU(MDS_BUF), %rdi
998         movq    PCPU(MDS_BUF64), %rdx
999         movdqa  %xmm0, PCPU(MDS_TMP)
1000         pxor    %xmm0, %xmm0
1001
1002         lfence
1003         orpd    (%rdx), %xmm0
1004         orpd    (%rdx), %xmm0
1005         xorl    %eax, %eax
1006 2:      clflushopt      5376(%rdi, %rax, 8)
1007         addl    $8, %eax
1008         cmpl    $8 * 12, %eax
1009         jb      2b
1010         sfence
1011         movl    $6144, %ecx
1012         xorl    %eax, %eax
1013         rep; stosb
1014         mfence
1015
1016         movdqa  PCPU(MDS_TMP), %xmm0
1017         testb   $CR0_TS, %al
1018         je      3f
1019         movq    %rax, %cr0
1020 3:      popq    %rdi
1021         popq    %rcx
1022         popq    %rdx
1023         popq    %rax
1024         retq
1025 END(mds_handler_skl_sse)
1026
1027 ENTRY(mds_handler_skl_avx)
1028         pushq   %rax
1029         pushq   %rdx
1030         pushq   %rcx
1031         pushq   %rdi
1032
1033         movq    %cr0, %rax
1034         testb   $CR0_TS, %al
1035         je      1f
1036         clts
1037 1:      movq    PCPU(MDS_BUF), %rdi
1038         movq    PCPU(MDS_BUF64), %rdx
1039         vmovdqa %ymm0, PCPU(MDS_TMP)
1040         vpxor   %ymm0, %ymm0, %ymm0
1041
1042         lfence
1043         vorpd   (%rdx), %ymm0, %ymm0
1044         vorpd   (%rdx), %ymm0, %ymm0
1045         xorl    %eax, %eax
1046 2:      clflushopt      5376(%rdi, %rax, 8)
1047         addl    $8, %eax
1048         cmpl    $8 * 12, %eax
1049         jb      2b
1050         sfence
1051         movl    $6144, %ecx
1052         xorl    %eax, %eax
1053         rep; stosb
1054         mfence
1055
1056         vmovdqa PCPU(MDS_TMP), %ymm0
1057         testb   $CR0_TS, %al
1058         je      3f
1059         movq    %rax, %cr0
1060 3:      popq    %rdi
1061         popq    %rcx
1062         popq    %rdx
1063         popq    %rax
1064         retq
1065 END(mds_handler_skl_avx)
1066
1067 ENTRY(mds_handler_skl_avx512)
1068         pushq   %rax
1069         pushq   %rdx
1070         pushq   %rcx
1071         pushq   %rdi
1072
1073         movq    %cr0, %rax
1074         testb   $CR0_TS, %al
1075         je      1f
1076         clts
1077 1:      movq    PCPU(MDS_BUF), %rdi
1078         movq    PCPU(MDS_BUF64), %rdx
1079 /*      vmovdqa64       %zmm0, PCPU(MDS_TMP) */
1080         .byte   0x65, 0x62, 0xf1, 0xfd, 0x48, 0x7f, 0x04, 0x25
1081         .long   PC_MDS_TMP
1082 /*      vpxor   %zmm0, %zmm0, %zmm0 */
1083         .byte   0x62, 0xf1, 0xfd, 0x48, 0xef, 0xc0
1084
1085         lfence
1086 /*      vorpd   (%rdx), %zmm0, %zmm0 */
1087         .byte   0x62, 0xf1, 0xfd, 0x48, 0x56, 0x02
1088 /*      vorpd   (%rdx), %zmm0, %zmm0 */
1089         .byte   0x62, 0xf1, 0xfd, 0x48, 0x56, 0x02
1090         xorl    %eax, %eax
1091 2:      clflushopt      5376(%rdi, %rax, 8)
1092         addl    $8, %eax
1093         cmpl    $8 * 12, %eax
1094         jb      2b
1095         sfence
1096         movl    $6144, %ecx
1097         xorl    %eax, %eax
1098         rep; stosb
1099         mfence
1100
1101 /*      vmovdqa64       PCPU(MDS_TMP), %zmm0 */
1102         .byte   0x65, 0x62, 0xf1, 0xfd, 0x48, 0x6f, 0x04, 0x25
1103         .long   PC_MDS_TMP
1104         testb   $CR0_TS, %al
1105         je      3f
1106         movq    %rax, %cr0
1107 3:      popq    %rdi
1108         popq    %rcx
1109         popq    %rdx
1110         popq    %rax
1111         retq
1112 END(mds_handler_skl_avx512)
1113
1114 ENTRY(mds_handler_silvermont)
1115         pushq   %rax
1116         pushq   %rdx
1117         pushq   %rcx
1118
1119         movq    %cr0, %rax
1120         testb   $CR0_TS, %al
1121         je      1f
1122         clts
1123 1:      movq    PCPU(MDS_BUF), %rdx
1124         movdqa  %xmm0, PCPU(MDS_TMP)
1125         pxor    %xmm0, %xmm0
1126
1127         movl    $16, %ecx
1128 2:      movntdq %xmm0, (%rdx)
1129         addq    $16, %rdx
1130         decl    %ecx
1131         jnz     2b
1132         mfence
1133
1134         movdqa  PCPU(MDS_TMP),%xmm0
1135         testb   $CR0_TS, %al
1136         je      3f
1137         movq    %rax, %cr0
1138 3:      popq    %rcx
1139         popq    %rdx
1140         popq    %rax
1141         retq
1142 END(mds_handler_silvermont)