]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/support.S
arm64/cmn600: Grammar fix
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / support.S
1 /*-
2  * Copyright (c) 2014 Andrew Turner
3  * Copyright (c) 2014-2015 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * Portions of this software were developed by Andrew Turner
7  * under sponsorship from the FreeBSD Foundation
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
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.
17  *
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
28  * SUCH DAMAGE.
29  *
30  */
31
32 #include <machine/asm.h>
33 #include <machine/setjmp.h>
34 #include <machine/param.h>
35 #include <machine/vmparam.h>
36
37 #include "assym.inc"
38
39 .macro check_user_access user_arg, limit, bad_addr_func
40         ldr     x7, =(\limit)
41         cmp     x\user_arg, x7
42         b.cs    \bad_addr_func
43 .endm
44
45 /*
46  * One of the fu* or su* functions failed, return -1.
47  */
48 ENTRY(fsu_fault)
49         SET_FAULT_HANDLER(xzr, x1)      /* Reset the handler function */
50         EXIT_USER_ACCESS_CHECK(w0, x1)
51 fsu_fault_nopcb:
52         mov     x0, #-1
53         ret
54 END(fsu_fault)
55
56 /*
57  * int swapueword8_llsc(volatile uint8_t *, uint8_t *)
58  */
59 ENTRY(swapueword8_llsc)
60         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
61         adr     x6, fsu_fault           /* Load the fault handler */
62         SET_FAULT_HANDLER(x6, x4)       /* And set it */
63         ENTER_USER_ACCESS(w6, x4)
64
65         ldrb    w7, [x1]
66
67         ldxrb   w2, [x0]
68         stxrb   w3, w7, [x0]
69         cbnz    w3, 1f
70
71         strb    w2, [x1]                /* Stash old value in *val */
72
73 1:      EXIT_USER_ACCESS(w6)
74         SET_FAULT_HANDLER(xzr, x6)
75         mov     w0, w3
76         ret
77 END(swapueword8_llsc)
78
79 /*
80  * int swapueword8_lse(volatile uint8_t *, uint8_t *)
81  */
82 ENTRY(swapueword8_lse)
83         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
84         adr     x6, fsu_fault           /* Load the fault handler */
85         SET_FAULT_HANDLER(x6, x4)       /* And set it */
86         ENTER_USER_ACCESS(w6, x4)
87
88         ldrb    w7, [x1]
89
90         .arch_extension lse
91         swpb    w7, w2, [x0]
92         .arch_extension nolse
93
94         strb    w2, [x1]                /* Stash old value in *val */
95
96         EXIT_USER_ACCESS(w6)
97         SET_FAULT_HANDLER(xzr, x6)
98         mov     w0, #0
99         ret
100 END(swapueword8_lse)
101
102 /*
103  * int swapueword32_llsc(volatile uint32_t *, uint32_t *)
104  */
105 ENTRY(swapueword32_llsc)
106         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
107         adr     x6, fsu_fault           /* Load the fault handler */
108         SET_FAULT_HANDLER(x6, x4)       /* And set it */
109         ENTER_USER_ACCESS(w6, x4)
110
111         ldr     w7, [x1]
112
113         ldxr    w2, [x0]                /* Stash the old value in w2 */
114         stxr    w3, w7, [x0]            /* Store new value */
115         cbnz    w3, 1f
116
117         str     w2, [x1]                /* Stash old value in *val */
118
119 1:      EXIT_USER_ACCESS(w6)
120         SET_FAULT_HANDLER(xzr, x6)
121         mov     w0, w3
122         ret
123 END(swapueword32_llsc)
124
125 /*
126  * int swapueword32_lse(volatile uint32_t *, uint32_t *)
127  */
128 ENTRY(swapueword32_lse)
129         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
130         adr     x6, fsu_fault           /* Load the fault handler */
131         SET_FAULT_HANDLER(x6, x4)       /* And set it */
132         ENTER_USER_ACCESS(w6, x4)
133
134         ldr     w7, [x1]
135
136         .arch_extension lse
137         swp     w7, w2, [x0]
138         .arch_extension nolse
139
140         str     w2, [x1]                /* Stash old value in *val */
141
142         EXIT_USER_ACCESS(w6)
143         SET_FAULT_HANDLER(xzr, x6)
144         mov     w0, #0
145         ret
146 END(swapueword32_llsc)
147
148 /*
149  * int casueword32_llsc(volatile uint32_t *, uint32_t, uint32_t *, uint32_t)
150  */
151 ENTRY(casueword32_llsc)
152         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
153         adr     x6, fsu_fault           /* Load the fault handler */
154         mov     w5, #1
155         SET_FAULT_HANDLER(x6, x4)       /* And set it */
156         ENTER_USER_ACCESS(w6, x4)
157         ldxr    w4, [x0]                /* Load-exclusive the data */
158         cmp     w4, w1                  /* Compare */
159         b.ne    1f                      /* Not equal, exit */
160         stxr    w5, w3, [x0]            /* Store the new data */
161 1:      EXIT_USER_ACCESS(w6)
162         SET_FAULT_HANDLER(xzr, x6)      /* Reset the fault handler */
163         str     w4, [x2]                /* Store the read data */
164         mov     w0, w5                  /* Result same as store status */
165         ret                             /* Return */
166 END(casueword32_llsc)
167
168 /*
169  * int casueword32_lse(volatile uint32_t *, uint32_t, uint32_t *, uint32_t)
170  */
171 ENTRY(casueword32_lse)
172         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
173         adr     x6, fsu_fault           /* Load the fault handler */
174         SET_FAULT_HANDLER(x6, x4)       /* And set it */
175         ENTER_USER_ACCESS(w6, x4)
176         mov     w7, w1                  /* Back up the compare value */
177         .arch_extension lse
178         cas     w1, w3, [x0]            /* Compare and Swap */
179         .arch_extension nolse
180         cmp     w1, w7                  /* Check if successful */
181         cset    w0, ne                  /* Return 0 on success, 1 on failure */
182         EXIT_USER_ACCESS(w6)
183         SET_FAULT_HANDLER(xzr, x6)      /* Reset the fault handler */
184         str     w1, [x2]                /* Store the read data */
185         ret                             /* Return */
186 END(casueword32_lse)
187
188 /*
189  * int casueword_llsc(volatile u_long *, u_long, u_long *, u_long)
190  */
191 ENTRY(casueword_llsc)
192         check_user_access 0, (VM_MAXUSER_ADDRESS-7), fsu_fault_nopcb
193         adr     x6, fsu_fault           /* Load the fault handler */
194         mov     w5, #1
195         SET_FAULT_HANDLER(x6, x4)       /* And set it */
196         ENTER_USER_ACCESS(w6, x4)
197         ldxr    x4, [x0]                /* Load-exclusive the data */
198         cmp     x4, x1                  /* Compare */
199         b.ne    1f                      /* Not equal, exit */
200         stxr    w5, x3, [x0]            /* Store the new data */
201 1:      EXIT_USER_ACCESS(w6)
202         SET_FAULT_HANDLER(xzr, x6)      /* Reset the fault handler */
203         str     x4, [x2]                /* Store the read data */
204         mov     w0, w5                  /* Result same as store status */
205         ret                             /* Return */
206 END(casueword_llsc)
207
208 /*
209  * int casueword_lse(volatile u_long *, u_long, u_long *, u_long)
210  */
211 ENTRY(casueword_lse)
212         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
213         adr     x6, fsu_fault           /* Load the fault handler */
214         SET_FAULT_HANDLER(x6, x4)       /* And set it */
215         ENTER_USER_ACCESS(w6, x4)
216         mov     x7, x1                  /* Back up the compare value */
217         .arch_extension lse
218         cas     x1, x3, [x0]            /* Compare and Swap */
219         .arch_extension nolse
220         cmp     x1, x7                  /* Check if successful */
221         cset    w0, ne                  /* Return 0 on success, 1 on failure */
222         EXIT_USER_ACCESS(w6)
223         SET_FAULT_HANDLER(xzr, x6)      /* Reset the fault handler */
224         str     x1, [x2]                /* Store the read data */
225         ret                             /* Return */
226 END(casueword_lse)
227
228 .macro fsudata insn, ret_reg, user_arg
229         adr     x7, fsu_fault           /* Load the fault handler */
230         SET_FAULT_HANDLER(x7, x6)       /* And set it */
231         \insn   \ret_reg, [x\user_arg]  /* Try accessing the data */
232         SET_FAULT_HANDLER(xzr, x6)      /* Reset the fault handler */
233 .endm
234
235 /*
236  * int fubyte(volatile const void *)
237  */
238 ENTRY(fubyte)
239         check_user_access 0, (VM_MAXUSER_ADDRESS), fsu_fault_nopcb
240         fsudata ldtrb, w0, 0
241         ret                             /* Return */
242 END(fubyte)
243
244 /*
245  * int fuword(volatile const void *)
246  */
247 ENTRY(fuword16)
248         check_user_access 0, (VM_MAXUSER_ADDRESS-1), fsu_fault_nopcb
249         fsudata ldtrh, w0, 0
250         ret                             /* Return */
251 END(fuword16)
252
253 /*
254  * int32_t fueword32(volatile const void *, int32_t *)
255  */
256 ENTRY(fueword32)
257         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
258         fsudata ldtr, w0, 0
259         str     w0, [x1]                /* Save the data in kernel space */
260         mov     w0, #0                  /* Success */
261         ret                             /* Return */
262 END(fueword32)
263
264 /*
265  * long fueword(volatile const void *, int64_t *)
266  * int64_t fueword64(volatile const void *, int64_t *)
267  */
268 EENTRY(fueword64)
269 ENTRY(fueword)
270         check_user_access 0, (VM_MAXUSER_ADDRESS-7), fsu_fault_nopcb
271         fsudata ldtr, x0, 0
272         str     x0, [x1]                /* Save the data in kernel space */
273         mov     x0, #0                  /* Success */
274         ret                             /* Return */
275 END(fueword)
276 EEND(fueword64)
277
278 /*
279  * int subyte(volatile void *, int)
280  */
281 ENTRY(subyte)
282         check_user_access 0, (VM_MAXUSER_ADDRESS), fsu_fault_nopcb
283         fsudata sttrb, w1, 0
284         mov     x0, #0                  /* Success */
285         ret                             /* Return */
286 END(subyte)
287
288 /*
289  * int suword16(volatile void *, int)
290  */
291 ENTRY(suword16)
292         check_user_access 0, (VM_MAXUSER_ADDRESS-1), fsu_fault_nopcb
293         fsudata sttrh, w1, 0
294         mov     x0, #0                  /* Success */
295         ret                             /* Return */
296 END(suword16)
297
298 /*
299  * int suword32(volatile void *, int)
300  */
301 ENTRY(suword32)
302         check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
303         fsudata sttr, w1, 0
304         mov     x0, #0                  /* Success */
305         ret                             /* Return */
306 END(suword32)
307
308 /*
309  * int suword(volatile void *, long)
310  */
311 EENTRY(suword64)
312 ENTRY(suword)
313         check_user_access 0, (VM_MAXUSER_ADDRESS-7), fsu_fault_nopcb
314         fsudata sttr, x1, 0
315         mov     x0, #0                  /* Success */
316         ret                             /* Return */
317 END(suword)
318 EEND(suword64)
319
320 ENTRY(setjmp)
321         /* Store the stack pointer */
322         mov     x8, sp
323         str     x8, [x0], #8
324
325         /* Store the general purpose registers and lr */
326         stp     x19, x20, [x0], #16
327         stp     x21, x22, [x0], #16
328         stp     x23, x24, [x0], #16
329         stp     x25, x26, [x0], #16
330         stp     x27, x28, [x0], #16
331         stp     x29, lr, [x0], #16
332
333         /* Return value */
334         mov     x0, #0
335         ret
336 END(setjmp)
337
338 ENTRY(longjmp)
339         /* Restore the stack pointer */
340         ldr     x8, [x0], #8
341         mov     sp, x8
342
343         /* Restore the general purpose registers and lr */
344         ldp     x19, x20, [x0], #16
345         ldp     x21, x22, [x0], #16
346         ldp     x23, x24, [x0], #16
347         ldp     x25, x26, [x0], #16
348         ldp     x27, x28, [x0], #16
349         ldp     x29, lr, [x0], #16
350
351         /* Load the return value */
352         mov     x0, x1
353         ret
354 END(longjmp)
355
356 /*
357  * pagezero, simple implementation
358  */
359 ENTRY(pagezero_simple)
360         add     x1, x0, #PAGE_SIZE
361
362 1:
363         stp     xzr, xzr, [x0], #0x10
364         stp     xzr, xzr, [x0], #0x10
365         stp     xzr, xzr, [x0], #0x10
366         stp     xzr, xzr, [x0], #0x10
367         cmp     x0, x1
368         b.ne    1b
369         ret
370
371 END(pagezero_simple)
372
373 /*
374  * pagezero, cache assisted
375  */
376 ENTRY(pagezero_cache)
377         add     x1, x0, #PAGE_SIZE
378
379         adrp    x2, dczva_line_size
380         ldr     x2, [x2, :lo12:dczva_line_size]
381
382 1:
383         dc      zva, x0
384         add     x0, x0, x2
385         cmp     x0, x1
386         b.ne    1b
387         ret
388
389 END(pagezero_cache)