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