]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/copyinout.S
Merge bmake-20201117
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / copyinout.S
1 /*-
2  * Copyright (c) 2015 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Andrew Turner under
6  * sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30
31 #include <machine/asm.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/errno.h>
35
36 #include <machine/vmparam.h>
37
38 #include "assym.inc"
39
40 .macro check_user_access user_arg, size_arg, bad_access_func
41         adds    x6, x\user_arg, x\size_arg
42         b.cs    \bad_access_func
43         ldr     x7, =VM_MAXUSER_ADDRESS
44         cmp     x6, x7
45         b.hi    \bad_access_func
46 .endm
47
48 /*
49  * Fault handler for the copy{in,out} functions below.
50  */
51 ENTRY(copyio_fault)
52         SET_FAULT_HANDLER(xzr, x1) /* Clear the handler */
53         EXIT_USER_ACCESS_CHECK(w0, x1)
54 copyio_fault_nopcb:
55         mov     x0, #EFAULT
56         ret
57 END(copyio_fault)
58
59 /*
60  * Copies from a kernel to user address
61  *
62  * int copyout(const void *kaddr, void *udaddr, size_t len)
63  */
64 ENTRY(copyout)
65         cbz     x2, 1f
66         check_user_access 1, 2, copyio_fault_nopcb
67
68         b       copycommon
69
70 1:      mov     x0, xzr         /* return 0 */
71         ret
72
73 END(copyout)
74
75 /*
76  * Copies from a user to kernel address
77  *
78  * int copyin(const void *uaddr, void *kdaddr, size_t len)
79  */
80 ENTRY(copyin)
81         cbz     x2, 1f
82         check_user_access 0, 2, copyio_fault_nopcb
83
84         b       copycommon
85
86 1:      mov     x0, xzr         /* return 0 */
87         ret
88
89 END(copyin)
90
91 /*
92  * Copies a string from a user to kernel address
93  *
94  * int copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
95  */
96 ENTRY(copyinstr)
97         mov     x5, xzr         /* count = 0 */
98         mov     w4, #1          /* If zero return faulure */
99         cbz     x2, 3f          /* If len == 0 then skip loop */
100
101         adr     x6, copyio_fault /* Get the handler address */
102         SET_FAULT_HANDLER(x6, x7) /* Set the handler */
103
104         ldr     x7, =VM_MAXUSER_ADDRESS
105 1:      cmp     x0, x7
106         b.cs    copyio_fault
107         ldtrb   w4, [x0]        /* Load from uaddr */
108         add     x0, x0, #1      /* Next char */
109         strb    w4, [x1], #1    /* Store in kaddr */
110         add     x5, x5, #1      /* count++ */
111         cbz     w4, 2f          /* Break when NUL-terminated */
112         sub     x2, x2, #1      /* len-- */
113         cbnz    x2, 1b
114
115 2:      SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
116
117
118 3:      cbz     x3, 4f          /* Check if done != NULL */
119         str     x5, [x3]        /* done = count */
120
121 4:      mov     w1, #ENAMETOOLONG /* Load ENAMETOOLONG to return if failed */
122         cmp     w4, #0          /* Check if we saved the NUL-terminator */
123         csel    w0, wzr, w1, eq /* If so return success, else failure */
124         ret
125 END(copyinstr)
126
127 /*
128  * Local helper
129  *
130  * x0 - src pointer
131  * x1 - dst pointer
132  * x2 - size
133  * lr - the return address, so jump here instead of calling
134  *
135  * This function is optimized to minimize concurrent memory accesses. In
136  * present form it is suited for cores with a single memory prefetching
137  * unit.
138  * ARM64TODO: 
139  *   Consider using separate functions for each ARM64 core. Adding memory
140  *   access interleaving might increase a total throughput on A57 or A72.
141  */
142         .text
143         .align  4
144         .local  copycommon
145         .type   copycommon,@function
146
147 copycommon:
148         adr     x6, copyio_fault /* Get the handler address */
149         SET_FAULT_HANDLER(x6, x7) /* Set the handler */
150         ENTER_USER_ACCESS(w6, x7)
151
152         /* Check alignment */
153         orr     x3, x0, x1
154         ands    x3, x3, 0x07
155         b.eq    aligned
156
157         /* Unaligned is byte by byte copy */
158 byte_by_byte:
159         ldrb    w3, [x0], #0x01
160         strb    w3, [x1], #0x01
161         subs    x2, x2, #0x01
162         b.ne    byte_by_byte
163         b       ending
164
165 aligned:
166         cmp     x2, #0x10
167         b.lt    lead_out
168         cmp     x2, #0x40
169         b.lt    by_dwords_start
170
171         /* Block copy */
172         lsr     x15, x2, #0x06
173 by_blocks:
174         ldp     x3, x4, [x0], #0x10
175         ldp     x5, x6, [x0], #0x10
176         ldp     x7, x8, [x0], #0x10
177         ldp     x9, x10, [x0], #0x10
178         stp     x3, x4, [x1], #0x10
179         stp     x5, x6, [x1], #0x10
180         stp     x7, x8, [x1], #0x10
181         stp     x9, x10, [x1], #0x10
182
183         subs    x15, x15, #0x01
184         b.ne    by_blocks
185
186         and     x2, x2, #0x3f
187
188 by_dwords_start:
189         lsr     x15, x2, #0x04
190         cbz     x15, lead_out
191 by_dwords:
192         ldp     x3, x4, [x0], #0x10
193         stp     x3, x4, [x1], #0x10
194         subs    x15, x15, #0x01
195         b.ne    by_dwords
196
197         /* Less than 16 bytes to copy */
198 lead_out:
199         tbz     x2, #0x03, last_word
200         ldr     x3, [x0], #0x08
201         str     x3, [x1], #0x08
202
203 last_word:
204         tbz     x2, #0x02, last_hword
205         ldr     w3, [x0], #0x04
206         str     w3, [x1], #0x04
207
208 last_hword:
209         tbz     x2, #0x01, last_byte
210         ldrh    w3, [x0], #0x02
211         strh    w3, [x1], #0x02
212
213 last_byte:
214         tbz     x2, #0x00, ending
215         ldrb    w3, [x0]
216         strb    w3, [x1]
217
218 ending:
219         EXIT_USER_ACCESS_CHECK(w6, x7)
220         SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */
221
222         mov     x0, xzr         /* return 0 */
223         ret
224         .size   copycommon, . - copycommon