2 * Copyright (c) 1993 The Regents of the University of California.
3 * Copyright (c) 2003 Peter Wemm.
4 * Copyright (c) 2008 The DragonFly Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
31 * $FreeBSD: src/sys/amd64/amd64/support.S,v 1.127 2007/05/23 08:33:04 kib Exp $
34 #include <machine/asmacros.h>
35 #include <machine/pmap.h>
44 * bzero(ptr:%rdi, bytes:%rsi)
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.
49 * Do not use non-termportal instructions here as we do not know the caller's
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.
73 * Do not use non-termportal instructions here as we do not know the caller's
79 movq $PAGE_SIZE>>3,%rcx
100 * bcmp(ptr:%rdi, ptr:%rsi, bytes:%rdx)
121 * bcopy(src:%rdi, dst:%rsi, cnt:%rdx)
123 * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
131 cmpq %rcx,%rax /* overlapping && src < dst? */
134 shrq $3,%rcx /* copy by 64-bit words */
138 andq $7,%rcx /* any bytes left? */
147 addq %rcx,%rdi /* copy backwards */
152 andq $7,%rcx /* any fractional bytes? */
156 3: movq %rdx,%rcx /* copy by 32-bit words */
167 movq $0x200,%rax /* the manual says that bit 10 must be set to 1 */
168 movq %rax,%dr7 /* disable all breapoints first */
179 * memcpy(dst:%rdi, src:%rsi, bytes:%rdx)
181 * Note: memcpy does not support overlapping copies
186 shrq $3,%rcx /* copy by 64-bit words */
190 andq $7,%rcx /* any bytes left? */
200 /* fillw(pat, base, cnt) */
201 /* %rdi,%rsi, %rdx */
211 /*****************************************************************************/
212 /* copyout and fubyte family */
213 /*****************************************************************************/
215 * Access user memory from inside the kernel. These routines should be
216 * the only places that do this.
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.
224 * uint64_t:%rax kreadmem64(addr:%rdi)
226 * Read kernel or user memory with fault protection.
229 movq PCPU(curthread),%rcx
230 movq TD_PCB(%rcx), %rcx
231 movq $kreadmem64fault,PCB_ONFAULT(%rcx)
232 movq %rsp,PCB_ONFAULT_SP(%rcx)
235 movq $0,PCB_ONFAULT(%rcx)
239 movq PCPU(curthread),%rcx
241 movq TD_PCB(%rcx),%rcx
242 movq %rax,PCB_ONFAULT(%rcx)
248 * std_copyout(from_kernel, to_user, len) - MP SAFE
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? */
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
267 * First, prevent address wrapping.
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.
278 movq $VM_MAX_USER_ADDRESS,%rcx
283 /* bcopy(%rsi, %rdi, %rdx) */
298 movq PCPU(curthread),%rdx
299 movq TD_PCB(%rdx), %rdx
300 movq %rax,PCB_ONFAULT(%rdx)
305 movq PCPU(curthread),%rdx
306 movq TD_PCB(%rdx), %rdx
307 movq $0,PCB_ONFAULT(%rdx)
313 * std_copyin(from_user, to_kernel, len) - MP SAFE
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? */
325 * make sure address is valid
330 movq $VM_MAX_USER_ADDRESS,%rcx
336 shrq $3,%rcx /* copy longword-wise */
341 andq $7,%rcx /* copy remaining bytes */
348 movq PCPU(curthread),%rdx
349 movq TD_PCB(%rdx), %rdx
350 movq %rax,PCB_ONFAULT(%rdx)
355 movq PCPU(curthread),%rdx
356 movq TD_PCB(%rdx), %rdx
357 movq $0,PCB_ONFAULT(%rdx)
363 * casu32 - Compare and set user integer. Returns -1 or the current value.
364 * dst = %rdi, old = %rsi, new = %rdx
367 movq PCPU(curthread),%rcx
368 movq TD_PCB(%rcx), %rcx
369 movq $fusufault,PCB_ONFAULT(%rcx)
370 movq %rsp,PCB_ONFAULT_SP(%rcx)
372 movq $VM_MAX_USER_ADDRESS-4,%rax
373 cmpq %rax,%rdi /* verify address is valid */
376 movl %esi,%eax /* old */
378 cmpxchgl %edx,(%rdi) /* new = %edx */
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.
386 movq PCPU(curthread),%rcx
387 movq TD_PCB(%rcx), %rcx
388 movq $0,PCB_ONFAULT(%rcx)
393 * swapu32 - Swap int in user space. ptr = %rdi, val = %rsi
396 movq PCPU(curthread),%rcx
397 movq TD_PCB(%rcx), %rcx
398 movq $fusufault,PCB_ONFAULT(%rcx)
399 movq %rsp,PCB_ONFAULT_SP(%rcx)
401 movq $VM_MAX_USER_ADDRESS-4,%rax
402 cmpq %rax,%rdi /* verify address is valid */
405 movq %rsi,%rax /* old */
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.
414 movq PCPU(curthread),%rcx
415 movq TD_PCB(%rcx), %rcx
416 movq $0,PCB_ONFAULT(%rcx)
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)
426 movq $VM_MAX_USER_ADDRESS-4,%rax
427 cmpq %rax,%rdi /* verify address is valid */
430 movq %rsi,%rax /* qty to add */
431 lock xaddl %eax,(%rdi)
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.
439 movq PCPU(curthread),%rcx
440 movq TD_PCB(%rcx), %rcx
441 movq $0,PCB_ONFAULT(%rcx)
446 * casu64 - Compare and set user word. Returns -1 or the current value.
447 * dst = %rdi, old = %rsi, new = %rdx
450 movq PCPU(curthread),%rcx
451 movq TD_PCB(%rcx), %rcx
452 movq $fusufault,PCB_ONFAULT(%rcx)
453 movq %rsp,PCB_ONFAULT_SP(%rcx)
455 movq $VM_MAX_USER_ADDRESS-8,%rax
456 cmpq %rax,%rdi /* verify address is valid */
459 movq %rsi,%rax /* old */
461 cmpxchgq %rdx,(%rdi) /* new = %rdx */
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.
469 movq PCPU(curthread),%rcx
470 movq TD_PCB(%rcx), %rcx
471 movq $0,PCB_ONFAULT(%rcx)
476 * swapu64 - Swap long in user space. ptr = %rdi, val = %rsi
479 movq PCPU(curthread),%rcx
480 movq TD_PCB(%rcx), %rcx
481 movq $fusufault,PCB_ONFAULT(%rcx)
482 movq %rsp,PCB_ONFAULT_SP(%rcx)
484 movq $VM_MAX_USER_ADDRESS-8,%rax
485 cmpq %rax,%rdi /* verify address is valid */
488 movq %rsi,%rax /* old */
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.
497 movq PCPU(curthread),%rcx
498 movq TD_PCB(%rcx), %rcx
499 movq $0,PCB_ONFAULT(%rcx)
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)
509 movq $VM_MAX_USER_ADDRESS-8,%rax
510 cmpq %rax,%rdi /* verify address is valid */
513 movq %rsi,%rax /* value to add */
514 lock xaddq %rax,(%rdi)
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.
522 movq PCPU(curthread),%rcx
523 movq TD_PCB(%rcx), %rcx
524 movq $0,PCB_ONFAULT(%rcx)
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.
535 movq PCPU(curthread),%rcx
536 movq TD_PCB(%rcx), %rcx
537 movq $fusufault,PCB_ONFAULT(%rcx)
538 movq %rsp,PCB_ONFAULT_SP(%rcx)
540 movq $VM_MAX_USER_ADDRESS-8,%rax
541 cmpq %rax,%rdi /* verify address is valid */
545 movq $0,PCB_ONFAULT(%rcx)
550 movq PCPU(curthread),%rcx
551 movq TD_PCB(%rcx), %rcx
552 movq $fusufault,PCB_ONFAULT(%rcx)
553 movq %rsp,PCB_ONFAULT_SP(%rcx)
555 movq $VM_MAX_USER_ADDRESS-4,%rax
556 cmpq %rax,%rdi /* verify address is valid */
560 movq $0,PCB_ONFAULT(%rcx)
565 movq PCPU(curthread),%rcx
566 movq TD_PCB(%rcx), %rcx
567 movq $fusufault,PCB_ONFAULT(%rcx)
568 movq %rsp,PCB_ONFAULT_SP(%rcx)
570 movq $VM_MAX_USER_ADDRESS-1,%rax
575 movq $0,PCB_ONFAULT(%rcx)
580 movq PCPU(curthread),%rcx
582 movq TD_PCB(%rcx), %rcx
583 movq %rax,PCB_ONFAULT(%rcx)
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.
592 * addr = %rdi, value = %rsi
597 movq PCPU(curthread),%rcx
598 movq TD_PCB(%rcx), %rcx
599 movq $fusufault,PCB_ONFAULT(%rcx)
600 movq %rsp,PCB_ONFAULT_SP(%rcx)
602 movq $VM_MAX_USER_ADDRESS-8,%rax
603 cmpq %rax,%rdi /* verify address validity */
608 movq PCPU(curthread),%rcx
609 movq TD_PCB(%rcx), %rcx
610 movq %rax,PCB_ONFAULT(%rcx)
618 movq PCPU(curthread),%rcx
619 movq TD_PCB(%rcx), %rcx
620 movq $fusufault,PCB_ONFAULT(%rcx)
621 movq %rsp,PCB_ONFAULT_SP(%rcx)
623 movq $VM_MAX_USER_ADDRESS-4,%rax
624 cmpq %rax,%rdi /* verify address validity */
629 movq PCPU(curthread),%rcx
630 movq TD_PCB(%rcx), %rcx
631 movq %rax,PCB_ONFAULT(%rcx)
636 movq PCPU(curthread),%rcx
637 movq TD_PCB(%rcx), %rcx
638 movq $fusufault,PCB_ONFAULT(%rcx)
639 movq %rsp,PCB_ONFAULT_SP(%rcx)
641 movq $VM_MAX_USER_ADDRESS-1,%rax
642 cmpq %rax,%rdi /* verify address validity */
648 movq PCPU(curthread),%rcx /* restore trashed register */
649 movq TD_PCB(%rcx), %rcx
650 movq %rax,PCB_ONFAULT(%rcx)
655 * std_copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
656 * %rdi, %rsi, %rdx, %rcx
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.
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)
671 movq $VM_MAX_USER_ADDRESS,%rax
673 /* make sure 'from' is within bounds */
677 /* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
689 movb (%rdi),%al /* faster than lodsb+stosb */
696 /* Success -- 0 byte reached */
701 /* rdx is zero - return ENAMETOOLONG or EFAULT */
702 movq $VM_MAX_USER_ADDRESS,%rax
706 movq $ENAMETOOLONG,%rax
713 /* set *lencopied and return %eax */
714 movq PCPU(curthread),%rcx
715 movq TD_PCB(%rcx), %rcx
716 movq $0,PCB_ONFAULT(%rcx)
727 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
728 * %rdi, %rsi, %rdx, %rcx
731 movq %rdx,%r8 /* %r8 = maxlen */
738 movb (%rdi),%al /* faster than lodsb+stosb */
745 /* Success -- 0 byte reached */
750 /* rdx is zero -- return ENAMETOOLONG */
751 movq $ENAMETOOLONG,%rax
757 /* set *lencopied and return %rax */
765 * Handling of special x86_64 registers and descriptor tables etc
768 /* void lgdt(struct region_descriptor *rdp); */
770 /* reload the descriptor table */
773 /* flush the prefetch q */
780 movl %eax,%fs /* Beware, use wrmsr to set 64 bit base */
781 movl %eax,%gs /* Beware, use wrmsr to set 64 bit base */
784 /* reload code selector by turning return into intersegmental return */
792 /*****************************************************************************/
793 /* setjmp, longjmp */
794 /*****************************************************************************/
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); */
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); */
826 * Support for reading MSRs in the safe manner.
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)
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 */
842 movq %rax,PCB_ONFAULT(%r8)
847 * Support for writing MSRs in the safe manner.
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)
859 wrmsr /* Write MSR pointed by %ecx. Accepts
860 hi byte in edx, lo in %eax. */
862 movq %rax,PCB_ONFAULT(%r8)
867 * MSR operations fault handler
871 movq PCPU(curthread),%r8
872 movq TD_PCB(%r8), %r8
873 movq $0,PCB_ONFAULT(%r8)