]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
MFV r336851:
[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)
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)
53
54 /*
55  * pagecopy(%rdi=from, %rsi=to)
56  */
57 ENTRY(pagecopy)
58         PUSH_FRAME_POINTER
59         movq    $PAGE_SIZE/8,%rcx
60         movq    %rdi,%r9
61         movq    %rsi,%rdi
62         movq    %r9,%rsi
63         rep
64         movsq
65         POP_FRAME_POINTER
66         ret
67 END(pagecopy)
68
69 /* Address: %rdi */
70 ENTRY(sse2_pagezero)
71         PUSH_FRAME_POINTER
72         movq    $-PAGE_SIZE,%rdx
73         subq    %rdx,%rdi
74         xorl    %eax,%eax
75         jmp     1f
76         /*
77          * The loop takes 29 bytes.  Ensure that it doesn't cross a 32-byte
78          * cache line.
79          */
80         .p2align 5,0x90
81 1:
82         movnti  %rax,(%rdi,%rdx)
83         movnti  %rax,8(%rdi,%rdx)
84         movnti  %rax,16(%rdi,%rdx)
85         movnti  %rax,24(%rdi,%rdx)
86         addq    $32,%rdx
87         jne     1b
88         sfence
89         POP_FRAME_POINTER
90         ret
91 END(sse2_pagezero)
92
93 /*
94  * memmove(dst, src, cnt)
95  *         rdi, rsi, rdx
96  * Adapted from bcopy written by:
97  *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
98  */
99 ENTRY(memmove)
100         PUSH_FRAME_POINTER
101         movq    %rdi,%r9
102         movq    %rdx,%rcx
103
104         movq    %rdi,%rax
105         subq    %rsi,%rax
106         cmpq    %rcx,%rax                       /* overlapping && src < dst? */
107         jb      1f
108
109         shrq    $3,%rcx                         /* copy by 64-bit words */
110         rep
111         movsq
112         movq    %rdx,%rcx
113         andq    $7,%rcx                         /* any bytes left? */
114         jne     2f
115         movq    %r9,%rax
116         POP_FRAME_POINTER
117         ret
118 2:
119         rep
120         movsb
121         movq    %r9,%rax
122         POP_FRAME_POINTER
123         ret
124
125         /* ALIGN_TEXT */
126 1:
127         addq    %rcx,%rdi                       /* copy backwards */
128         addq    %rcx,%rsi
129         decq    %rdi
130         decq    %rsi
131         andq    $7,%rcx                         /* any fractional bytes? */
132         std
133         rep
134         movsb
135         movq    %rdx,%rcx                       /* copy remainder by 32-bit words */
136         shrq    $3,%rcx
137         subq    $7,%rsi
138         subq    $7,%rdi
139         rep
140         movsq
141         cld
142         movq    %r9,%rax
143         POP_FRAME_POINTER
144         ret
145 END(memmove)
146
147 /*
148  * memcpy(dst, src, len)
149  *        rdi, rsi, rdx
150  *
151  * Note: memcpy does not support overlapping copies
152  */
153 ENTRY(memcpy)
154         PUSH_FRAME_POINTER
155         movq    %rdi,%rax
156         movq    %rdx,%rcx
157         shrq    $3,%rcx                         /* copy by 64-bit words */
158         rep
159         movsq
160         movq    %rdx,%rcx
161         andq    $7,%rcx                         /* any bytes left? */
162         jne     1f
163         POP_FRAME_POINTER
164         ret
165 1:
166         rep
167         movsb
168         POP_FRAME_POINTER
169         ret
170 END(memcpy)
171
172 /*
173  * memset(dst, c,   len)
174  *        rdi, rsi, rdx
175  */
176 ENTRY(memset)
177         PUSH_FRAME_POINTER
178         movq    %rdi,%r9
179         movq    %rdx,%rcx
180         movzbq  %sil,%r8
181         movabs  $0x0101010101010101,%rax
182         imulq   %r8,%rax
183         shrq    $3,%rcx
184         rep
185         stosq
186         movq    %rdx,%rcx
187         andq    $7,%rcx
188         jne     1f
189         movq    %r9,%rax
190         POP_FRAME_POINTER
191         ret
192 1:
193         rep
194         stosb
195         movq    %r9,%rax
196         POP_FRAME_POINTER
197         ret
198 END(memset)
199
200 /* fillw(pat, base, cnt) */
201 /*       %rdi,%rsi, %rdx */
202 ENTRY(fillw)
203         PUSH_FRAME_POINTER
204         movq    %rdi,%rax
205         movq    %rsi,%rdi
206         movq    %rdx,%rcx
207         rep
208         stosw
209         POP_FRAME_POINTER
210         ret
211 END(fillw)
212
213 /*****************************************************************************/
214 /* copyout and fubyte family                                                 */
215 /*****************************************************************************/
216 /*
217  * Access user memory from inside the kernel. These routines should be
218  * the only places that do this.
219  *
220  * These routines set curpcb->pcb_onfault for the time they execute. When a
221  * protection violation occurs inside the functions, the trap handler
222  * returns to *curpcb->pcb_onfault instead of the function.
223  */
224
225 /*
226  * copyout(from_kernel, to_user, len)
227  *         %rdi,        %rsi,    %rdx
228  */
229 ENTRY(copyout)
230         PUSH_FRAME_POINTER
231         movq    PCPU(CURPCB),%rax
232         movq    $copyout_fault,PCB_ONFAULT(%rax)
233         testq   %rdx,%rdx                       /* anything to do? */
234         jz      done_copyout
235
236         /*
237          * Check explicitly for non-user addresses.  This check is essential
238          * because it prevents usermode from writing into the kernel.  We do
239          * not verify anywhere else that the user did not specify a rogue
240          * address.
241          */
242         /*
243          * First, prevent address wrapping.
244          */
245         movq    %rsi,%rax
246         addq    %rdx,%rax
247         jc      copyout_fault
248 /*
249  * XXX STOP USING VM_MAXUSER_ADDRESS.
250  * It is an end address, not a max, so every time it is used correctly it
251  * looks like there is an off by one error, and of course it caused an off
252  * by one error in several places.
253  */
254         movq    $VM_MAXUSER_ADDRESS,%rcx
255         cmpq    %rcx,%rax
256         ja      copyout_fault
257
258         xchgq   %rdi,%rsi
259         /* bcopy(%rsi, %rdi, %rdx) */
260         movq    %rdx,%rcx
261
262         shrq    $3,%rcx
263         rep
264         movsq
265         movb    %dl,%cl
266         andb    $7,%cl
267         je      done_copyout
268         rep
269         movsb
270
271 done_copyout:
272         xorl    %eax,%eax
273         movq    PCPU(CURPCB),%rdx
274         movq    %rax,PCB_ONFAULT(%rdx)
275         POP_FRAME_POINTER
276         ret
277
278         ALIGN_TEXT
279 copyout_fault:
280         movq    PCPU(CURPCB),%rdx
281         movq    $0,PCB_ONFAULT(%rdx)
282         movq    $EFAULT,%rax
283         POP_FRAME_POINTER
284         ret
285 END(copyout)
286
287 /*
288  * copyin(from_user, to_kernel, len)
289  *        %rdi,      %rsi,      %rdx
290  */
291 ENTRY(copyin)
292         PUSH_FRAME_POINTER
293         movq    PCPU(CURPCB),%rax
294         movq    $copyin_fault,PCB_ONFAULT(%rax)
295         testq   %rdx,%rdx                       /* anything to do? */
296         jz      done_copyin
297
298         /*
299          * make sure address is valid
300          */
301         movq    %rdi,%rax
302         addq    %rdx,%rax
303         jc      copyin_fault
304         movq    $VM_MAXUSER_ADDRESS,%rcx
305         cmpq    %rcx,%rax
306         ja      copyin_fault
307
308         xchgq   %rdi,%rsi
309         movq    %rdx,%rcx
310         movb    %cl,%al
311         shrq    $3,%rcx                         /* copy longword-wise */
312         rep
313         movsq
314         movb    %al,%cl
315         andb    $7,%cl                          /* copy remaining bytes */
316         je      done_copyin
317         rep
318         movsb
319
320 done_copyin:
321         xorl    %eax,%eax
322         movq    PCPU(CURPCB),%rdx
323         movq    %rax,PCB_ONFAULT(%rdx)
324         POP_FRAME_POINTER
325         ret
326
327         ALIGN_TEXT
328 copyin_fault:
329         movq    PCPU(CURPCB),%rdx
330         movq    $0,PCB_ONFAULT(%rdx)
331         movq    $EFAULT,%rax
332         POP_FRAME_POINTER
333         ret
334 END(copyin)
335
336 /*
337  * casueword32.  Compare and set user integer.  Returns -1 on fault,
338  *        0 if access was successful.  Old value is written to *oldp.
339  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
340  */
341 ENTRY(casueword32)
342         PUSH_FRAME_POINTER
343         movq    PCPU(CURPCB),%r8
344         movq    $fusufault,PCB_ONFAULT(%r8)
345
346         movq    $VM_MAXUSER_ADDRESS-4,%rax
347         cmpq    %rax,%rdi                       /* verify address is valid */
348         ja      fusufault
349
350         movl    %esi,%eax                       /* old */
351 #ifdef SMP
352         lock
353 #endif
354         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
355
356         /*
357          * The old value is in %eax.  If the store succeeded it will be the
358          * value we expected (old) from before the store, otherwise it will
359          * be the current value.  Save %eax into %esi to prepare the return
360          * value.
361          */
362         movl    %eax,%esi
363         xorl    %eax,%eax
364         movq    %rax,PCB_ONFAULT(%r8)
365
366         /*
367          * Access the oldp after the pcb_onfault is cleared, to correctly
368          * catch corrupted pointer.
369          */
370         movl    %esi,(%rdx)                     /* oldp = %rdx */
371         POP_FRAME_POINTER
372         ret
373 END(casueword32)
374
375 /*
376  * casueword.  Compare and set user long.  Returns -1 on fault,
377  *        0 if access was successful.  Old value is written to *oldp.
378  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
379  */
380 ENTRY(casueword)
381         PUSH_FRAME_POINTER
382         movq    PCPU(CURPCB),%r8
383         movq    $fusufault,PCB_ONFAULT(%r8)
384
385         movq    $VM_MAXUSER_ADDRESS-4,%rax
386         cmpq    %rax,%rdi                       /* verify address is valid */
387         ja      fusufault
388
389         movq    %rsi,%rax                       /* old */
390 #ifdef SMP
391         lock
392 #endif
393         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
394
395         /*
396          * The old value is in %rax.  If the store succeeded it will be the
397          * value we expected (old) from before the store, otherwise it will
398          * be the current value.
399          */
400         movq    %rax,%rsi
401         xorl    %eax,%eax
402         movq    %rax,PCB_ONFAULT(%r8)
403         movq    %rsi,(%rdx)
404         POP_FRAME_POINTER
405         ret
406 END(casueword)
407
408 /*
409  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
410  * byte from user memory.
411  * addr = %rdi, valp = %rsi
412  */
413
414 ALTENTRY(fueword64)
415 ENTRY(fueword)
416         PUSH_FRAME_POINTER
417         movq    PCPU(CURPCB),%rcx
418         movq    $fusufault,PCB_ONFAULT(%rcx)
419
420         movq    $VM_MAXUSER_ADDRESS-8,%rax
421         cmpq    %rax,%rdi                       /* verify address is valid */
422         ja      fusufault
423
424         xorl    %eax,%eax
425         movq    (%rdi),%r11
426         movq    %rax,PCB_ONFAULT(%rcx)
427         movq    %r11,(%rsi)
428         POP_FRAME_POINTER
429         ret
430 END(fueword64)
431 END(fueword)
432
433 ENTRY(fueword32)
434         PUSH_FRAME_POINTER
435         movq    PCPU(CURPCB),%rcx
436         movq    $fusufault,PCB_ONFAULT(%rcx)
437
438         movq    $VM_MAXUSER_ADDRESS-4,%rax
439         cmpq    %rax,%rdi                       /* verify address is valid */
440         ja      fusufault
441
442         xorl    %eax,%eax
443         movl    (%rdi),%r11d
444         movq    %rax,PCB_ONFAULT(%rcx)
445         movl    %r11d,(%rsi)
446         POP_FRAME_POINTER
447         ret
448 END(fueword32)
449
450 ENTRY(fuword16)
451         PUSH_FRAME_POINTER
452         movq    PCPU(CURPCB),%rcx
453         movq    $fusufault,PCB_ONFAULT(%rcx)
454
455         movq    $VM_MAXUSER_ADDRESS-2,%rax
456         cmpq    %rax,%rdi
457         ja      fusufault
458
459         movzwl  (%rdi),%eax
460         movq    $0,PCB_ONFAULT(%rcx)
461         POP_FRAME_POINTER
462         ret
463 END(fuword16)
464
465 ENTRY(fubyte)
466         PUSH_FRAME_POINTER
467         movq    PCPU(CURPCB),%rcx
468         movq    $fusufault,PCB_ONFAULT(%rcx)
469
470         movq    $VM_MAXUSER_ADDRESS-1,%rax
471         cmpq    %rax,%rdi
472         ja      fusufault
473
474         movzbl  (%rdi),%eax
475         movq    $0,PCB_ONFAULT(%rcx)
476         POP_FRAME_POINTER
477         ret
478 END(fubyte)
479
480         ALIGN_TEXT
481 fusufault:
482         movq    PCPU(CURPCB),%rcx
483         xorl    %eax,%eax
484         movq    %rax,PCB_ONFAULT(%rcx)
485         decq    %rax
486         POP_FRAME_POINTER
487         ret
488
489 /*
490  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
491  * user memory.
492  * addr = %rdi, value = %rsi
493  */
494 ALTENTRY(suword64)
495 ENTRY(suword)
496         PUSH_FRAME_POINTER
497         movq    PCPU(CURPCB),%rcx
498         movq    $fusufault,PCB_ONFAULT(%rcx)
499
500         movq    $VM_MAXUSER_ADDRESS-8,%rax
501         cmpq    %rax,%rdi                       /* verify address validity */
502         ja      fusufault
503
504         movq    %rsi,(%rdi)
505         xorl    %eax,%eax
506         movq    PCPU(CURPCB),%rcx
507         movq    %rax,PCB_ONFAULT(%rcx)
508         POP_FRAME_POINTER
509         ret
510 END(suword64)
511 END(suword)
512
513 ENTRY(suword32)
514         PUSH_FRAME_POINTER
515         movq    PCPU(CURPCB),%rcx
516         movq    $fusufault,PCB_ONFAULT(%rcx)
517
518         movq    $VM_MAXUSER_ADDRESS-4,%rax
519         cmpq    %rax,%rdi                       /* verify address validity */
520         ja      fusufault
521
522         movl    %esi,(%rdi)
523         xorl    %eax,%eax
524         movq    PCPU(CURPCB),%rcx
525         movq    %rax,PCB_ONFAULT(%rcx)
526         POP_FRAME_POINTER
527         ret
528 END(suword32)
529
530 ENTRY(suword16)
531         PUSH_FRAME_POINTER
532         movq    PCPU(CURPCB),%rcx
533         movq    $fusufault,PCB_ONFAULT(%rcx)
534
535         movq    $VM_MAXUSER_ADDRESS-2,%rax
536         cmpq    %rax,%rdi                       /* verify address validity */
537         ja      fusufault
538
539         movw    %si,(%rdi)
540         xorl    %eax,%eax
541         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
542         movq    %rax,PCB_ONFAULT(%rcx)
543         POP_FRAME_POINTER
544         ret
545 END(suword16)
546
547 ENTRY(subyte)
548         PUSH_FRAME_POINTER
549         movq    PCPU(CURPCB),%rcx
550         movq    $fusufault,PCB_ONFAULT(%rcx)
551
552         movq    $VM_MAXUSER_ADDRESS-1,%rax
553         cmpq    %rax,%rdi                       /* verify address validity */
554         ja      fusufault
555
556         movl    %esi,%eax
557         movb    %al,(%rdi)
558         xorl    %eax,%eax
559         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
560         movq    %rax,PCB_ONFAULT(%rcx)
561         POP_FRAME_POINTER
562         ret
563 END(subyte)
564
565 /*
566  * copyinstr(from, to, maxlen, int *lencopied)
567  *           %rdi, %rsi, %rdx, %rcx
568  *
569  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
570  *      return ENAMETOOLONG if string is longer than maxlen, and
571  *      EFAULT on protection violations. If lencopied is non-zero,
572  *      return the actual length in *lencopied.
573  */
574 ENTRY(copyinstr)
575         PUSH_FRAME_POINTER
576         movq    %rdx,%r8                        /* %r8 = maxlen */
577         movq    %rcx,%r9                        /* %r9 = *len */
578         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
579         movq    PCPU(CURPCB),%rcx
580         movq    $cpystrflt,PCB_ONFAULT(%rcx)
581
582         movq    $VM_MAXUSER_ADDRESS,%rax
583
584         /* make sure 'from' is within bounds */
585         subq    %rsi,%rax
586         jbe     cpystrflt
587
588         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
589         cmpq    %rdx,%rax
590         jae     1f
591         movq    %rax,%rdx
592         movq    %rax,%r8
593 1:
594         incq    %rdx
595
596 2:
597         decq    %rdx
598         jz      3f
599
600         lodsb
601         stosb
602         orb     %al,%al
603         jnz     2b
604
605         /* Success -- 0 byte reached */
606         decq    %rdx
607         xorl    %eax,%eax
608         jmp     cpystrflt_x
609 3:
610         /* rdx is zero - return ENAMETOOLONG or EFAULT */
611         movq    $VM_MAXUSER_ADDRESS,%rax
612         cmpq    %rax,%rsi
613         jae     cpystrflt
614 4:
615         movq    $ENAMETOOLONG,%rax
616         jmp     cpystrflt_x
617
618 cpystrflt:
619         movq    $EFAULT,%rax
620
621 cpystrflt_x:
622         /* set *lencopied and return %eax */
623         movq    PCPU(CURPCB),%rcx
624         movq    $0,PCB_ONFAULT(%rcx)
625
626         testq   %r9,%r9
627         jz      1f
628         subq    %rdx,%r8
629         movq    %r8,(%r9)
630 1:
631         POP_FRAME_POINTER
632         ret
633 END(copyinstr)
634
635 /*
636  * copystr(from, to, maxlen, int *lencopied)
637  *         %rdi, %rsi, %rdx, %rcx
638  */
639 ENTRY(copystr)
640         PUSH_FRAME_POINTER
641         movq    %rdx,%r8                        /* %r8 = maxlen */
642
643         xchgq   %rdi,%rsi
644         incq    %rdx
645 1:
646         decq    %rdx
647         jz      4f
648         lodsb
649         stosb
650         orb     %al,%al
651         jnz     1b
652
653         /* Success -- 0 byte reached */
654         decq    %rdx
655         xorl    %eax,%eax
656         jmp     6f
657 4:
658         /* rdx is zero -- return ENAMETOOLONG */
659         movq    $ENAMETOOLONG,%rax
660
661 6:
662
663         testq   %rcx,%rcx
664         jz      7f
665         /* set *lencopied and return %rax */
666         subq    %rdx,%r8
667         movq    %r8,(%rcx)
668 7:
669         POP_FRAME_POINTER
670         ret
671 END(copystr)
672
673 /*
674  * Handling of special amd64 registers and descriptor tables etc
675  */
676 /* void lgdt(struct region_descriptor *rdp); */
677 ENTRY(lgdt)
678         /* reload the descriptor table */
679         lgdt    (%rdi)
680
681         /* flush the prefetch q */
682         jmp     1f
683         nop
684 1:
685         movl    $KDSEL,%eax
686         movl    %eax,%ds
687         movl    %eax,%es
688         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
689         movl    %eax,%gs
690         movl    %eax,%ss
691
692         /* reload code selector by turning return into intersegmental return */
693         popq    %rax
694         pushq   $KCSEL
695         pushq   %rax
696         MEXITCOUNT
697         lretq
698 END(lgdt)
699
700 /*****************************************************************************/
701 /* setjump, longjump                                                         */
702 /*****************************************************************************/
703
704 ENTRY(setjmp)
705         movq    %rbx,0(%rdi)                    /* save rbx */
706         movq    %rsp,8(%rdi)                    /* save rsp */
707         movq    %rbp,16(%rdi)                   /* save rbp */
708         movq    %r12,24(%rdi)                   /* save r12 */
709         movq    %r13,32(%rdi)                   /* save r13 */
710         movq    %r14,40(%rdi)                   /* save r14 */
711         movq    %r15,48(%rdi)                   /* save r15 */
712         movq    0(%rsp),%rdx                    /* get rta */
713         movq    %rdx,56(%rdi)                   /* save rip */
714         xorl    %eax,%eax                       /* return(0); */
715         ret
716 END(setjmp)
717
718 ENTRY(longjmp)
719         movq    0(%rdi),%rbx                    /* restore rbx */
720         movq    8(%rdi),%rsp                    /* restore rsp */
721         movq    16(%rdi),%rbp                   /* restore rbp */
722         movq    24(%rdi),%r12                   /* restore r12 */
723         movq    32(%rdi),%r13                   /* restore r13 */
724         movq    40(%rdi),%r14                   /* restore r14 */
725         movq    48(%rdi),%r15                   /* restore r15 */
726         movq    56(%rdi),%rdx                   /* get rta */
727         movq    %rdx,0(%rsp)                    /* put in return frame */
728         xorl    %eax,%eax                       /* return(1); */
729         incl    %eax
730         ret
731 END(longjmp)
732
733 /*
734  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
735  * return an error.)
736  */
737 ENTRY(rdmsr_safe)
738 /* int rdmsr_safe(u_int msr, uint64_t *data) */
739         PUSH_FRAME_POINTER
740         movq    PCPU(CURPCB),%r8
741         movq    $msr_onfault,PCB_ONFAULT(%r8)
742         movl    %edi,%ecx
743         rdmsr                   /* Read MSR pointed by %ecx. Returns
744                                    hi byte in edx, lo in %eax */
745         salq    $32,%rdx        /* sign-shift %rdx left */
746         movl    %eax,%eax       /* zero-extend %eax -> %rax */
747         orq     %rdx,%rax
748         movq    %rax,(%rsi)
749         xorq    %rax,%rax
750         movq    %rax,PCB_ONFAULT(%r8)
751         POP_FRAME_POINTER
752         ret
753
754 /*
755  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
756  * return an error.)
757  */
758 ENTRY(wrmsr_safe)
759 /* int wrmsr_safe(u_int msr, uint64_t data) */
760         PUSH_FRAME_POINTER
761         movq    PCPU(CURPCB),%r8
762         movq    $msr_onfault,PCB_ONFAULT(%r8)
763         movl    %edi,%ecx
764         movl    %esi,%eax
765         sarq    $32,%rsi
766         movl    %esi,%edx
767         wrmsr                   /* Write MSR pointed by %ecx. Accepts
768                                    hi byte in edx, lo in %eax. */
769         xorq    %rax,%rax
770         movq    %rax,PCB_ONFAULT(%r8)
771         POP_FRAME_POINTER
772         ret
773
774 /*
775  * MSR operations fault handler
776  */
777         ALIGN_TEXT
778 msr_onfault:
779         movq    $0,PCB_ONFAULT(%r8)
780         movl    $EFAULT,%eax
781         POP_FRAME_POINTER
782         ret
783
784 /*
785  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
786  * Invalidates address space addressed by ucr3, then returns to kcr3.
787  * Done in assembler to ensure no other memory accesses happen while
788  * on ucr3.
789  */
790         ALIGN_TEXT
791 ENTRY(pmap_pti_pcid_invalidate)
792         pushfq
793         cli
794         movq    %rdi,%cr3       /* to user page table */
795         movq    %rsi,%cr3       /* back to kernel */
796         popfq
797         retq
798
799 /*
800  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
801  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
802  */
803         ALIGN_TEXT
804 ENTRY(pmap_pti_pcid_invlpg)
805         pushfq
806         cli
807         movq    %rdi,%cr3       /* to user page table */
808         invlpg  (%rdx)
809         movq    %rsi,%cr3       /* back to kernel */
810         popfq
811         retq
812
813 /*
814  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
815  *     vm_offset_t eva);
816  * Invalidates virtual addresses between sva and eva in address space ucr3,
817  * then returns to kcr3.
818  */
819         ALIGN_TEXT
820 ENTRY(pmap_pti_pcid_invlrng)
821         pushfq
822         cli
823         movq    %rdi,%cr3       /* to user page table */
824 1:      invlpg  (%rdx)
825         addq    $PAGE_SIZE,%rdx
826         cmpq    %rdx,%rcx
827         ja      1b
828         movq    %rsi,%cr3       /* back to kernel */
829         popfq
830         retq
831
832         .altmacro
833         .macro  ibrs_seq_label l
834 handle_ibrs_\l:
835         .endm
836         .macro  ibrs_call_label l
837         call    handle_ibrs_\l
838         .endm
839         .macro  ibrs_seq count
840         ll=1
841         .rept   \count
842         ibrs_call_label %(ll)
843         nop
844         ibrs_seq_label %(ll)
845         addq    $8,%rsp
846         ll=ll+1
847         .endr
848         .endm
849
850 /* all callers already saved %rax, %rdx, and %rcx */
851 ENTRY(handle_ibrs_entry)
852         cmpb    $0,hw_ibrs_active(%rip)
853         je      1f
854         movl    $MSR_IA32_SPEC_CTRL,%ecx
855         rdmsr
856         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
857         orl     $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
858         wrmsr
859         movb    $1,PCPU(IBPB_SET)
860         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
861         jne     1f
862         ibrs_seq 32
863 1:      ret
864 END(handle_ibrs_entry)
865
866 ENTRY(handle_ibrs_exit)
867         cmpb    $0,PCPU(IBPB_SET)
868         je      1f
869         movl    $MSR_IA32_SPEC_CTRL,%ecx
870         rdmsr
871         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
872         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
873         wrmsr
874         movb    $0,PCPU(IBPB_SET)
875 1:      ret
876 END(handle_ibrs_exit)
877
878 /* registers-neutral version, but needs stack */
879 ENTRY(handle_ibrs_exit_rs)
880         cmpb    $0,PCPU(IBPB_SET)
881         je      1f
882         pushq   %rax
883         pushq   %rdx
884         pushq   %rcx
885         movl    $MSR_IA32_SPEC_CTRL,%ecx
886         rdmsr
887         andl    $~(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
888         andl    $~((IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32),%edx
889         wrmsr
890         popq    %rcx
891         popq    %rdx
892         popq    %rax
893         movb    $0,PCPU(IBPB_SET)
894 1:      ret
895 END(handle_ibrs_exit_rs)
896
897         .noaltmacro