ef60345fd64ea37250b498275e680ac408d96e8c
[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  * 3. 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  * bzero(ptr:%rdi, bytes:%rsi)
45  *
46  * Using rep stosq is 70% faster than a %rax loop and almost as fast as
47  * a %xmm0 loop on a modern intel cpu.
48  *
49  * Do not use non-termportal instructions here as we do not know the caller's
50  * intent.
51  */
52 ENTRY(bzero)
53         movq    %rsi,%rcx
54         xorl    %eax,%eax
55         shrq    $3,%rcx
56         rep
57         stosq
58         movq    %rsi,%rcx
59         andq    $7,%rcx
60         jnz     1f
61         ret
62 1:      rep
63         stosb
64         ret
65 END(bzero)
66
67 /*
68  * pagezero(ptr:%rdi)
69  *
70  * Using rep stosq is nearly as fast as using %xmm0 on a modern intel cpu,
71  * and about 70% faster than a %rax loop.
72  *
73  * Do not use non-termportal instructions here as we do not know the caller's
74  * intent.
75  */
76 #if 0
77
78 ENTRY(pagezero)
79         movq    $PAGE_SIZE>>3,%rcx
80         xorl    %eax,%eax
81         rep
82         stosq
83         ret
84 END(pagezero)
85
86 #endif
87
88 ENTRY(pagezero)
89         addq    $4096,%rdi
90         movq    $-4096,%rax
91         ALIGN_TEXT
92 1:
93         movq    $0,(%rdi,%rax,1)
94         addq    $8,%rax
95         jne     1b
96         ret
97 END(pagezero)
98
99 /*
100  * bcmp(ptr:%rdi, ptr:%rsi, bytes:%rdx)
101  */
102 ENTRY(bcmp)
103         movq    %rdx,%rcx
104         shrq    $3,%rcx
105         repe
106         cmpsq
107         jne     1f
108
109         movq    %rdx,%rcx
110         andq    $7,%rcx
111         je      1f
112         repe
113         cmpsb
114 1:
115         setne   %al
116         movsbl  %al,%eax
117         ret
118 END(bcmp)
119
120 /*
121  * bcopy(src:%rdi, dst:%rsi, cnt:%rdx)
122  *
123  * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
124  */
125 ENTRY(bcopy)
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      2f
133
134         shrq    $3,%rcx                         /* copy by 64-bit words */
135         rep
136         movsq
137         movq    %rdx,%rcx
138         andq    $7,%rcx                         /* any bytes left? */
139         jnz     1f
140         ret
141 1:      rep
142         movsb
143         ret
144
145         ALIGN_TEXT
146 2:
147         addq    %rcx,%rdi                       /* copy backwards */
148         addq    %rcx,%rsi
149         std
150         decq    %rdi
151         decq    %rsi
152         andq    $7,%rcx                         /* any fractional bytes? */
153         jz      3f
154         rep
155         movsb
156 3:      movq    %rdx,%rcx                       /* copy by 32-bit words */
157         shrq    $3,%rcx
158         subq    $7,%rsi
159         subq    $7,%rdi
160         rep
161         movsq
162         cld
163         ret
164 END(bcopy)
165
166 ENTRY(reset_dbregs)
167         movq    $0x200,%rax     /* the manual says that bit 10 must be set to 1 */
168         movq    %rax,%dr7       /* disable all breapoints first */
169         movq    $0,%rax
170         movq    %rax,%dr0
171         movq    %rax,%dr1
172         movq    %rax,%dr2
173         movq    %rax,%dr3
174         movq    %rax,%dr6
175         ret
176 END(reset_dbregs)
177
178 /*
179  * memcpy(dst:%rdi, src:%rsi, bytes:%rdx)
180  *
181  * Note: memcpy does not support overlapping copies
182  */
183 ENTRY(memcpy)
184         movq    %rdi,%r8
185         movq    %rdx,%rcx
186         shrq    $3,%rcx                         /* copy by 64-bit words */
187         rep
188         movsq
189         movq    %rdx,%rcx
190         andq    $7,%rcx                         /* any bytes left? */
191         jnz     1f
192         movq    %r8,%rax
193         ret
194 1:      rep
195         movsb
196         movq    %r8,%rax
197         ret
198 END(memcpy)
199
200 /* fillw(pat, base, cnt) */
201 /*       %rdi,%rsi, %rdx */
202 ENTRY(fillw)
203         movq    %rdi,%rax
204         movq    %rsi,%rdi
205         movq    %rdx,%rcx
206         rep
207         stosw
208         ret
209 END(fillw)
210
211 /*****************************************************************************/
212 /* copyout and fubyte family                                                 */
213 /*****************************************************************************/
214 /*
215  * Access user memory from inside the kernel. These routines should be
216  * the only places that do this.
217  *
218  * These routines set curpcb->onfault for the time they execute. When a
219  * protection violation occurs inside the functions, the trap handler
220  * returns to *curpcb->onfault instead of the function.
221  */
222
223 /*
224  * uint64_t:%rax kreadmem64(addr:%rdi)
225  *
226  * Read kernel or user memory with fault protection.
227  */
228 ENTRY(kreadmem64)
229         movq    PCPU(curthread),%rcx
230         movq    TD_PCB(%rcx), %rcx
231         movq    $kreadmem64fault,PCB_ONFAULT(%rcx)
232         movq    %rsp,PCB_ONFAULT_SP(%rcx)
233
234         movq    (%rdi),%rax
235         movq    $0,PCB_ONFAULT(%rcx)
236         ret
237
238 kreadmem64fault:
239         movq    PCPU(curthread),%rcx
240         xorl    %eax,%eax
241         movq    TD_PCB(%rcx),%rcx
242         movq    %rax,PCB_ONFAULT(%rcx)
243         decq    %rax
244         ret
245 END(kreadmem64)
246
247 /*
248  * std_copyout(from_kernel, to_user, len)  - MP SAFE
249  *         %rdi,        %rsi,    %rdx
250  */
251 ENTRY(std_copyout)
252         movq    PCPU(curthread),%rax
253         movq    TD_PCB(%rax), %rax
254         movq    $copyout_fault,PCB_ONFAULT(%rax)
255         movq    %rsp,PCB_ONFAULT_SP(%rax)
256         testq   %rdx,%rdx                       /* anything to do? */
257         jz      done_copyout
258
259         /*
260          * Check explicitly for non-user addresses.  If 486 write protection
261          * is being used, this check is essential because we are in kernel
262          * mode so the h/w does not provide any protection against writing
263          * kernel addresses.
264          */
265
266         /*
267          * First, prevent address wrapping.
268          */
269         movq    %rsi,%rax
270         addq    %rdx,%rax
271         jc      copyout_fault
272 /*
273  * XXX STOP USING VM_MAX_USER_ADDRESS.
274  * It is an end address, not a max, so every time it is used correctly it
275  * looks like there is an off by one error, and of course it caused an off
276  * by one error in several places.
277  */
278         movq    $VM_MAX_USER_ADDRESS,%rcx
279         cmpq    %rcx,%rax
280         ja      copyout_fault
281
282         xchgq   %rdi,%rsi
283         /* bcopy(%rsi, %rdi, %rdx) */
284         movq    %rdx,%rcx
285
286         shrq    $3,%rcx
287         jz      1f
288         rep
289         movsq
290 1:      movq    %rdx,%rcx
291         andq    $7,%rcx
292         jz      done_copyout
293         rep
294         movsb
295
296 done_copyout:
297         xorl    %eax,%eax
298         movq    PCPU(curthread),%rdx
299         movq    TD_PCB(%rdx), %rdx
300         movq    %rax,PCB_ONFAULT(%rdx)
301         ret
302
303         ALIGN_TEXT
304 copyout_fault:
305         movq    PCPU(curthread),%rdx
306         movq    TD_PCB(%rdx), %rdx
307         movq    $0,PCB_ONFAULT(%rdx)
308         movq    $EFAULT,%rax
309         ret
310 END(std_copyout)
311
312 /*
313  * std_copyin(from_user, to_kernel, len) - MP SAFE
314  *        %rdi,      %rsi,      %rdx
315  */
316 ENTRY(std_copyin)
317         movq    PCPU(curthread),%rax
318         movq    TD_PCB(%rax), %rax
319         movq    $copyin_fault,PCB_ONFAULT(%rax)
320         movq    %rsp,PCB_ONFAULT_SP(%rax)
321         testq   %rdx,%rdx                       /* anything to do? */
322         jz      done_copyin
323
324         /*
325          * make sure address is valid
326          */
327         movq    %rdi,%rax
328         addq    %rdx,%rax
329         jc      copyin_fault
330         movq    $VM_MAX_USER_ADDRESS,%rcx
331         cmpq    %rcx,%rax
332         ja      copyin_fault
333
334         xchgq   %rdi,%rsi
335         movq    %rdx,%rcx
336         shrq    $3,%rcx                         /* copy longword-wise */
337         jz      1f
338         rep
339         movsq
340 1:      movq    %rdx,%rcx
341         andq    $7,%rcx                         /* copy remaining bytes */
342         jz      done_copyin
343         rep
344         movsb
345
346 done_copyin:
347         xorl    %eax,%eax
348         movq    PCPU(curthread),%rdx
349         movq    TD_PCB(%rdx), %rdx
350         movq    %rax,PCB_ONFAULT(%rdx)
351         ret
352
353         ALIGN_TEXT
354 copyin_fault:
355         movq    PCPU(curthread),%rdx
356         movq    TD_PCB(%rdx), %rdx
357         movq    $0,PCB_ONFAULT(%rdx)
358         movq    $EFAULT,%rax
359         ret
360 END(std_copyin)
361
362 /*
363  * casu32 - Compare and set user integer.  Returns -1 or the current value.
364  *          dst = %rdi, old = %rsi, new = %rdx
365  */
366 ENTRY(casu32)
367         movq    PCPU(curthread),%rcx
368         movq    TD_PCB(%rcx), %rcx
369         movq    $fusufault,PCB_ONFAULT(%rcx)
370         movq    %rsp,PCB_ONFAULT_SP(%rcx)
371
372         movq    $VM_MAX_USER_ADDRESS-4,%rax
373         cmpq    %rax,%rdi                       /* verify address is valid */
374         ja      fusufault
375
376         movl    %esi,%eax                       /* old */
377         lock
378         cmpxchgl %edx,(%rdi)                    /* new = %edx */
379
380         /*
381          * The old value is in %eax.  If the store succeeded it will be the
382          * value we expected (old) from before the store, otherwise it will
383          * be the current value.
384          */
385
386         movq    PCPU(curthread),%rcx
387         movq    TD_PCB(%rcx), %rcx
388         movq    $0,PCB_ONFAULT(%rcx)
389         ret
390 END(casu32)
391
392 /*
393  * swapu32 - Swap int in user space.  ptr = %rdi, val = %rsi
394  */
395 ENTRY(std_swapu32)
396         movq    PCPU(curthread),%rcx
397         movq    TD_PCB(%rcx), %rcx
398         movq    $fusufault,PCB_ONFAULT(%rcx)
399         movq    %rsp,PCB_ONFAULT_SP(%rcx)
400
401         movq    $VM_MAX_USER_ADDRESS-4,%rax
402         cmpq    %rax,%rdi                       /* verify address is valid */
403         ja      fusufault
404
405         movq    %rsi,%rax                       /* old */
406         xchgl   %eax,(%rdi)
407
408         /*
409          * The old value is in %rax.  If the store succeeded it will be the
410          * value we expected (old) from before the store, otherwise it will
411          * be the current value.
412          */
413
414         movq    PCPU(curthread),%rcx
415         movq    TD_PCB(%rcx), %rcx
416         movq    $0,PCB_ONFAULT(%rcx)
417         ret
418 END(std_swapu32)
419
420 ENTRY(std_fuwordadd32)
421         movq    PCPU(curthread),%rcx
422         movq    TD_PCB(%rcx), %rcx
423         movq    $fusufault,PCB_ONFAULT(%rcx)
424         movq    %rsp,PCB_ONFAULT_SP(%rcx)
425
426         movq    $VM_MAX_USER_ADDRESS-4,%rax
427         cmpq    %rax,%rdi                       /* verify address is valid */
428         ja      fusufault
429
430         movq    %rsi,%rax                       /* qty to add */
431         lock xaddl      %eax,(%rdi)
432
433         /*
434          * The old value is in %rax.  If the store succeeded it will be the
435          * value we expected (old) from before the store, otherwise it will
436          * be the current value.
437          */
438
439         movq    PCPU(curthread),%rcx
440         movq    TD_PCB(%rcx), %rcx
441         movq    $0,PCB_ONFAULT(%rcx)
442         ret
443 END(std_fuwordadd32)
444
445 /*
446  * casu64 - Compare and set user word.  Returns -1 or the current value.
447  *          dst = %rdi, old = %rsi, new = %rdx
448  */
449 ENTRY(casu64)
450         movq    PCPU(curthread),%rcx
451         movq    TD_PCB(%rcx), %rcx
452         movq    $fusufault,PCB_ONFAULT(%rcx)
453         movq    %rsp,PCB_ONFAULT_SP(%rcx)
454
455         movq    $VM_MAX_USER_ADDRESS-8,%rax
456         cmpq    %rax,%rdi                       /* verify address is valid */
457         ja      fusufault
458
459         movq    %rsi,%rax                       /* old */
460         lock
461         cmpxchgq %rdx,(%rdi)                    /* new = %rdx */
462
463         /*
464          * The old value is in %rax.  If the store succeeded it will be the
465          * value we expected (old) from before the store, otherwise it will
466          * be the current value.
467          */
468
469         movq    PCPU(curthread),%rcx
470         movq    TD_PCB(%rcx), %rcx
471         movq    $0,PCB_ONFAULT(%rcx)
472         ret
473 END(casu64)
474
475 /*
476  * swapu64 - Swap long in user space.  ptr = %rdi, val = %rsi
477  */
478 ENTRY(std_swapu64)
479         movq    PCPU(curthread),%rcx
480         movq    TD_PCB(%rcx), %rcx
481         movq    $fusufault,PCB_ONFAULT(%rcx)
482         movq    %rsp,PCB_ONFAULT_SP(%rcx)
483
484         movq    $VM_MAX_USER_ADDRESS-8,%rax
485         cmpq    %rax,%rdi                       /* verify address is valid */
486         ja      fusufault
487
488         movq    %rsi,%rax                       /* old */
489         xchgq   %rax,(%rdi)
490
491         /*
492          * The old value is in %rax.  If the store succeeded it will be the
493          * value we expected (old) from before the store, otherwise it will
494          * be the current value.
495          */
496
497         movq    PCPU(curthread),%rcx
498         movq    TD_PCB(%rcx), %rcx
499         movq    $0,PCB_ONFAULT(%rcx)
500         ret
501 END(std_swapu64)
502
503 ENTRY(std_fuwordadd64)
504         movq    PCPU(curthread),%rcx
505         movq    TD_PCB(%rcx), %rcx
506         movq    $fusufault,PCB_ONFAULT(%rcx)
507         movq    %rsp,PCB_ONFAULT_SP(%rcx)
508
509         movq    $VM_MAX_USER_ADDRESS-8,%rax
510         cmpq    %rax,%rdi                       /* verify address is valid */
511         ja      fusufault
512
513         movq    %rsi,%rax                       /* value to add */
514         lock xaddq      %rax,(%rdi)
515
516         /*
517          * The old value is in %rax.  If the store succeeded it will be the
518          * value we expected (old) from before the store, otherwise it will
519          * be the current value.
520          */
521
522         movq    PCPU(curthread),%rcx
523         movq    TD_PCB(%rcx), %rcx
524         movq    $0,PCB_ONFAULT(%rcx)
525         ret
526 END(std_fuwordadd64)
527
528 /*
529  * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
530  * byte from user memory.  All these functions are MPSAFE.
531  * addr = %rdi
532  */
533
534 ENTRY(std_fuword64)
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-8,%rax
541         cmpq    %rax,%rdi                       /* verify address is valid */
542         ja      fusufault
543
544         movq    (%rdi),%rax
545         movq    $0,PCB_ONFAULT(%rcx)
546         ret
547 END(std_fuword64)
548
549 ENTRY(std_fuword32)
550         movq    PCPU(curthread),%rcx
551         movq    TD_PCB(%rcx), %rcx
552         movq    $fusufault,PCB_ONFAULT(%rcx)
553         movq    %rsp,PCB_ONFAULT_SP(%rcx)
554
555         movq    $VM_MAX_USER_ADDRESS-4,%rax
556         cmpq    %rax,%rdi                       /* verify address is valid */
557         ja      fusufault
558
559         movl    (%rdi),%eax
560         movq    $0,PCB_ONFAULT(%rcx)
561         ret
562 END(std_fuword32)
563
564 ENTRY(std_fubyte)
565         movq    PCPU(curthread),%rcx
566         movq    TD_PCB(%rcx), %rcx
567         movq    $fusufault,PCB_ONFAULT(%rcx)
568         movq    %rsp,PCB_ONFAULT_SP(%rcx)
569
570         movq    $VM_MAX_USER_ADDRESS-1,%rax
571         cmpq    %rax,%rdi
572         ja      fusufault
573
574         movzbl  (%rdi),%eax
575         movq    $0,PCB_ONFAULT(%rcx)
576         ret
577
578         ALIGN_TEXT
579 fusufault:
580         movq    PCPU(curthread),%rcx
581         xorl    %eax,%eax
582         movq    TD_PCB(%rcx), %rcx
583         movq    %rax,PCB_ONFAULT(%rcx)
584         decq    %rax
585         ret
586 END(std_fubyte)
587
588 /*
589  * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
590  * user memory.  All these functions are MPSAFE.
591  *
592  * addr = %rdi, value = %rsi
593  *
594  * Write a long
595  */
596 ENTRY(std_suword64)
597         movq    PCPU(curthread),%rcx
598         movq    TD_PCB(%rcx), %rcx
599         movq    $fusufault,PCB_ONFAULT(%rcx)
600         movq    %rsp,PCB_ONFAULT_SP(%rcx)
601
602         movq    $VM_MAX_USER_ADDRESS-8,%rax
603         cmpq    %rax,%rdi                       /* verify address validity */
604         ja      fusufault
605
606         movq    %rsi,(%rdi)
607         xorl    %eax,%eax
608         movq    PCPU(curthread),%rcx
609         movq    TD_PCB(%rcx), %rcx
610         movq    %rax,PCB_ONFAULT(%rcx)
611         ret
612 END(std_suword64)
613
614 /*
615  * Write an int
616  */
617 ENTRY(std_suword32)
618         movq    PCPU(curthread),%rcx
619         movq    TD_PCB(%rcx), %rcx
620         movq    $fusufault,PCB_ONFAULT(%rcx)
621         movq    %rsp,PCB_ONFAULT_SP(%rcx)
622
623         movq    $VM_MAX_USER_ADDRESS-4,%rax
624         cmpq    %rax,%rdi                       /* verify address validity */
625         ja      fusufault
626
627         movl    %esi,(%rdi)
628         xorl    %eax,%eax
629         movq    PCPU(curthread),%rcx
630         movq    TD_PCB(%rcx), %rcx
631         movq    %rax,PCB_ONFAULT(%rcx)
632         ret
633 END(std_suword32)
634
635 ENTRY(std_subyte)
636         movq    PCPU(curthread),%rcx
637         movq    TD_PCB(%rcx), %rcx
638         movq    $fusufault,PCB_ONFAULT(%rcx)
639         movq    %rsp,PCB_ONFAULT_SP(%rcx)
640
641         movq    $VM_MAX_USER_ADDRESS-1,%rax
642         cmpq    %rax,%rdi                       /* verify address validity */
643         ja      fusufault
644
645         movl    %esi,%eax
646         movb    %al,(%rdi)
647         xorl    %eax,%eax
648         movq    PCPU(curthread),%rcx            /* restore trashed register */
649         movq    TD_PCB(%rcx), %rcx
650         movq    %rax,PCB_ONFAULT(%rcx)
651         ret
652 END(std_subyte)
653
654 /*
655  * std_copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
656  *           %rdi, %rsi, %rdx, %rcx
657  *
658  *      copy a string from from to to, stop when a 0 character is reached.
659  *      return ENAMETOOLONG if string is longer than maxlen, and
660  *      EFAULT on protection violations. If lencopied is non-zero,
661  *      return the actual length in *lencopied.
662  */
663 ENTRY(std_copyinstr)
664         movq    %rdx,%r8                        /* %r8 = maxlen */
665         movq    %rcx,%r9                        /* %r9 = *len */
666         movq    PCPU(curthread),%rcx
667         movq    TD_PCB(%rcx), %rcx
668         movq    $cpystrflt,PCB_ONFAULT(%rcx)
669         movq    %rsp,PCB_ONFAULT_SP(%rcx)
670
671         movq    $VM_MAX_USER_ADDRESS,%rax
672
673         /* make sure 'from' is within bounds */
674         subq    %rdi,%rax
675         jbe     cpystrflt
676
677         /* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
678         cmpq    %rdx,%rax
679         jae     1f
680         movq    %rax,%rdx
681         movq    %rax,%r8
682 1:
683         incq    %rdx
684
685 2:
686         decq    %rdx
687         jz      3f
688
689         movb    (%rdi),%al                      /* faster than lodsb+stosb */
690         movb    %al,(%rsi)
691         leaq    1(%rdi),%rdi
692         leaq    1(%rsi),%rsi
693         testb   %al,%al
694         jnz     2b
695
696         /* Success -- 0 byte reached */
697         decq    %rdx
698         xorl    %eax,%eax
699         jmp     cpystrflt_x
700 3:
701         /* rdx is zero - return ENAMETOOLONG or EFAULT */
702         movq    $VM_MAX_USER_ADDRESS,%rax
703         cmpq    %rax,%rsi
704         jae     cpystrflt
705 4:
706         movq    $ENAMETOOLONG,%rax
707         jmp     cpystrflt_x
708
709 cpystrflt:
710         movq    $EFAULT,%rax
711
712 cpystrflt_x:
713         /* set *lencopied and return %eax */
714         movq    PCPU(curthread),%rcx
715         movq    TD_PCB(%rcx), %rcx
716         movq    $0,PCB_ONFAULT(%rcx)
717
718         testq   %r9,%r9
719         jz      1f
720         subq    %rdx,%r8
721         movq    %r8,(%r9)
722 1:
723         ret
724 END(std_copyinstr)
725
726 /*
727  * copystr(from, to, maxlen, int *lencopied) - MP SAFE
728  *         %rdi, %rsi, %rdx, %rcx
729  */
730 ENTRY(copystr)
731         movq    %rdx,%r8                        /* %r8 = maxlen */
732
733         incq    %rdx
734 1:
735         decq    %rdx
736         jz      4f
737
738         movb    (%rdi),%al                      /* faster than lodsb+stosb */
739         movb    %al,(%rsi)
740         leaq    1(%rdi),%rdi
741         leaq    1(%rsi),%rsi
742         testb   %al,%al
743         jnz     1b
744
745         /* Success -- 0 byte reached */
746         decq    %rdx
747         xorl    %eax,%eax
748         jmp     6f
749 4:
750         /* rdx is zero -- return ENAMETOOLONG */
751         movq    $ENAMETOOLONG,%rax
752
753 6:
754
755         testq   %rcx,%rcx
756         jz      7f
757         /* set *lencopied and return %rax */
758         subq    %rdx,%r8
759         movq    %r8,(%rcx)
760 7:
761         ret
762 END(copystr)
763
764 /*
765  * Handling of special x86_64 registers and descriptor tables etc
766  * %rdi
767  */
768 /* void lgdt(struct region_descriptor *rdp); */
769 ENTRY(lgdt)
770         /* reload the descriptor table */
771         lgdt    (%rdi)
772
773         /* flush the prefetch q */
774         jmp     1f
775         nop
776 1:
777         movl    $KDSEL,%eax
778         movl    %eax,%ds
779         movl    %eax,%es
780         movl    %eax,%fs        /* Beware, use wrmsr to set 64 bit base */
781         movl    %eax,%gs        /* Beware, use wrmsr to set 64 bit base */
782         movl    %eax,%ss
783
784         /* reload code selector by turning return into intersegmental return */
785         popq    %rax
786         pushq   $KCSEL
787         pushq   %rax
788         MEXITCOUNT
789         lretq
790 END(lgdt)
791
792 /*****************************************************************************/
793 /* setjmp, longjmp                                                           */
794 /*****************************************************************************/
795
796 ENTRY(setjmp)
797         movq    %rbx,0(%rdi)                    /* save rbx */
798         movq    %rsp,8(%rdi)                    /* save rsp */
799         movq    %rbp,16(%rdi)                   /* save rbp */
800         movq    %r12,24(%rdi)                   /* save r12 */
801         movq    %r13,32(%rdi)                   /* save r13 */
802         movq    %r14,40(%rdi)                   /* save r14 */
803         movq    %r15,48(%rdi)                   /* save r15 */
804         movq    0(%rsp),%rdx                    /* get rta */
805         movq    %rdx,56(%rdi)                   /* save rip */
806         xorl    %eax,%eax                       /* return(0); */
807         ret
808 END(setjmp)
809
810 ENTRY(longjmp)
811         movq    0(%rdi),%rbx                    /* restore rbx */
812         movq    8(%rdi),%rsp                    /* restore rsp */
813         movq    16(%rdi),%rbp                   /* restore rbp */
814         movq    24(%rdi),%r12                   /* restore r12 */
815         movq    32(%rdi),%r13                   /* restore r13 */
816         movq    40(%rdi),%r14                   /* restore r14 */
817         movq    48(%rdi),%r15                   /* restore r15 */
818         movq    56(%rdi),%rdx                   /* get rta */
819         movq    %rdx,0(%rsp)                    /* put in return frame */
820         xorl    %eax,%eax                       /* return(1); */
821         incl    %eax
822         ret
823 END(longjmp)
824
825 /*
826  * Support for reading MSRs in the safe manner.
827  */
828 ENTRY(rdmsr_safe)
829 /* int rdmsr_safe(u_int msr, uint64_t *data) */
830         movq    PCPU(curthread),%r8
831         movq    TD_PCB(%r8), %r8
832         movq    $msr_onfault,PCB_ONFAULT(%r8)
833         movq    %rsp,PCB_ONFAULT_SP(%r8)
834         movl    %edi,%ecx
835         rdmsr                   /* Read MSR pointed by %ecx. Returns
836                                    hi byte in edx, lo in %eax */
837         salq    $32,%rdx        /* sign-shift %rdx left */
838         movl    %eax,%eax       /* zero-extend %eax -> %rax */
839         orq     %rdx,%rax
840         movq    %rax,(%rsi)
841         xorq    %rax,%rax
842         movq    %rax,PCB_ONFAULT(%r8)
843         ret
844 END(rdmsr_safe)
845
846 /*
847  * Support for writing MSRs in the safe manner.
848  */
849 ENTRY(wrmsr_safe)
850 /* int wrmsr_safe(u_int msr, uint64_t data) */
851         movq    PCPU(curthread),%r8
852         movq    TD_PCB(%r8), %r8
853         movq    $msr_onfault,PCB_ONFAULT(%r8)
854         movq    %rsp,PCB_ONFAULT_SP(%r8)
855         movl    %edi,%ecx
856         movl    %esi,%eax
857         sarq    $32,%rsi
858         movl    %esi,%edx
859         wrmsr                   /* Write MSR pointed by %ecx. Accepts
860                                    hi byte in edx, lo in %eax. */
861         xorq    %rax,%rax
862         movq    %rax,PCB_ONFAULT(%r8)
863         ret
864 END(wrmsr_safe)
865
866 /*
867  * MSR operations fault handler
868  */
869         ALIGN_TEXT
870 msr_onfault:
871         movq    PCPU(curthread),%r8
872         movq    TD_PCB(%r8), %r8
873         movq    $0,PCB_ONFAULT(%r8)
874         movl    $EFAULT,%eax
875         ret