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