2 * Copyright (c) 2014 Andrew Turner
3 * Copyright (c) 2014-2015 The FreeBSD Foundation
6 * Portions of this software were developed by Andrew Turner
7 * under sponsorship from the FreeBSD Foundation
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <machine/asm.h>
33 __FBSDID("$FreeBSD$");
35 #include <machine/setjmp.h>
36 #include <machine/param.h>
37 #include <machine/vmparam.h>
41 .macro check_user_access user_arg, limit, bad_addr_func
48 * One of the fu* or su* functions failed, return -1.
51 SET_FAULT_HANDLER(xzr, x1) /* Reset the handler function */
52 EXIT_USER_ACCESS_CHECK(w0, x1)
59 * int swapueword8_llsc(volatile uint8_t *, uint8_t *)
61 ENTRY(swapueword8_llsc)
62 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
63 adr x6, fsu_fault /* Load the fault handler */
64 SET_FAULT_HANDLER(x6, x4) /* And set it */
65 ENTER_USER_ACCESS(w6, x4)
73 strb w2, [x1] /* Stash old value in *val */
75 1: EXIT_USER_ACCESS(w6)
76 SET_FAULT_HANDLER(xzr, x6)
82 * int swapueword8_lse(volatile uint8_t *, uint8_t *)
84 ENTRY(swapueword8_lse)
85 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
86 adr x6, fsu_fault /* Load the fault handler */
87 SET_FAULT_HANDLER(x6, x4) /* And set it */
88 ENTER_USER_ACCESS(w6, x4)
96 strb w2, [x1] /* Stash old value in *val */
99 SET_FAULT_HANDLER(xzr, x6)
105 * int swapueword32_llsc(volatile uint32_t *, uint32_t *)
107 ENTRY(swapueword32_llsc)
108 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
109 adr x6, fsu_fault /* Load the fault handler */
110 SET_FAULT_HANDLER(x6, x4) /* And set it */
111 ENTER_USER_ACCESS(w6, x4)
115 ldxr w2, [x0] /* Stash the old value in w2 */
116 stxr w3, w7, [x0] /* Store new value */
119 str w2, [x1] /* Stash old value in *val */
121 1: EXIT_USER_ACCESS(w6)
122 SET_FAULT_HANDLER(xzr, x6)
125 END(swapueword32_llsc)
128 * int swapueword32_lse(volatile uint32_t *, uint32_t *)
130 ENTRY(swapueword32_lse)
131 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
132 adr x6, fsu_fault /* Load the fault handler */
133 SET_FAULT_HANDLER(x6, x4) /* And set it */
134 ENTER_USER_ACCESS(w6, x4)
140 .arch_extension nolse
142 str w2, [x1] /* Stash old value in *val */
145 SET_FAULT_HANDLER(xzr, x6)
148 END(swapueword32_llsc)
151 * int casueword32_llsc(volatile uint32_t *, uint32_t, uint32_t *, uint32_t)
153 ENTRY(casueword32_llsc)
154 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
155 adr x6, fsu_fault /* Load the fault handler */
157 SET_FAULT_HANDLER(x6, x4) /* And set it */
158 ENTER_USER_ACCESS(w6, x4)
159 ldxr w4, [x0] /* Load-exclusive the data */
160 cmp w4, w1 /* Compare */
161 b.ne 1f /* Not equal, exit */
162 stxr w5, w3, [x0] /* Store the new data */
163 1: EXIT_USER_ACCESS(w6)
164 SET_FAULT_HANDLER(xzr, x6) /* Reset the fault handler */
165 str w4, [x2] /* Store the read data */
166 mov w0, w5 /* Result same as store status */
168 END(casueword32_llsc)
171 * int casueword32_lse(volatile uint32_t *, uint32_t, uint32_t *, uint32_t)
173 ENTRY(casueword32_lse)
174 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
175 adr x6, fsu_fault /* Load the fault handler */
176 SET_FAULT_HANDLER(x6, x4) /* And set it */
177 ENTER_USER_ACCESS(w6, x4)
178 mov w7, w1 /* Back up the compare value */
180 cas w1, w3, [x0] /* Compare and Swap */
181 .arch_extension nolse
182 cmp w1, w7 /* Check if successful */
183 cset w0, ne /* Return 0 on success, 1 on failure */
185 SET_FAULT_HANDLER(xzr, x6) /* Reset the fault handler */
186 str w1, [x2] /* Store the read data */
191 * int casueword_llsc(volatile u_long *, u_long, u_long *, u_long)
193 ENTRY(casueword_llsc)
194 check_user_access 0, (VM_MAXUSER_ADDRESS-7), fsu_fault_nopcb
195 adr x6, fsu_fault /* Load the fault handler */
197 SET_FAULT_HANDLER(x6, x4) /* And set it */
198 ENTER_USER_ACCESS(w6, x4)
199 ldxr x4, [x0] /* Load-exclusive the data */
200 cmp x4, x1 /* Compare */
201 b.ne 1f /* Not equal, exit */
202 stxr w5, x3, [x0] /* Store the new data */
203 1: EXIT_USER_ACCESS(w6)
204 SET_FAULT_HANDLER(xzr, x6) /* Reset the fault handler */
205 str x4, [x2] /* Store the read data */
206 mov w0, w5 /* Result same as store status */
211 * int casueword_lse(volatile u_long *, u_long, u_long *, u_long)
214 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
215 adr x6, fsu_fault /* Load the fault handler */
216 SET_FAULT_HANDLER(x6, x4) /* And set it */
217 ENTER_USER_ACCESS(w6, x4)
218 mov x7, x1 /* Back up the compare value */
220 cas x1, x3, [x0] /* Compare and Swap */
221 .arch_extension nolse
222 cmp x1, x7 /* Check if successful */
223 cset w0, ne /* Return 0 on success, 1 on failure */
225 SET_FAULT_HANDLER(xzr, x6) /* Reset the fault handler */
226 str x1, [x2] /* Store the read data */
230 .macro fsudata insn, ret_reg, user_arg
231 adr x7, fsu_fault /* Load the fault handler */
232 SET_FAULT_HANDLER(x7, x6) /* And set it */
233 \insn \ret_reg, [x\user_arg] /* Try accessing the data */
234 SET_FAULT_HANDLER(xzr, x6) /* Reset the fault handler */
238 * int fubyte(volatile const void *)
241 check_user_access 0, (VM_MAXUSER_ADDRESS), fsu_fault_nopcb
247 * int fuword(volatile const void *)
250 check_user_access 0, (VM_MAXUSER_ADDRESS-1), fsu_fault_nopcb
256 * int32_t fueword32(volatile const void *, int32_t *)
259 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
261 str w0, [x1] /* Save the data in kernel space */
262 mov w0, #0 /* Success */
267 * long fueword(volatile const void *, int64_t *)
268 * int64_t fueword64(volatile const void *, int64_t *)
272 check_user_access 0, (VM_MAXUSER_ADDRESS-7), fsu_fault_nopcb
274 str x0, [x1] /* Save the data in kernel space */
275 mov x0, #0 /* Success */
281 * int subyte(volatile void *, int)
284 check_user_access 0, (VM_MAXUSER_ADDRESS), fsu_fault_nopcb
286 mov x0, #0 /* Success */
291 * int suword16(volatile void *, int)
294 check_user_access 0, (VM_MAXUSER_ADDRESS-1), fsu_fault_nopcb
296 mov x0, #0 /* Success */
301 * int suword32(volatile void *, int)
304 check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
306 mov x0, #0 /* Success */
311 * int suword(volatile void *, long)
315 check_user_access 0, (VM_MAXUSER_ADDRESS-7), fsu_fault_nopcb
317 mov x0, #0 /* Success */
323 /* Store the stack pointer */
327 /* Store the general purpose registers and lr */
328 stp x19, x20, [x0], #16
329 stp x21, x22, [x0], #16
330 stp x23, x24, [x0], #16
331 stp x25, x26, [x0], #16
332 stp x27, x28, [x0], #16
333 stp x29, lr, [x0], #16
341 /* Restore the stack pointer */
345 /* Restore the general purpose registers and lr */
346 ldp x19, x20, [x0], #16
347 ldp x21, x22, [x0], #16
348 ldp x23, x24, [x0], #16
349 ldp x25, x26, [x0], #16
350 ldp x27, x28, [x0], #16
351 ldp x29, lr, [x0], #16
353 /* Load the return value */
359 * pagezero, simple implementation
361 ENTRY(pagezero_simple)
362 add x1, x0, #PAGE_SIZE
365 stp xzr, xzr, [x0], #0x10
366 stp xzr, xzr, [x0], #0x10
367 stp xzr, xzr, [x0], #0x10
368 stp xzr, xzr, [x0], #0x10
376 * pagezero, cache assisted
378 ENTRY(pagezero_cache)
379 add x1, x0, #PAGE_SIZE
381 ldr x2, =dczva_line_size