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