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