]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
Import Intel Processor Trace decoder library from
[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.s"
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 /*
460  * fuswintr() and suswintr() are specialized variants of fuword16() and
461  * suword16(), respectively.  They are called from the profiling code,
462  * potentially at interrupt time.  If they fail, that's okay; good things
463  * will happen later.  They always fail for now, until the trap code is
464  * able to deal with this.
465  */
466 ALTENTRY(suswintr)
467 ENTRY(fuswintr)
468         movq    $-1,%rax
469         ret
470 END(suswintr)
471 END(fuswintr)
472
473 ENTRY(fuword16)
474         PUSH_FRAME_POINTER
475         movq    PCPU(CURPCB),%rcx
476         movq    $fusufault,PCB_ONFAULT(%rcx)
477
478         movq    $VM_MAXUSER_ADDRESS-2,%rax
479         cmpq    %rax,%rdi
480         ja      fusufault
481
482         movzwl  (%rdi),%eax
483         movq    $0,PCB_ONFAULT(%rcx)
484         POP_FRAME_POINTER
485         ret
486 END(fuword16)
487
488 ENTRY(fubyte)
489         PUSH_FRAME_POINTER
490         movq    PCPU(CURPCB),%rcx
491         movq    $fusufault,PCB_ONFAULT(%rcx)
492
493         movq    $VM_MAXUSER_ADDRESS-1,%rax
494         cmpq    %rax,%rdi
495         ja      fusufault
496
497         movzbl  (%rdi),%eax
498         movq    $0,PCB_ONFAULT(%rcx)
499         POP_FRAME_POINTER
500         ret
501 END(fubyte)
502
503         ALIGN_TEXT
504 fusufault:
505         movq    PCPU(CURPCB),%rcx
506         xorl    %eax,%eax
507         movq    %rax,PCB_ONFAULT(%rcx)
508         decq    %rax
509         POP_FRAME_POINTER
510         ret
511
512 /*
513  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
514  * user memory.
515  * addr = %rdi, value = %rsi
516  */
517 ALTENTRY(suword64)
518 ENTRY(suword)
519         PUSH_FRAME_POINTER
520         movq    PCPU(CURPCB),%rcx
521         movq    $fusufault,PCB_ONFAULT(%rcx)
522
523         movq    $VM_MAXUSER_ADDRESS-8,%rax
524         cmpq    %rax,%rdi                       /* verify address validity */
525         ja      fusufault
526
527         movq    %rsi,(%rdi)
528         xorl    %eax,%eax
529         movq    PCPU(CURPCB),%rcx
530         movq    %rax,PCB_ONFAULT(%rcx)
531         POP_FRAME_POINTER
532         ret
533 END(suword64)
534 END(suword)
535
536 ENTRY(suword32)
537         PUSH_FRAME_POINTER
538         movq    PCPU(CURPCB),%rcx
539         movq    $fusufault,PCB_ONFAULT(%rcx)
540
541         movq    $VM_MAXUSER_ADDRESS-4,%rax
542         cmpq    %rax,%rdi                       /* verify address validity */
543         ja      fusufault
544
545         movl    %esi,(%rdi)
546         xorl    %eax,%eax
547         movq    PCPU(CURPCB),%rcx
548         movq    %rax,PCB_ONFAULT(%rcx)
549         POP_FRAME_POINTER
550         ret
551 END(suword32)
552
553 ENTRY(suword16)
554         PUSH_FRAME_POINTER
555         movq    PCPU(CURPCB),%rcx
556         movq    $fusufault,PCB_ONFAULT(%rcx)
557
558         movq    $VM_MAXUSER_ADDRESS-2,%rax
559         cmpq    %rax,%rdi                       /* verify address validity */
560         ja      fusufault
561
562         movw    %si,(%rdi)
563         xorl    %eax,%eax
564         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
565         movq    %rax,PCB_ONFAULT(%rcx)
566         POP_FRAME_POINTER
567         ret
568 END(suword16)
569
570 ENTRY(subyte)
571         PUSH_FRAME_POINTER
572         movq    PCPU(CURPCB),%rcx
573         movq    $fusufault,PCB_ONFAULT(%rcx)
574
575         movq    $VM_MAXUSER_ADDRESS-1,%rax
576         cmpq    %rax,%rdi                       /* verify address validity */
577         ja      fusufault
578
579         movl    %esi,%eax
580         movb    %al,(%rdi)
581         xorl    %eax,%eax
582         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
583         movq    %rax,PCB_ONFAULT(%rcx)
584         POP_FRAME_POINTER
585         ret
586 END(subyte)
587
588 /*
589  * copyinstr(from, to, maxlen, int *lencopied)
590  *           %rdi, %rsi, %rdx, %rcx
591  *
592  *      copy a string from 'from' to 'to', stop when a 0 character is reached.
593  *      return ENAMETOOLONG if string is longer than maxlen, and
594  *      EFAULT on protection violations. If lencopied is non-zero,
595  *      return the actual length in *lencopied.
596  */
597 ENTRY(copyinstr)
598         PUSH_FRAME_POINTER
599         movq    %rdx,%r8                        /* %r8 = maxlen */
600         movq    %rcx,%r9                        /* %r9 = *len */
601         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
602         movq    PCPU(CURPCB),%rcx
603         movq    $cpystrflt,PCB_ONFAULT(%rcx)
604
605         movq    $VM_MAXUSER_ADDRESS,%rax
606
607         /* make sure 'from' is within bounds */
608         subq    %rsi,%rax
609         jbe     cpystrflt
610
611         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
612         cmpq    %rdx,%rax
613         jae     1f
614         movq    %rax,%rdx
615         movq    %rax,%r8
616 1:
617         incq    %rdx
618
619 2:
620         decq    %rdx
621         jz      3f
622
623         lodsb
624         stosb
625         orb     %al,%al
626         jnz     2b
627
628         /* Success -- 0 byte reached */
629         decq    %rdx
630         xorl    %eax,%eax
631         jmp     cpystrflt_x
632 3:
633         /* rdx is zero - return ENAMETOOLONG or EFAULT */
634         movq    $VM_MAXUSER_ADDRESS,%rax
635         cmpq    %rax,%rsi
636         jae     cpystrflt
637 4:
638         movq    $ENAMETOOLONG,%rax
639         jmp     cpystrflt_x
640
641 cpystrflt:
642         movq    $EFAULT,%rax
643
644 cpystrflt_x:
645         /* set *lencopied and return %eax */
646         movq    PCPU(CURPCB),%rcx
647         movq    $0,PCB_ONFAULT(%rcx)
648
649         testq   %r9,%r9
650         jz      1f
651         subq    %rdx,%r8
652         movq    %r8,(%r9)
653 1:
654         POP_FRAME_POINTER
655         ret
656 END(copyinstr)
657
658 /*
659  * copystr(from, to, maxlen, int *lencopied)
660  *         %rdi, %rsi, %rdx, %rcx
661  */
662 ENTRY(copystr)
663         PUSH_FRAME_POINTER
664         movq    %rdx,%r8                        /* %r8 = maxlen */
665
666         xchgq   %rdi,%rsi
667         incq    %rdx
668 1:
669         decq    %rdx
670         jz      4f
671         lodsb
672         stosb
673         orb     %al,%al
674         jnz     1b
675
676         /* Success -- 0 byte reached */
677         decq    %rdx
678         xorl    %eax,%eax
679         jmp     6f
680 4:
681         /* rdx is zero -- return ENAMETOOLONG */
682         movq    $ENAMETOOLONG,%rax
683
684 6:
685
686         testq   %rcx,%rcx
687         jz      7f
688         /* set *lencopied and return %rax */
689         subq    %rdx,%r8
690         movq    %r8,(%rcx)
691 7:
692         POP_FRAME_POINTER
693         ret
694 END(copystr)
695
696 /*
697  * Handling of special amd64 registers and descriptor tables etc
698  */
699 /* void lgdt(struct region_descriptor *rdp); */
700 ENTRY(lgdt)
701         /* reload the descriptor table */
702         lgdt    (%rdi)
703
704         /* flush the prefetch q */
705         jmp     1f
706         nop
707 1:
708         movl    $KDSEL,%eax
709         movl    %eax,%ds
710         movl    %eax,%es
711         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
712         movl    %eax,%gs
713         movl    %eax,%ss
714
715         /* reload code selector by turning return into intersegmental return */
716         popq    %rax
717         pushq   $KCSEL
718         pushq   %rax
719         MEXITCOUNT
720         lretq
721 END(lgdt)
722
723 /*****************************************************************************/
724 /* setjump, longjump                                                         */
725 /*****************************************************************************/
726
727 ENTRY(setjmp)
728         movq    %rbx,0(%rdi)                    /* save rbx */
729         movq    %rsp,8(%rdi)                    /* save rsp */
730         movq    %rbp,16(%rdi)                   /* save rbp */
731         movq    %r12,24(%rdi)                   /* save r12 */
732         movq    %r13,32(%rdi)                   /* save r13 */
733         movq    %r14,40(%rdi)                   /* save r14 */
734         movq    %r15,48(%rdi)                   /* save r15 */
735         movq    0(%rsp),%rdx                    /* get rta */
736         movq    %rdx,56(%rdi)                   /* save rip */
737         xorl    %eax,%eax                       /* return(0); */
738         ret
739 END(setjmp)
740
741 ENTRY(longjmp)
742         movq    0(%rdi),%rbx                    /* restore rbx */
743         movq    8(%rdi),%rsp                    /* restore rsp */
744         movq    16(%rdi),%rbp                   /* restore rbp */
745         movq    24(%rdi),%r12                   /* restore r12 */
746         movq    32(%rdi),%r13                   /* restore r13 */
747         movq    40(%rdi),%r14                   /* restore r14 */
748         movq    48(%rdi),%r15                   /* restore r15 */
749         movq    56(%rdi),%rdx                   /* get rta */
750         movq    %rdx,0(%rsp)                    /* put in return frame */
751         xorl    %eax,%eax                       /* return(1); */
752         incl    %eax
753         ret
754 END(longjmp)
755
756 /*
757  * Support for reading MSRs in the safe manner.  (Instead of panic on #gp,
758  * return an error.)
759  */
760 ENTRY(rdmsr_safe)
761 /* int rdmsr_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         rdmsr                   /* Read MSR pointed by %ecx. Returns
767                                    hi byte in edx, lo in %eax */
768         salq    $32,%rdx        /* sign-shift %rdx left */
769         movl    %eax,%eax       /* zero-extend %eax -> %rax */
770         orq     %rdx,%rax
771         movq    %rax,(%rsi)
772         xorq    %rax,%rax
773         movq    %rax,PCB_ONFAULT(%r8)
774         POP_FRAME_POINTER
775         ret
776
777 /*
778  * Support for writing MSRs in the safe manner.  (Instead of panic on #gp,
779  * return an error.)
780  */
781 ENTRY(wrmsr_safe)
782 /* int wrmsr_safe(u_int msr, uint64_t data) */
783         PUSH_FRAME_POINTER
784         movq    PCPU(CURPCB),%r8
785         movq    $msr_onfault,PCB_ONFAULT(%r8)
786         movl    %edi,%ecx
787         movl    %esi,%eax
788         sarq    $32,%rsi
789         movl    %esi,%edx
790         wrmsr                   /* Write MSR pointed by %ecx. Accepts
791                                    hi byte in edx, lo in %eax. */
792         xorq    %rax,%rax
793         movq    %rax,PCB_ONFAULT(%r8)
794         POP_FRAME_POINTER
795         ret
796
797 /*
798  * MSR operations fault handler
799  */
800         ALIGN_TEXT
801 msr_onfault:
802         movq    $0,PCB_ONFAULT(%r8)
803         movl    $EFAULT,%eax
804         POP_FRAME_POINTER
805         ret
806
807 /*
808  * void pmap_pti_pcid_invalidate(uint64_t ucr3, uint64_t kcr3);
809  * Invalidates address space addressed by ucr3, then returns to kcr3.
810  * Done in assembler to ensure no other memory accesses happen while
811  * on ucr3.
812  */
813         ALIGN_TEXT
814 ENTRY(pmap_pti_pcid_invalidate)
815         pushfq
816         cli
817         movq    %rdi,%cr3       /* to user page table */
818         movq    %rsi,%cr3       /* back to kernel */
819         popfq
820         retq
821
822 /*
823  * void pmap_pti_pcid_invlpg(uint64_t ucr3, uint64_t kcr3, vm_offset_t va);
824  * Invalidates virtual address va in address space ucr3, then returns to kcr3.
825  */
826         ALIGN_TEXT
827 ENTRY(pmap_pti_pcid_invlpg)
828         pushfq
829         cli
830         movq    %rdi,%cr3       /* to user page table */
831         invlpg  (%rdx)
832         movq    %rsi,%cr3       /* back to kernel */
833         popfq
834         retq
835
836 /*
837  * void pmap_pti_pcid_invlrng(uint64_t ucr3, uint64_t kcr3, vm_offset_t sva,
838  *     vm_offset_t eva);
839  * Invalidates virtual addresses between sva and eva in address space ucr3,
840  * then returns to kcr3.
841  */
842         ALIGN_TEXT
843 ENTRY(pmap_pti_pcid_invlrng)
844         pushfq
845         cli
846         movq    %rdi,%cr3       /* to user page table */
847 1:      invlpg  (%rdx)
848         addq    $PAGE_SIZE,%rdx
849         cmpq    %rdx,%rcx
850         ja      1b
851         movq    %rsi,%cr3       /* back to kernel */
852         popfq
853         retq
854
855         .altmacro
856         .macro  ibrs_seq_label l
857 handle_ibrs_\l:
858         .endm
859         .macro  ibrs_call_label l
860         call    handle_ibrs_\l
861         .endm
862         .macro  ibrs_seq count
863         ll=1
864         .rept   \count
865         ibrs_call_label %(ll)
866         nop
867         ibrs_seq_label %(ll)
868         addq    $8,%rsp
869         ll=ll+1
870         .endr
871         .endm
872
873 /* all callers already saved %rax, %rdx, and %rcx */
874 ENTRY(handle_ibrs_entry)
875         cmpb    $0,hw_ibrs_active(%rip)
876         je      1f
877         movl    $MSR_IA32_SPEC_CTRL,%ecx
878         movl    $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP),%eax
879         movl    $(IA32_SPEC_CTRL_IBRS|IA32_SPEC_CTRL_STIBP)>>32,%edx
880         wrmsr
881         movb    $1,PCPU(IBPB_SET)
882         testl   $CPUID_STDEXT_SMEP,cpu_stdext_feature(%rip)
883         jne     1f
884         ibrs_seq 32
885 1:      ret
886 END(handle_ibrs_entry)
887
888 ENTRY(handle_ibrs_exit)
889         cmpb    $0,PCPU(IBPB_SET)
890         je      1f
891         movl    $MSR_IA32_SPEC_CTRL,%ecx
892         xorl    %eax,%eax
893         xorl    %edx,%edx
894         wrmsr
895         movb    $0,PCPU(IBPB_SET)
896 1:      ret
897 END(handle_ibrs_exit)
898
899 /* registers-neutral version, but needs stack */
900 ENTRY(handle_ibrs_exit_rs)
901         cmpb    $0,PCPU(IBPB_SET)
902         je      1f
903         pushq   %rax
904         pushq   %rdx
905         pushq   %rcx
906         movl    $MSR_IA32_SPEC_CTRL,%ecx
907         xorl    %eax,%eax
908         xorl    %edx,%edx
909         wrmsr
910         popq    %rcx
911         popq    %rdx
912         popq    %rax
913         movb    $0,PCPU(IBPB_SET)
914 1:      ret
915 END(handle_ibrs_exit_rs)
916
917         .noaltmacro