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