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