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 * Copyright (c) 2008-2020 The DragonFly Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/sys/amd64/amd64/support.S,v 1.127 2007/05/23 08:33:04 kib Exp $
35 #include <machine/asmacros.h>
36 #include <machine/asm_mjgmacros.h>
37 #include <machine/pmap.h>
46 * bzero(ptr:%rdi, bytes:%rsi)
48 * Using rep stosq is 70% faster than a %rax loop and almost as fast as
49 * a %xmm0 loop on a modern intel cpu.
51 * Do not use non-termportal instructions here as we do not know the caller's
64 * void *memset(ptr:%rdi, char:%rsi, bytes:%rdx)
66 * Same as bzero except we load the char into all byte
67 * positions of %rax. Returns original (ptr).
71 movabs $
0x0101010101010101,%r10
82 * Modern intel and AMD cpus do a good job with rep stosq on page-sized
83 * blocks. The cross-point on intel is at the 256 byte mark and on AMD
84 * it is around the 1024 byte mark. With large counts, rep stosq will
85 * internally use non-termporal instructions and a cache sync at the end.
90 movq $PAGE_SIZE
>>3,%rcx
104 movq $
0,(%rdi
,%rax
,1)
105 movq $
0,8(%rdi
,%rax
,1)
114 * bcopy(src:%rdi, dst:%rsi, cnt:%rdx)
116 * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
120 MEMMOVE erms
=0 overlap
=1 end
=ret
124 * Use in situations where a bcopy function pointer is needed.
130 * memmove(dst:%rdi, src:%rsi, cnt:%rdx)
131 * (same as bcopy but without the xchgq, and must return (dst)).
133 * NOTE: gcc builtin backs-off to memmove() call
138 MEMMOVE erms
=0 overlap
=1 end
=ret
142 .equ _memmove, memmove
145 movq $
0x200,%rax
/* the manual says that bit 10 must be set to 1 */
146 movq
%rax
,%dr7
/* disable all breapoints first */
157 * memcpy(dst:%rdi, src:%rsi, bytes:%rdx)
159 * NOTE: memcpy does not support overlapping copies
164 MEMMOVE erms
=0 overlap
=0 end
=ret
170 /* fillw(pat, base, cnt) */
171 /* %rdi,%rsi, %rdx */
181 /*****************************************************************************/
182 /* copyout and fubyte family */
183 /*****************************************************************************/
185 * Access user memory from inside the kernel. These routines should be
186 * the only places that do this.
188 * These routines set curpcb->onfault for the time they execute. When a
189 * protection violation occurs inside the functions, the trap handler
190 * returns to *curpcb->onfault instead of the function.
194 * uint64_t:%rax kreadmem64(addr:%rdi)
196 * Read kernel or user memory with fault protection.
200 movq PCPU
(curthread
),%rcx
201 movq TD_PCB
(%rcx
), %rcx
202 movq $kreadmem64fault
,PCB_ONFAULT
(%rcx
)
203 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
205 movq $
0,PCB_ONFAULT
(%rcx
)
211 movq PCPU
(curthread
),%rcx
213 movq TD_PCB
(%rcx
),%rcx
214 movq
%rax
,PCB_ONFAULT
(%rcx
)
225 * std_copyout(from_kernel, to_user, len) - MP SAFE
230 movq PCPU
(curthread
),%rax
231 movq TD_PCB
(%rax
), %rax
232 movq $copyout_fault
,PCB_ONFAULT
(%rax
)
233 movq
%rsp
,PCB_ONFAULT_SP
(%rax
)
234 testq
%rdx
,%rdx
/* anything to do? */
238 * Check explicitly for non-user addresses. If 486 write protection
239 * is being used, this check is essential because we are in kernel
240 * mode so the h/w does not provide any protection against writing
245 * First, prevent address wrapping.
251 * XXX STOP USING VM_MAX_USER_ADDRESS.
252 * It is an end address, not a max, so every time it is used correctly it
253 * looks like there is an off by one error, and of course it caused an off
254 * by one error in several places.
256 movq $VM_MAX_USER_ADDRESS
,%rcx
261 MEMMOVE erms
=0 overlap
=0 end
=COPYOUT_END
266 movq PCPU
(curthread
),%rdx
267 movq TD_PCB
(%rdx
), %rdx
268 movq
%rax
,PCB_ONFAULT
(%rdx
)
274 movq PCPU
(curthread
),%rdx
275 movq TD_PCB
(%rdx
), %rdx
276 movq $
0,PCB_ONFAULT
(%rdx
)
287 * std_copyin(from_user, to_kernel, len) - MP SAFE
292 movq PCPU
(curthread
),%rax
293 movq TD_PCB
(%rax
), %rax
294 movq $copyin_fault
,PCB_ONFAULT
(%rax
)
295 movq
%rsp
,PCB_ONFAULT_SP
(%rax
)
296 testq
%rdx
,%rdx
/* anything to do? */
300 * make sure address is valid
305 movq $VM_MAX_USER_ADDRESS
,%rcx
310 MEMMOVE erms
=0 overlap
=0 end
=COPYIN_END
315 movq PCPU
(curthread
),%rdx
316 movq TD_PCB
(%rdx
), %rdx
317 movq
%rax
,PCB_ONFAULT
(%rdx
)
323 movq PCPU
(curthread
),%rdx
324 movq TD_PCB
(%rdx
), %rdx
325 movq $
0,PCB_ONFAULT
(%rdx
)
331 * casu32 - Compare and set user integer. Returns -1 or the current value.
332 * dst = %rdi, old = %rsi, new = %rdx
336 movq PCPU
(curthread
),%rcx
337 movq TD_PCB
(%rcx
), %rcx
338 movq $fusufault
,PCB_ONFAULT
(%rcx
)
339 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
341 movq $VM_MAX_USER_ADDRESS-
4,%rax
342 cmpq
%rax
,%rdi
/* verify address is valid */
345 movl
%esi
,%eax
/* old */
347 cmpxchgl
%edx
,(%rdi
) /* new = %edx */
350 * The old value is in %eax. If the store succeeded it will be the
351 * value we expected (old) from before the store, otherwise it will
352 * be the current value.
355 movq PCPU
(curthread
),%rcx
356 movq TD_PCB
(%rcx
), %rcx
357 movq $
0,PCB_ONFAULT
(%rcx
)
363 * swapu32 - Swap int in user space. ptr = %rdi, val = %rsi
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 movq
%rsi
,%rax
/* old */
380 * The old value is in %rax. If the store succeeded it will be the
381 * value we expected (old) from before the store, otherwise it will
382 * be the current value.
385 movq PCPU
(curthread
),%rcx
386 movq TD_PCB
(%rcx
), %rcx
387 movq $
0,PCB_ONFAULT
(%rcx
)
392 ENTRY
(std_fuwordadd32
)
394 movq PCPU
(curthread
),%rcx
395 movq TD_PCB
(%rcx
), %rcx
396 movq $fusufault
,PCB_ONFAULT
(%rcx
)
397 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
399 movq $VM_MAX_USER_ADDRESS-
4,%rax
400 cmpq
%rax
,%rdi
/* verify address is valid */
403 movq
%rsi
,%rax
/* qty to add */
404 lock xaddl
%eax
,(%rdi
)
407 * The old value is in %rax. If the store succeeded it will be the
408 * value we expected (old) from before the store, otherwise it will
409 * be the current value.
411 movq PCPU
(curthread
),%rcx
412 movq TD_PCB
(%rcx
), %rcx
413 movq $
0,PCB_ONFAULT
(%rcx
)
419 * casu64 - Compare and set user word. Returns -1 or the current value.
420 * dst = %rdi, old = %rsi, new = %rdx
424 movq PCPU
(curthread
),%rcx
425 movq TD_PCB
(%rcx
), %rcx
426 movq $fusufault
,PCB_ONFAULT
(%rcx
)
427 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
429 movq $VM_MAX_USER_ADDRESS-
8,%rax
430 cmpq
%rax
,%rdi
/* verify address is valid */
433 movq
%rsi
,%rax
/* old */
435 cmpxchgq
%rdx
,(%rdi
) /* new = %rdx */
438 * The old value is in %rax. If the store succeeded it will be the
439 * value we expected (old) from before the store, otherwise it will
440 * be the current value.
443 movq PCPU
(curthread
),%rcx
444 movq TD_PCB
(%rcx
), %rcx
445 movq $
0,PCB_ONFAULT
(%rcx
)
451 * swapu64 - Swap long in user space. ptr = %rdi, val = %rsi
455 movq PCPU
(curthread
),%rcx
456 movq TD_PCB
(%rcx
), %rcx
457 movq $fusufault
,PCB_ONFAULT
(%rcx
)
458 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
460 movq $VM_MAX_USER_ADDRESS-
8,%rax
461 cmpq
%rax
,%rdi
/* verify address is valid */
464 movq
%rsi
,%rax
/* old */
468 * The old value is in %rax. If the store succeeded it will be the
469 * value we expected (old) from before the store, otherwise it will
470 * be the current value.
473 movq PCPU
(curthread
),%rcx
474 movq TD_PCB
(%rcx
), %rcx
475 movq $
0,PCB_ONFAULT
(%rcx
)
480 ENTRY
(std_fuwordadd64
)
482 movq PCPU
(curthread
),%rcx
483 movq TD_PCB
(%rcx
), %rcx
484 movq $fusufault
,PCB_ONFAULT
(%rcx
)
485 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
487 movq $VM_MAX_USER_ADDRESS-
8,%rax
488 cmpq
%rax
,%rdi
/* verify address is valid */
491 movq
%rsi
,%rax
/* value to add */
492 lock xaddq
%rax
,(%rdi
)
495 * The old value is in %rax. If the store succeeded it will be the
496 * value we expected (old) from before the store, otherwise it will
497 * be the current value.
500 movq PCPU
(curthread
),%rcx
501 movq TD_PCB
(%rcx
), %rcx
502 movq $
0,PCB_ONFAULT
(%rcx
)
508 * Fetch (load) a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit
509 * byte from user memory. All these functions are MPSAFE.
515 movq PCPU
(curthread
),%rcx
516 movq TD_PCB
(%rcx
), %rcx
517 movq $fusufault
,PCB_ONFAULT
(%rcx
)
518 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
520 movq $VM_MAX_USER_ADDRESS-
8,%rax
521 cmpq
%rax
,%rdi
/* verify address is valid */
525 movq $
0,PCB_ONFAULT
(%rcx
)
532 movq PCPU
(curthread
),%rcx
533 movq TD_PCB
(%rcx
), %rcx
534 movq $fusufault
,PCB_ONFAULT
(%rcx
)
535 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
537 movq $VM_MAX_USER_ADDRESS-
4,%rax
538 cmpq
%rax
,%rdi
/* verify address is valid */
542 movq $
0,PCB_ONFAULT
(%rcx
)
549 movq PCPU
(curthread
),%rcx
550 movq TD_PCB
(%rcx
), %rcx
551 movq $fusufault
,PCB_ONFAULT
(%rcx
)
552 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
554 movq $VM_MAX_USER_ADDRESS-
1,%rax
559 movq $
0,PCB_ONFAULT
(%rcx
)
565 movq PCPU
(curthread
),%rcx
567 movq TD_PCB
(%rcx
), %rcx
568 movq
%rax
,PCB_ONFAULT
(%rcx
)
575 * Store a 64-bit word, a 32-bit word, a 16-bit word, or an 8-bit byte to
576 * user memory. All these functions are MPSAFE.
578 * addr = %rdi, value = %rsi
584 movq PCPU
(curthread
),%rcx
585 movq TD_PCB
(%rcx
), %rcx
586 movq $fusufault
,PCB_ONFAULT
(%rcx
)
587 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
589 movq $VM_MAX_USER_ADDRESS-
8,%rax
590 cmpq
%rax
,%rdi
/* verify address validity */
595 movq PCPU
(curthread
),%rcx
596 movq TD_PCB
(%rcx
), %rcx
597 movq
%rax
,PCB_ONFAULT
(%rcx
)
607 movq PCPU
(curthread
),%rcx
608 movq TD_PCB
(%rcx
), %rcx
609 movq $fusufault
,PCB_ONFAULT
(%rcx
)
610 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
612 movq $VM_MAX_USER_ADDRESS-
4,%rax
613 cmpq
%rax
,%rdi
/* verify address validity */
618 movq PCPU
(curthread
),%rcx
619 movq TD_PCB
(%rcx
), %rcx
620 movq
%rax
,PCB_ONFAULT
(%rcx
)
627 movq PCPU
(curthread
),%rcx
628 movq TD_PCB
(%rcx
), %rcx
629 movq $fusufault
,PCB_ONFAULT
(%rcx
)
630 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
632 movq $VM_MAX_USER_ADDRESS-
1,%rax
633 cmpq
%rax
,%rdi
/* verify address validity */
639 movq PCPU
(curthread
),%rcx
/* restore trashed register */
640 movq TD_PCB
(%rcx
), %rcx
641 movq
%rax
,PCB_ONFAULT
(%rcx
)
647 * std_copyinstr(from, to, maxlen, int *lencopied) - MP SAFE
648 * %rdi, %rsi, %rdx, %rcx
650 * copy a string from from to to, stop when a 0 character is reached.
651 * return ENAMETOOLONG if string is longer than maxlen, and
652 * EFAULT on protection violations. If lencopied is non-zero,
653 * return the actual length in *lencopied.
657 movq
%rdx
,%r8 /* %r8 = maxlen */
658 movq
%rcx
,%r9 /* %r9 = *len */
659 movq PCPU
(curthread
),%rcx
660 movq TD_PCB
(%rcx
), %rcx
661 movq $cpystrflt
,PCB_ONFAULT
(%rcx
)
662 movq
%rsp
,PCB_ONFAULT_SP
(%rcx
)
664 movq $VM_MAX_USER_ADDRESS
,%rax
666 /* make sure 'from' is within bounds */
670 /* restrict maxlen to <= VM_MAX_USER_ADDRESS-from */
682 movb
(%rdi
),%al
/* faster than lodsb+stosb */
689 /* Success -- 0 byte reached */
694 /* rdx is zero - return ENAMETOOLONG or EFAULT */
695 movq $VM_MAX_USER_ADDRESS
,%rax
699 movq $ENAMETOOLONG
,%rax
707 /* set *lencopied and return %eax */
708 movq PCPU
(curthread
),%rcx
709 movq TD_PCB
(%rcx
), %rcx
710 movq $
0,PCB_ONFAULT
(%rcx
)
721 * copystr(from, to, maxlen, int *lencopied) - MP SAFE
722 * %rdi, %rsi, %rdx, %rcx
725 movq
%rdx
,%r8 /* %r8 = maxlen */
731 movb
(%rdi
),%al
/* faster than lodsb+stosb */
738 /* Success -- 0 byte reached */
743 /* rdx is zero -- return ENAMETOOLONG */
744 movq $ENAMETOOLONG
,%rax
749 /* set *lencopied and return %rax */
757 * Handling of special x86_64 registers and descriptor tables etc
760 /* void lgdt(struct region_descriptor *rdp); */
762 /* reload the descriptor table */
765 /* flush the prefetch q */
772 movl
%eax
,%fs /* Beware, use wrmsr to set 64 bit base */
773 movl
%eax
,%gs
/* Beware, use wrmsr to set 64 bit base */
776 /* reload code selector by turning return into intersegmental return */
784 /*****************************************************************************/
785 /* setjmp, longjmp */
786 /*****************************************************************************/
789 movq
%rbx
,0(%rdi
) /* save rbx */
790 movq
%rsp
,8(%rdi
) /* save rsp */
791 movq
%rbp
,16(%rdi
) /* save rbp */
792 movq
%r12,24(%rdi
) /* save r12 */
793 movq
%r13,32(%rdi
) /* save r13 */
794 movq
%r14,40(%rdi
) /* save r14 */
795 movq
%r15,48(%rdi
) /* save r15 */
796 movq
0(%rsp
),%rdx
/* get rta */
797 movq
%rdx
,56(%rdi
) /* save rip */
798 xorl
%eax
,%eax
/* return(0); */
803 movq
0(%rdi
),%rbx
/* restore rbx */
804 movq
8(%rdi
),%rsp
/* restore rsp */
805 movq
16(%rdi
),%rbp
/* restore rbp */
806 movq
24(%rdi
),%r12 /* restore r12 */
807 movq
32(%rdi
),%r13 /* restore r13 */
808 movq
40(%rdi
),%r14 /* restore r14 */
809 movq
48(%rdi
),%r15 /* restore r15 */
810 movq
56(%rdi
),%rdx
/* get rta */
811 movq
%rdx
,0(%rsp
) /* put in return frame */
812 xorl
%eax
,%eax
/* return(1); */
818 * Support for reading MSRs in the safe manner.
821 /* int rdmsr_safe(u_int msr, uint64_t *data) */
822 movq PCPU
(curthread
),%r8
823 movq TD_PCB
(%r8), %r8
824 movq $msr_onfault
,PCB_ONFAULT
(%r8)
825 movq
%rsp
,PCB_ONFAULT_SP
(%r8)
827 rdmsr
/* Read MSR pointed by %ecx. Returns
828 hi byte in edx, lo in %eax */
829 salq $
32,%rdx
/* sign-shift %rdx left */
830 movl
%eax
,%eax
/* zero-extend %eax -> %rax */
834 movq
%rax
,PCB_ONFAULT
(%r8)
839 * Support for writing MSRs in the safe manner.
842 /* int wrmsr_safe(u_int msr, uint64_t data) */
843 movq PCPU
(curthread
),%r8
844 movq TD_PCB
(%r8), %r8
845 movq $msr_onfault
,PCB_ONFAULT
(%r8)
846 movq
%rsp
,PCB_ONFAULT_SP
(%r8)
851 wrmsr
/* Write MSR pointed by %ecx. Accepts
852 hi byte in edx, lo in %eax. */
854 movq
%rax
,PCB_ONFAULT
(%r8)
859 * MSR operations fault handler
863 movq PCPU
(curthread
),%r8
864 movq TD_PCB
(%r8), %r8
865 movq $
0,PCB_ONFAULT
(%r8)