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