kernel - Make pcb_onfault more robust.
[dragonfly.git] / sys / platform / pc64 / x86_64 / support.s
1 /*-
2  * Copyright (c) 1993 The Regents of the University of California.
3  * Copyright (c) 2003 Peter Wemm.
4  * Copyright (c) 2008 The DragonFly Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 4. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD: src/sys/amd64/amd64/support.S,v 1.127 2007/05/23 08:33:04 kib Exp $
32  */
33
34 #include <machine/asmacros.h>
35 #include <machine/pmap.h>
36
37 #include "assym.s"
38
39         ALIGN_DATA
40
41         .text
42
43 /*
44  * bcopy family
45  * void bzero(void *buf, size_t len)
46  */
47
48 /* done */
49 ENTRY(bzero)
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         ret
61
62 /* Address: %rdi */
63 ENTRY(pagezero)
64         movq    $-PAGE_SIZE,%rdx
65         subq    %rdx,%rdi
66         xorl    %eax,%eax
67 1:
68         movq    %rax,(%rdi,%rdx)        /* movnti */
69         movq    %rax,8(%rdi,%rdx)       /* movnti */
70         movq    %rax,16(%rdi,%rdx)      /* movnti */
71         movq    %rax,24(%rdi,%rdx)      /* movnti */
72         addq    $32,%rdx
73         jne     1b
74         /*sfence*/
75         ret
76
77 ENTRY(bcmp)
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         ret
93
94 /*
95  * bcopy(src, dst, cnt)
96  *       rdi, rsi, rdx
97  *  ws@tools.de     (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
98  */
99 ENTRY(generic_bcopy)    /* generic_bcopy is bcopy without FPU */
100 ENTRY(ovbcopy) /* our bcopy doesn't use the FPU, so ovbcopy is the same */
101 ENTRY(bcopy)
102         xchgq   %rsi,%rdi
103         movq    %rdx,%rcx
104
105         movq    %rdi,%rax
106         subq    %rsi,%rax
107         cmpq    %rcx,%rax                       /* overlapping && src < dst? */
108         jb      1f
109
110         shrq    $3,%rcx                         /* copy by 64-bit words */
111         cld                                     /* nope, copy forwards */
112         rep
113         movsq
114         movq    %rdx,%rcx
115         andq    $7,%rcx                         /* any bytes left? */
116         rep
117         movsb
118         ret
119
120         /* ALIGN_TEXT */
121 1:
122         addq    %rcx,%rdi                       /* copy backwards */
123         addq    %rcx,%rsi
124         decq    %rdi
125         decq    %rsi
126         andq    $7,%rcx                         /* any fractional bytes? */
127         std
128         rep
129         movsb
130         movq    %rdx,%rcx                       /* copy remainder by 32-bit words */
131         shrq    $3,%rcx
132         subq    $7,%rsi
133         subq    $7,%rdi
134         rep
135         movsq
136         cld
137         ret
138 ENTRY(reset_dbregs)
139         movq    $0x200,%rax   /* the manual says that bit 10 must be set to 1 */
140         movq    %rax,%dr7     /* disable all breapoints first */
141         movq    $0,%rax
142         movq    %rax,%dr0
143         movq    %rax,%dr1
144         movq    %rax,%dr2
145         movq    %rax,%dr3
146         movq    %rax,%dr6
147         ret
148
149 /*
150  * Note: memcpy does not support overlapping copies
151  */
152 ENTRY(memcpy)
153         movq    %rdx,%rcx
154         shrq    $3,%rcx                         /* copy by 64-bit words */
155         cld                                     /* copy forwards */
156         rep
157         movsq
158         movq    %rdx,%rcx
159         andq    $7,%rcx                         /* any bytes left? */
160         rep
161         movsb
162         ret
163
164 /*
165  * pagecopy(%rdi=from, %rsi=to)
166  */
167 ENTRY(pagecopy)
168         movq    $-PAGE_SIZE,%rax
169         movq    %rax,%rdx
170         subq    %rax,%rdi
171         subq    %rax,%rsi
172 1:
173         /*prefetchnta (%rdi,%rax)*/
174         /*addq  $64,%rax*/
175         /*jne   1b*/
176 2:
177         movq    (%rdi,%rdx),%rax
178         movq    %rax,(%rsi,%rdx)        /* movnti */
179         movq    8(%rdi,%rdx),%rax
180         movq    %rax,8(%rsi,%rdx)       /* movnti */
181         movq    16(%rdi,%rdx),%rax
182         movq    %rax,16(%rsi,%rdx)      /* movnti */
183         movq    24(%rdi,%rdx),%rax
184         movq    %rax,24(%rsi,%rdx)      /* movnti */
185         addq    $32,%rdx
186         jne     2b
187         /*sfence*/
188         ret
189
190 /* fillw(pat, base, cnt) */  
191 /*       %rdi,%rsi, %rdx */
192 ENTRY(fillw)
193         movq    %rdi,%rax   
194         movq    %rsi,%rdi
195         movq    %rdx,%rcx
196         cld
197         rep
198         stosw
199         ret
200
201 /*****************************************************************************/
202 /* copyout and fubyte family                                                 */
203 /*****************************************************************************/
204 /*
205  * Access user memory from inside the kernel. These routines should be
206  * the only places that do this.
207  *
208  * These routines set curpcb->onfault for the time they execute. When a
209  * protection violation occurs inside the functions, the trap handler
210  * returns to *curpcb->onfault instead of the function.
211  */
212
213 /*
214  * copyout(from_kernel, to_user, len)  - MP SAFE
215  *         %rdi,        %rsi,    %rdx
216  */
217 ENTRY(copyout)
218         movq    PCPU(curthread),%rax
219         movq    TD_PCB(%rax), %rax
220         movq    $copyout_fault,PCB_ONFAULT(%rax)
221         movq    %rsp,PCB_ONFAULT_SP(%rax)
222         testq   %rdx,%rdx                       /* anything to do? */
223         jz      done_copyout
224
225         /*
226          * Check explicitly for non-user addresses.  If 486 write protection
227          * is being used, this check is essential because we are in kernel
228          * mode so the h/w does not provide any protection against writing
229          * kernel addresses.
230          */
231
232         /*
233          * First, prevent address wrapping.
234          */
235         movq    %rsi,%rax
236         addq    %rdx,%rax
237         jc      copyout_fault
238 /*
239  * XXX STOP USING VM_MAX_USER_ADDRESS.
240  * It is an end address, not a max, so every time it is used correctly it
241  * looks like there is an off by one error, and of course it caused an off
242  * by one error in several places.
243  */
244         movq    $VM_MAX_USER_ADDRESS,%rcx
245         cmpq    %rcx,%rax
246         ja      copyout_fault
247
248         xchgq   %rdi,%rsi
249         /* bcopy(%rsi, %rdi, %rdx) */
250         movq    %rdx,%rcx
251
252         shrq    $3,%rcx
253         cld
254         rep
255         movsq
256         movb    %dl,%cl
257         andb    $7,%cl
258         rep
259         movsb
260
261 done_copyout:
262         xorl    %eax,%eax
263         movq    PCPU(curthread),%rdx
264         movq    TD_PCB(%rdx), %rdx
265         movq    %rax,PCB_ONFAULT(%rdx)
266         ret
267
268         ALIGN_TEXT
269 copyout_fault:
270         movq    PCPU(curthread),%rdx
271         movq    TD_PCB(%rdx), %rdx
272         movq    $0,PCB_ONFAULT(%rdx)
273         movq    $EFAULT,%rax
274         ret
275
276 /*
277  * copyin(from_user, to_kernel, len) - MP SAFE
278  *        %rdi,      %rsi,      %rdx
279  */
280 ENTRY(copyin)
281         movq    PCPU(curthread),%rax
282         movq    TD_PCB(%rax), %rax
283         movq    $copyin_fault,PCB_ONFAULT(%rax)
284         movq    %rsp,PCB_ONFAULT_SP(%rax)
285         testq   %rdx,%rdx                       /* anything to do? */
286         jz      done_copyin
287
288         /*
289          * make sure address is valid
290          */
291         movq    %rdi,%rax
292         addq    %rdx,%rax
293         jc      copyin_fault
294         movq    $VM_MAX_USER_ADDRESS,%rcx
295         cmpq    %rcx,%rax
296         ja      copyin_fault
297
298         xchgq   %rdi,%rsi
299         movq    %rdx,%rcx
300         movb    %cl,%al
301         shrq    $3,%rcx                         /* copy longword-wise */
302         cld
303         rep
304         movsq
305         movb    %al,%cl
306         andb    $7,%cl                          /* copy remaining bytes */
307         rep
308         movsb
309
310 done_copyin:
311         xorl    %eax,%eax
312         movq    PCPU(curthread),%rdx
313         movq    TD_PCB(%rdx), %rdx
314         movq    %rax,PCB_ONFAULT(%rdx)
315         ret
316
317         ALIGN_TEXT
318 copyin_fault:
319         movq    PCPU(curthread),%rdx
320         movq    TD_PCB(%rdx), %rdx
321         movq    $0,PCB_ONFAULT(%rdx)
322         movq    $EFAULT,%rax
323         ret
324
325 /*
326  * casuword32.  Compare and set user integer.  Returns -1 or the current value.
327  *        dst = %rdi, old = %rsi, new = %rdx
328  */
329 ENTRY(casuword32)
330         movq    PCPU(curthread),%rcx
331         movq    TD_PCB(%rcx), %rcx
332         movq    $fusufault,PCB_ONFAULT(%rcx)
333         movq    %rsp,PCB_ONFAULT_SP(%rcx)
334
335         movq    $VM_MAX_USER_ADDRESS-4,%rax
336         cmpq    %rax,%rdi                       /* verify address is valid */
337         ja      fusufault
338
339         movl    %esi,%eax                       /* old */
340 #ifdef SMP
341         lock
342 #endif
343         cmpxchgl %edx,(%rdi)                    /* new = %edx */
344
345         /*
346          * The old value is in %eax.  If the store succeeded it will be the
347          * value we expected (old) from before the store, otherwise it will
348          * be the current value.
349          */
350
351         movq    PCPU(curthread),%rcx
352         movq    TD_PCB(%rcx), %rcx
353         movq    $0,PCB_ONFAULT(%rcx)
354         ret
355
356 /*
357  * casuword.  Compare and set user word.  Returns -1 or the current value.
358  *        dst = %rdi, old = %rsi, new = %rdx
359  */
360 ENTRY(casuword)
361         movq    PCPU(curthread),%rcx
362         movq    TD_PCB(%rcx), %rcx
363         movq    $fusufault,PCB_ONFAULT(%rcx)
364         movq    %rsp,PCB_ONFAULT_SP(%rcx)
365
366         movq    $VM_MAX_USER_ADDRESS-4,%rax
367         cmpq    %rax,%rdi                       /* verify address is valid */
368         ja      fusufault
369
370         movq    %rsi,%rax                       /* old */
371 #ifdef SMP
372         lock
373 #endif
374         cmpxchgq %rdx,(%rdi)                    /* new = %rdx */
375
376         /*
377          * The old value is in %eax.  If the store succeeded it will be the
378          * value we expected (old) from before the store, otherwise it will
379          * be the current value.
380          */
381
382         movq    PCPU(curthread),%rcx
383         movq    TD_PCB(%rcx), %rcx
384         movq    $0,PCB_ONFAULT(%rcx)
385         ret
386
387 /*
388  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
389  * byte from user memory.  All these functions are MPSAFE.
390  * addr = %rdi
391  */
392
393 ALTENTRY(fuword64)
394 ENTRY(fuword)
395         movq    PCPU(curthread),%rcx
396         movq    TD_PCB(%rcx), %rcx
397         movq    $fusufault,PCB_ONFAULT(%rcx)
398         movq    %rsp,PCB_ONFAULT_SP(%rcx)
399
400         movq    $VM_MAX_USER_ADDRESS-8,%rax
401         cmpq    %rax,%rdi                       /* verify address is valid */
402         ja      fusufault
403
404         movq    (%rdi),%rax
405         movq    $0,PCB_ONFAULT(%rcx)
406         ret
407
408 ENTRY(fuword32)
409         movq    PCPU(curthread),%rcx
410         movq    TD_PCB(%rcx), %rcx
411         movq    $fusufault,PCB_ONFAULT(%rcx)
412         movq    %rsp,PCB_ONFAULT_SP(%rcx)
413
414         movq    $VM_MAX_USER_ADDRESS-4,%rax
415         cmpq    %rax,%rdi                       /* verify address is valid */
416         ja      fusufault
417
418         movl    (%rdi),%eax
419         movq    $0,PCB_ONFAULT(%rcx)
420         ret
421
422 /*
423  * fuswintr() and suswintr() are specialized variants of fuword16() and
424  * suword16(), respectively.  They are called from the profiling code,
425  * potentially at interrupt time.  If they fail, that's okay; good things
426  * will happen later.  They always fail for now, until the trap code is
427  * able to deal with this.
428  */
429 ALTENTRY(suswintr)
430 ENTRY(fuswintr)
431         movq    $-1,%rax
432         ret
433
434 ENTRY(fuword16)
435         movq    PCPU(curthread),%rcx
436         movq    TD_PCB(%rcx), %rcx
437         movq    $fusufault,PCB_ONFAULT(%rcx)
438         movq    %rsp,PCB_ONFAULT_SP(%rcx)
439
440         movq    $VM_MAX_USER_ADDRESS-2,%rax
441         cmpq    %rax,%rdi
442         ja      fusufault
443
444         movzwl  (%rdi),%eax
445         movq    $0,PCB_ONFAULT(%rcx)
446         ret
447
448 ENTRY(fubyte)
449         movq    PCPU(curthread),%rcx
450         movq    TD_PCB(%rcx), %rcx
451         movq    $fusufault,PCB_ONFAULT(%rcx)
452         movq    %rsp,PCB_ONFAULT_SP(%rcx)
453
454         movq    $VM_MAX_USER_ADDRESS-1,%rax
455         cmpq    %rax,%rdi
456         ja      fusufault
457
458         movzbl  (%rdi),%eax
459         movq    $0,PCB_ONFAULT(%rcx)
460         ret
461
462         ALIGN_TEXT
463 fusufault:
464         movq    PCPU(curthread),%rcx
465         xorl    %eax,%eax
466         movq    TD_PCB(%rcx), %rcx
467         movq    %rax,PCB_ONFAULT(%rcx)
468         decq    %rax
469         ret
470
471 /*
472  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
473  * user memory.  All these functions are MPSAFE.
474  *
475  * addr = %rdi, value = %rsi
476  *
477  * Write a long
478  */
479 ALTENTRY(suword64)
480 ENTRY(suword)
481         movq    PCPU(curthread),%rcx
482         movq    TD_PCB(%rcx), %rcx
483         movq    $fusufault,PCB_ONFAULT(%rcx)
484         movq    %rsp,PCB_ONFAULT_SP(%rcx)
485
486         movq    $VM_MAX_USER_ADDRESS-8,%rax
487         cmpq    %rax,%rdi                       /* verify address validity */
488         ja      fusufault
489
490         movq    %rsi,(%rdi)
491         xorl    %eax,%eax
492         movq    PCPU(curthread),%rcx
493         movq    TD_PCB(%rcx), %rcx
494         movq    %rax,PCB_ONFAULT(%rcx)
495         ret
496
497 /*
498  * Write an int
499  */
500 ENTRY(suword32)
501         movq    PCPU(curthread),%rcx
502         movq    TD_PCB(%rcx), %rcx
503         movq    $fusufault,PCB_ONFAULT(%rcx)
504         movq    %rsp,PCB_ONFAULT_SP(%rcx)
505
506         movq    $VM_MAX_USER_ADDRESS-4,%rax
507         cmpq    %rax,%rdi                       /* verify address validity */
508         ja      fusufault
509
510         movl    %esi,(%rdi)
511         xorl    %eax,%eax
512         movq    PCPU(curthread),%rcx
513         movq    TD_PCB(%rcx), %rcx
514         movq    %rax,PCB_ONFAULT(%rcx)
515         ret
516
517 ENTRY(suword16)
518         movq    PCPU(curthread),%rcx
519         movq    TD_PCB(%rcx), %rcx
520         movq    $fusufault,PCB_ONFAULT(%rcx)
521         movq    %rsp,PCB_ONFAULT_SP(%rcx)
522
523         movq    $VM_MAX_USER_ADDRESS-2,%rax
524         cmpq    %rax,%rdi                       /* verify address validity */
525         ja      fusufault
526
527         movw    %si,(%rdi)
528         xorl    %eax,%eax
529         movq    PCPU(curthread),%rcx            /* restore trashed register */
530         movq    TD_PCB(%rcx), %rcx
531         movq    %rax,PCB_ONFAULT(%rcx)
532         ret
533
534 ENTRY(subyte)
535         movq    PCPU(curthread),%rcx
536         movq    TD_PCB(%rcx), %rcx
537         movq    $fusufault,PCB_ONFAULT(%rcx)
538         movq    %rsp,PCB_ONFAULT_SP(%rcx)
539
540         movq    $VM_MAX_USER_ADDRESS-1,%rax
541         cmpq    %rax,%rdi                       /* verify address validity */
542         ja      fusufault
543
544         movl    %esi,%eax
545         movb    %al,(%rdi)
546         xorl    %eax,%eax
547         movq    PCPU(curthread),%rcx            /* restore trashed register */
548         movq    TD_PCB(%rcx), %rcx
549         movq    %rax,PCB_ONFAULT(%rcx)
550         ret
551
552 /*
553  * copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
554  *           %rdi, %rsi, %rdx, %rcx
555  *
556  *      copy a string from from to to, stop when a 0 character is reached.
557  *      return ENAMETOOLONG if string is longer than maxlen, and
558  *      EFAULT on protection violations. If lencopied is non-zero,
559  *      return the actual length in *lencopied.
560  */
561 ENTRY(copyinstr)
562         movq    %rdx,%r8                        /* %r8 = maxlen */
563         movq    %rcx,%r9                        /* %r9 = *len */
564         xchgq   %rdi,%rsi                       /* %rdi = from, %rsi = to */
565         movq    PCPU(curthread),%rcx
566         movq    TD_PCB(%rcx), %rcx
567         movq    $cpystrflt,PCB_ONFAULT(%rcx)
568         movq    %rsp,PCB_ONFAULT_SP(%rcx)
569
570         movq    $VM_MAX_USER_ADDRESS,%rax
571
572         /* make sure 'from' is within bounds */
573         subq    %rsi,%rax
574         jbe     cpystrflt
575
576         /* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
577         cmpq    %rdx,%rax
578         jae     1f
579         movq    %rax,%rdx
580         movq    %rax,%r8
581 1:
582         incq    %rdx
583         cld
584
585 2:
586         decq    %rdx
587         jz      3f
588
589         lodsb
590         stosb
591         orb     %al,%al
592         jnz     2b
593
594         /* Success -- 0 byte reached */
595         decq    %rdx
596         xorl    %eax,%eax
597         jmp     cpystrflt_x
598 3:
599         /* rdx is zero - return ENAMETOOLONG or EFAULT */
600         movq    $VM_MAX_USER_ADDRESS,%rax
601         cmpq    %rax,%rsi
602         jae     cpystrflt
603 4:
604         movq    $ENAMETOOLONG,%rax
605         jmp     cpystrflt_x
606
607 cpystrflt:
608         movq    $EFAULT,%rax
609
610 cpystrflt_x:
611         /* set *lencopied and return %eax */
612         movq    PCPU(curthread),%rcx
613         movq    TD_PCB(%rcx), %rcx
614         movq    $0,PCB_ONFAULT(%rcx)
615
616         testq   %r9,%r9
617         jz      1f
618         subq    %rdx,%r8
619         movq    %r8,(%r9)
620 1:
621         ret
622
623
624 /*
625  * copystr(from, to, maxlen, int *lencopied) - MP SAFE
626  *         %rdi, %rsi, %rdx, %rcx
627  */
628 ENTRY(copystr)
629         movq    %rdx,%r8                        /* %r8 = maxlen */
630
631         xchgq   %rdi,%rsi
632         incq    %rdx
633         cld
634 1:
635         decq    %rdx
636         jz      4f
637         lodsb
638         stosb
639         orb     %al,%al
640         jnz     1b
641
642         /* Success -- 0 byte reached */
643         decq    %rdx
644         xorl    %eax,%eax
645         jmp     6f
646 4:
647         /* rdx is zero -- return ENAMETOOLONG */
648         movq    $ENAMETOOLONG,%rax
649
650 6:
651
652         testq   %rcx,%rcx
653         jz      7f
654         /* set *lencopied and return %rax */
655         subq    %rdx,%r8
656         movq    %r8,(%rcx)
657 7:
658         ret
659
660 /*
661  * Handling of special x86_64 registers and descriptor tables etc
662  * %rdi
663  */
664 /* void lgdt(struct region_descriptor *rdp); */
665 ENTRY(lgdt)
666         /* reload the descriptor table */
667         lgdt    (%rdi)
668
669         /* flush the prefetch q */
670         jmp     1f
671         nop
672 1:
673         movl    $KDSEL,%eax
674         movl    %eax,%ds
675         movl    %eax,%es
676         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
677         movl    %eax,%gs        /* Beware, use wrmsr to set 64 bit base */
678         movl    %eax,%ss
679
680         /* reload code selector by turning return into intersegmental return */
681         popq    %rax
682         pushq   $KCSEL
683         pushq   %rax
684         MEXITCOUNT
685         lretq
686
687 /*****************************************************************************/
688 /* setjump, longjump                                                         */
689 /*****************************************************************************/
690
691 ENTRY(setjmp)
692         movq    %rbx,0(%rdi)                    /* save rbx */
693         movq    %rsp,8(%rdi)                    /* save rsp */
694         movq    %rbp,16(%rdi)                   /* save rbp */
695         movq    %r12,24(%rdi)                   /* save r12 */
696         movq    %r13,32(%rdi)                   /* save r13 */
697         movq    %r14,40(%rdi)                   /* save r14 */
698         movq    %r15,48(%rdi)                   /* save r15 */
699         movq    0(%rsp),%rdx                    /* get rta */
700         movq    %rdx,56(%rdi)                   /* save rip */
701         xorl    %eax,%eax                       /* return(0); */
702         ret
703
704 ENTRY(longjmp)
705         movq    0(%rdi),%rbx                    /* restore rbx */
706         movq    8(%rdi),%rsp                    /* restore rsp */
707         movq    16(%rdi),%rbp                   /* restore rbp */
708         movq    24(%rdi),%r12                   /* restore r12 */
709         movq    32(%rdi),%r13                   /* restore r13 */
710         movq    40(%rdi),%r14                   /* restore r14 */
711         movq    48(%rdi),%r15                   /* restore r15 */
712         movq    56(%rdi),%rdx                   /* get rta */
713         movq    %rdx,0(%rsp)                    /* put in return frame */
714         xorl    %eax,%eax                       /* return(1); */
715         incl    %eax
716         ret
717
718 /*
719  * Support for reading MSRs in the safe manner.
720  */
721 ENTRY(rdmsr_safe)
722 /* int rdmsr_safe(u_int msr, uint64_t *data) */
723         movq    PCPU(curthread),%r8
724         movq    TD_PCB(%r8), %r8
725         movq    $msr_onfault,PCB_ONFAULT(%r8)
726         movq    %rsp,PCB_ONFAULT_SP(%r8)
727         movl    %edi,%ecx
728         rdmsr                   /* Read MSR pointed by %ecx. Returns
729                                    hi byte in edx, lo in %eax */
730         salq    $32,%rdx        /* sign-shift %rdx left */
731         movl    %eax,%eax       /* zero-extend %eax -> %rax */
732         orq     %rdx,%rax
733         movq    %rax,(%rsi)
734         xorq    %rax,%rax
735         movq    %rax,PCB_ONFAULT(%r8)
736         ret
737
738 /*
739  * MSR operations fault handler
740  */
741         ALIGN_TEXT
742 msr_onfault:
743         movq    PCPU(curthread),%r8
744         movq    TD_PCB(%r8), %r8
745         movq    $0,PCB_ONFAULT(%r8)
746         movl    $EFAULT,%eax
747         ret
748
749 /*
750  * Support for BB-profiling (gcc -a).  The kernbb program will extract
751  * the data from the kernel.
752  */
753
754         .data
755         ALIGN_DATA
756         .globl bbhead
757 bbhead:
758         .quad 0
759
760         .text
761 NON_GPROF_ENTRY(__bb_init_func)
762         movq    $1,(%rdi)
763         movq    bbhead,%rax
764         movq    %rax,32(%rdi)
765         movq    %rdi,bbhead
766         NON_GPROF_RET