]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/support.S
Merge ^/head r320573 through r320970.
[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)  - MP SAFE
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.  If 486 write protection
253          * is being used, this check is essential because we are in kernel
254          * mode so the h/w does not provide any protection against writing
255          * kernel addresses.
256          */
257
258         /*
259          * First, prevent address wrapping.
260          */
261         movq    %rsi,%rax
262         addq    %rdx,%rax
263         jc      copyout_fault
264 /*
265  * XXX STOP USING VM_MAXUSER_ADDRESS.
266  * It is an end address, not a max, so every time it is used correctly it
267  * looks like there is an off by one error, and of course it caused an off
268  * by one error in several places.
269  */
270         movq    $VM_MAXUSER_ADDRESS,%rcx
271         cmpq    %rcx,%rax
272         ja      copyout_fault
273
274         xchgq   %rdi,%rsi
275         /* bcopy(%rsi, %rdi, %rdx) */
276         movq    %rdx,%rcx
277
278         shrq    $3,%rcx
279         cld
280         rep
281         movsq
282         movb    %dl,%cl
283         andb    $7,%cl
284         rep
285         movsb
286
287 done_copyout:
288         xorl    %eax,%eax
289         movq    PCPU(CURPCB),%rdx
290         movq    %rax,PCB_ONFAULT(%rdx)
291         POP_FRAME_POINTER
292         ret
293
294         ALIGN_TEXT
295 copyout_fault:
296         movq    PCPU(CURPCB),%rdx
297         movq    $0,PCB_ONFAULT(%rdx)
298         movq    $EFAULT,%rax
299         POP_FRAME_POINTER
300         ret
301 END(copyout)
302
303 /*
304  * copyin(from_user, to_kernel, len) - MP SAFE
305  *        %rdi,      %rsi,      %rdx
306  */
307 ENTRY(copyin)
308         PUSH_FRAME_POINTER
309         movq    PCPU(CURPCB),%rax
310         movq    $copyin_fault,PCB_ONFAULT(%rax)
311         testq   %rdx,%rdx                       /* anything to do? */
312         jz      done_copyin
313
314         /*
315          * make sure address is valid
316          */
317         movq    %rdi,%rax
318         addq    %rdx,%rax
319         jc      copyin_fault
320         movq    $VM_MAXUSER_ADDRESS,%rcx
321         cmpq    %rcx,%rax
322         ja      copyin_fault
323
324         xchgq   %rdi,%rsi
325         movq    %rdx,%rcx
326         movb    %cl,%al
327         shrq    $3,%rcx                         /* copy longword-wise */
328         cld
329         rep
330         movsq
331         movb    %al,%cl
332         andb    $7,%cl                          /* copy remaining bytes */
333         rep
334         movsb
335
336 done_copyin:
337         xorl    %eax,%eax
338         movq    PCPU(CURPCB),%rdx
339         movq    %rax,PCB_ONFAULT(%rdx)
340         POP_FRAME_POINTER
341         ret
342
343         ALIGN_TEXT
344 copyin_fault:
345         movq    PCPU(CURPCB),%rdx
346         movq    $0,PCB_ONFAULT(%rdx)
347         movq    $EFAULT,%rax
348         POP_FRAME_POINTER
349         ret
350 END(copyin)
351
352 /*
353  * casueword32.  Compare and set user integer.  Returns -1 on fault,
354  *        0 if access was successful.  Old value is written to *oldp.
355  *        dst = %rdi, old = %esi, oldp = %rdx, new = %ecx
356  */
357 ENTRY(casueword32)
358         PUSH_FRAME_POINTER
359         movq    PCPU(CURPCB),%r8
360         movq    $fusufault,PCB_ONFAULT(%r8)
361
362         movq    $VM_MAXUSER_ADDRESS-4,%rax
363         cmpq    %rax,%rdi                       /* verify address is valid */
364         ja      fusufault
365
366         movl    %esi,%eax                       /* old */
367 #ifdef SMP
368         lock
369 #endif
370         cmpxchgl %ecx,(%rdi)                    /* new = %ecx */
371
372         /*
373          * The old value is in %eax.  If the store succeeded it will be the
374          * value we expected (old) from before the store, otherwise it will
375          * be the current value.  Save %eax into %esi to prepare the return
376          * value.
377          */
378         movl    %eax,%esi
379         xorl    %eax,%eax
380         movq    %rax,PCB_ONFAULT(%r8)
381
382         /*
383          * Access the oldp after the pcb_onfault is cleared, to correctly
384          * catch corrupted pointer.
385          */
386         movl    %esi,(%rdx)                     /* oldp = %rdx */
387         POP_FRAME_POINTER
388         ret
389 END(casueword32)
390
391 /*
392  * casueword.  Compare and set user long.  Returns -1 on fault,
393  *        0 if access was successful.  Old value is written to *oldp.
394  *        dst = %rdi, old = %rsi, oldp = %rdx, new = %rcx
395  */
396 ENTRY(casueword)
397         PUSH_FRAME_POINTER
398         movq    PCPU(CURPCB),%r8
399         movq    $fusufault,PCB_ONFAULT(%r8)
400
401         movq    $VM_MAXUSER_ADDRESS-4,%rax
402         cmpq    %rax,%rdi                       /* verify address is valid */
403         ja      fusufault
404
405         movq    %rsi,%rax                       /* old */
406 #ifdef SMP
407         lock
408 #endif
409         cmpxchgq %rcx,(%rdi)                    /* new = %rcx */
410
411         /*
412          * The old value is in %rax.  If the store succeeded it will be the
413          * value we expected (old) from before the store, otherwise it will
414          * be the current value.
415          */
416         movq    %rax,%rsi
417         xorl    %eax,%eax
418         movq    %rax,PCB_ONFAULT(%r8)
419         movq    %rsi,(%rdx)
420         POP_FRAME_POINTER
421         ret
422 END(casueword)
423
424 /*
425  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
426  * byte from user memory.
427  * addr = %rdi, valp = %rsi
428  */
429
430 ALTENTRY(fueword64)
431 ENTRY(fueword)
432         PUSH_FRAME_POINTER
433         movq    PCPU(CURPCB),%rcx
434         movq    $fusufault,PCB_ONFAULT(%rcx)
435
436         movq    $VM_MAXUSER_ADDRESS-8,%rax
437         cmpq    %rax,%rdi                       /* verify address is valid */
438         ja      fusufault
439
440         xorl    %eax,%eax
441         movq    (%rdi),%r11
442         movq    %rax,PCB_ONFAULT(%rcx)
443         movq    %r11,(%rsi)
444         POP_FRAME_POINTER
445         ret
446 END(fueword64)
447 END(fueword)
448
449 ENTRY(fueword32)
450         PUSH_FRAME_POINTER
451         movq    PCPU(CURPCB),%rcx
452         movq    $fusufault,PCB_ONFAULT(%rcx)
453
454         movq    $VM_MAXUSER_ADDRESS-4,%rax
455         cmpq    %rax,%rdi                       /* verify address is valid */
456         ja      fusufault
457
458         xorl    %eax,%eax
459         movl    (%rdi),%r11d
460         movq    %rax,PCB_ONFAULT(%rcx)
461         movl    %r11d,(%rsi)
462         POP_FRAME_POINTER
463         ret
464 END(fueword32)
465
466 /*
467  * fuswintr() and suswintr() are specialized variants of fuword16() and
468  * suword16(), respectively.  They are called from the profiling code,
469  * potentially at interrupt time.  If they fail, that's okay; good things
470  * will happen later.  They always fail for now, until the trap code is
471  * able to deal with this.
472  */
473 ALTENTRY(suswintr)
474 ENTRY(fuswintr)
475         movq    $-1,%rax
476         ret
477 END(suswintr)
478 END(fuswintr)
479
480 ENTRY(fuword16)
481         PUSH_FRAME_POINTER
482         movq    PCPU(CURPCB),%rcx
483         movq    $fusufault,PCB_ONFAULT(%rcx)
484
485         movq    $VM_MAXUSER_ADDRESS-2,%rax
486         cmpq    %rax,%rdi
487         ja      fusufault
488
489         movzwl  (%rdi),%eax
490         movq    $0,PCB_ONFAULT(%rcx)
491         POP_FRAME_POINTER
492         ret
493 END(fuword16)
494
495 ENTRY(fubyte)
496         PUSH_FRAME_POINTER
497         movq    PCPU(CURPCB),%rcx
498         movq    $fusufault,PCB_ONFAULT(%rcx)
499
500         movq    $VM_MAXUSER_ADDRESS-1,%rax
501         cmpq    %rax,%rdi
502         ja      fusufault
503
504         movzbl  (%rdi),%eax
505         movq    $0,PCB_ONFAULT(%rcx)
506         POP_FRAME_POINTER
507         ret
508 END(fubyte)
509
510         ALIGN_TEXT
511 fusufault:
512         movq    PCPU(CURPCB),%rcx
513         xorl    %eax,%eax
514         movq    %rax,PCB_ONFAULT(%rcx)
515         decq    %rax
516         POP_FRAME_POINTER
517         ret
518
519 /*
520  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
521  * user memory.  All these functions are MPSAFE.
522  * addr = %rdi, value = %rsi
523  */
524 ALTENTRY(suword64)
525 ENTRY(suword)
526         PUSH_FRAME_POINTER
527         movq    PCPU(CURPCB),%rcx
528         movq    $fusufault,PCB_ONFAULT(%rcx)
529
530         movq    $VM_MAXUSER_ADDRESS-8,%rax
531         cmpq    %rax,%rdi                       /* verify address validity */
532         ja      fusufault
533
534         movq    %rsi,(%rdi)
535         xorl    %eax,%eax
536         movq    PCPU(CURPCB),%rcx
537         movq    %rax,PCB_ONFAULT(%rcx)
538         POP_FRAME_POINTER
539         ret
540 END(suword64)
541 END(suword)
542
543 ENTRY(suword32)
544         PUSH_FRAME_POINTER
545         movq    PCPU(CURPCB),%rcx
546         movq    $fusufault,PCB_ONFAULT(%rcx)
547
548         movq    $VM_MAXUSER_ADDRESS-4,%rax
549         cmpq    %rax,%rdi                       /* verify address validity */
550         ja      fusufault
551
552         movl    %esi,(%rdi)
553         xorl    %eax,%eax
554         movq    PCPU(CURPCB),%rcx
555         movq    %rax,PCB_ONFAULT(%rcx)
556         POP_FRAME_POINTER
557         ret
558 END(suword32)
559
560 ENTRY(suword16)
561         PUSH_FRAME_POINTER
562         movq    PCPU(CURPCB),%rcx
563         movq    $fusufault,PCB_ONFAULT(%rcx)
564
565         movq    $VM_MAXUSER_ADDRESS-2,%rax
566         cmpq    %rax,%rdi                       /* verify address validity */
567         ja      fusufault
568
569         movw    %si,(%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(suword16)
576
577 ENTRY(subyte)
578         PUSH_FRAME_POINTER
579         movq    PCPU(CURPCB),%rcx
580         movq    $fusufault,PCB_ONFAULT(%rcx)
581
582         movq    $VM_MAXUSER_ADDRESS-1,%rax
583         cmpq    %rax,%rdi                       /* verify address validity */
584         ja      fusufault
585
586         movl    %esi,%eax
587         movb    %al,(%rdi)
588         xorl    %eax,%eax
589         movq    PCPU(CURPCB),%rcx               /* restore trashed register */
590         movq    %rax,PCB_ONFAULT(%rcx)
591         POP_FRAME_POINTER
592         ret
593 END(subyte)
594
595 /*
596  * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
597  *           %rdi, %rsi, %rdx, %rcx
598  *
599  *      copy a string from from to to, stop when a 0 character is reached.
600  *      return ENAMETOOLONG if string is longer than maxlen, and
601  *      EFAULT on protection violations. If lencopied is non-zero,
602  *      return the actual length in *lencopied.
603  */
604 ENTRY(copyinstr)
605         PUSH_FRAME_POINTER
606         movq    %rdx,%r8                        /* %r8 = maxlen */
607         movq    %rcx,%r9                        /* %r9 = *len */
608         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
609         movq    PCPU(CURPCB),%rcx
610         movq    $cpystrflt,PCB_ONFAULT(%rcx)
611
612         movq    $VM_MAXUSER_ADDRESS,%rax
613
614         /* make sure 'from' is within bounds */
615         subq    %rsi,%rax
616         jbe     cpystrflt
617
618         /* restrict maxlen to <= VM_MAXUSER_ADDRESS-from */
619         cmpq    %rdx,%rax
620         jae     1f
621         movq    %rax,%rdx
622         movq    %rax,%r8
623 1:
624         incq    %rdx
625         cld
626
627 2:
628         decq    %rdx
629         jz      3f
630
631         lodsb
632         stosb
633         orb     %al,%al
634         jnz     2b
635
636         /* Success -- 0 byte reached */
637         decq    %rdx
638         xorl    %eax,%eax
639         jmp     cpystrflt_x
640 3:
641         /* rdx is zero - return ENAMETOOLONG or EFAULT */
642         movq    $VM_MAXUSER_ADDRESS,%rax
643         cmpq    %rax,%rsi
644         jae     cpystrflt
645 4:
646         movq    $ENAMETOOLONG,%rax
647         jmp     cpystrflt_x
648
649 cpystrflt:
650         movq    $EFAULT,%rax
651
652 cpystrflt_x:
653         /* set *lencopied and return %eax */
654         movq    PCPU(CURPCB),%rcx
655         movq    $0,PCB_ONFAULT(%rcx)
656
657         testq   %r9,%r9
658         jz      1f
659         subq    %rdx,%r8
660         movq    %r8,(%r9)
661 1:
662         POP_FRAME_POINTER
663         ret
664 END(copyinstr)
665
666 /*
667  * copystr(from, to, maxlen, int *lencopied) - MP SAFE
668  *         %rdi, %rsi, %rdx, %rcx
669  */
670 ENTRY(copystr)
671         PUSH_FRAME_POINTER
672         movq    %rdx,%r8                        /* %r8 = maxlen */
673
674         xchgq   %rdi,%rsi
675         incq    %rdx
676         cld
677 1:
678         decq    %rdx
679         jz      4f
680         lodsb
681         stosb
682         orb     %al,%al
683         jnz     1b
684
685         /* Success -- 0 byte reached */
686         decq    %rdx
687         xorl    %eax,%eax
688         jmp     6f
689 4:
690         /* rdx is zero -- return ENAMETOOLONG */
691         movq    $ENAMETOOLONG,%rax
692
693 6:
694
695         testq   %rcx,%rcx
696         jz      7f
697         /* set *lencopied and return %rax */
698         subq    %rdx,%r8
699         movq    %r8,(%rcx)
700 7:
701         POP_FRAME_POINTER
702         ret
703 END(copystr)
704
705 /*
706  * Handling of special amd64 registers and descriptor tables etc
707  * %rdi
708  */
709 /* void lgdt(struct region_descriptor *rdp); */
710 ENTRY(lgdt)
711         /* reload the descriptor table */
712         lgdt    (%rdi)
713
714         /* flush the prefetch q */
715         jmp     1f
716         nop
717 1:
718         movl    $KDSEL,%eax
719         movl    %eax,%ds
720         movl    %eax,%es
721         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
722         movl    %eax,%gs
723         movl    %eax,%ss
724
725         /* reload code selector by turning return into intersegmental return */
726         popq    %rax
727         pushq   $KCSEL
728         pushq   %rax
729         MEXITCOUNT
730         lretq
731 END(lgdt)
732
733 /*****************************************************************************/
734 /* setjump, longjump                                                         */
735 /*****************************************************************************/
736
737 ENTRY(setjmp)
738         movq    %rbx,0(%rdi)                    /* save rbx */
739         movq    %rsp,8(%rdi)                    /* save rsp */
740         movq    %rbp,16(%rdi)                   /* save rbp */
741         movq    %r12,24(%rdi)                   /* save r12 */
742         movq    %r13,32(%rdi)                   /* save r13 */
743         movq    %r14,40(%rdi)                   /* save r14 */
744         movq    %r15,48(%rdi)                   /* save r15 */
745         movq    0(%rsp),%rdx                    /* get rta */
746         movq    %rdx,56(%rdi)                   /* save rip */
747         xorl    %eax,%eax                       /* return(0); */
748         ret
749 END(setjmp)
750
751 ENTRY(longjmp)
752         movq    0(%rdi),%rbx                    /* restore rbx */
753         movq    8(%rdi),%rsp                    /* restore rsp */
754         movq    16(%rdi),%rbp                   /* restore rbp */
755         movq    24(%rdi),%r12                   /* restore r12 */
756         movq    32(%rdi),%r13                   /* restore r13 */
757         movq    40(%rdi),%r14                   /* restore r14 */
758         movq    48(%rdi),%r15                   /* restore r15 */
759         movq    56(%rdi),%rdx                   /* get rta */
760         movq    %rdx,0(%rsp)                    /* put in return frame */
761         xorl    %eax,%eax                       /* return(1); */
762         incl    %eax
763         ret
764 END(longjmp)
765
766 /*
767  * Support for reading MSRs in the safe manner.
768  */
769 ENTRY(rdmsr_safe)
770 /* int rdmsr_safe(u_int msr, uint64_t *data) */
771         PUSH_FRAME_POINTER
772         movq    PCPU(CURPCB),%r8
773         movq    $msr_onfault,PCB_ONFAULT(%r8)
774         movl    %edi,%ecx
775         rdmsr                   /* Read MSR pointed by %ecx. Returns
776                                    hi byte in edx, lo in %eax */
777         salq    $32,%rdx        /* sign-shift %rdx left */
778         movl    %eax,%eax       /* zero-extend %eax -> %rax */
779         orq     %rdx,%rax
780         movq    %rax,(%rsi)
781         xorq    %rax,%rax
782         movq    %rax,PCB_ONFAULT(%r8)
783         POP_FRAME_POINTER
784         ret
785
786 /*
787  * Support for writing MSRs in the safe manner.
788  */
789 ENTRY(wrmsr_safe)
790 /* int wrmsr_safe(u_int msr, uint64_t data) */
791         PUSH_FRAME_POINTER
792         movq    PCPU(CURPCB),%r8
793         movq    $msr_onfault,PCB_ONFAULT(%r8)
794         movl    %edi,%ecx
795         movl    %esi,%eax
796         sarq    $32,%rsi
797         movl    %esi,%edx
798         wrmsr                   /* Write MSR pointed by %ecx. Accepts
799                                    hi byte in edx, lo in %eax. */
800         xorq    %rax,%rax
801         movq    %rax,PCB_ONFAULT(%r8)
802         POP_FRAME_POINTER
803         ret
804
805 /*
806  * MSR operations fault handler
807  */
808         ALIGN_TEXT
809 msr_onfault:
810         movq    $0,PCB_ONFAULT(%r8)
811         movl    $EFAULT,%eax
812         POP_FRAME_POINTER
813         ret