]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/swtch.S
contrib/tzdata: import tzdata 2024a
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / swtch.S
1 /*-
2  * Copyright (c) 2014 Andrew Turner
3  * Copyright (c) 2014 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * This software was developed by Andrew Turner under sponsorship from
7  * 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 "assym.inc"
33 #include "opt_kstack_pages.h"
34 #include "opt_sched.h"
35
36 #include <machine/asm.h>
37 #include <machine/armreg.h>
38 .macro clear_step_flag pcbflags, tmp
39         tbz     \pcbflags, #PCB_SINGLE_STEP_SHIFT, 999f
40         mrs     \tmp, mdscr_el1
41         bic     \tmp, \tmp, #MDSCR_SS
42         msr     mdscr_el1, \tmp
43         isb
44 999:
45 .endm
46
47 .macro set_step_flag pcbflags, tmp
48         tbz     \pcbflags, #PCB_SINGLE_STEP_SHIFT, 999f
49         mrs     \tmp, mdscr_el1
50         orr     \tmp, \tmp, #MDSCR_SS
51         msr     mdscr_el1, \tmp
52         isb
53 999:
54 .endm
55
56 /*
57  * void cpu_throw(struct thread *old, struct thread *new)
58  */
59 ENTRY(cpu_throw)
60         /* Of old == NULL skip disabling stepping */
61         cbz     x0, 1f
62
63         /* If we were single stepping, disable it */
64         ldr     x4, [x0, #TD_PCB]
65         ldr     w5, [x4, #PCB_FLAGS]
66         clear_step_flag w5, x6
67 1:
68
69 #ifdef VFP
70         /* Backup the new thread pointer around a call to C code */
71         mov     x19, x1
72         bl      vfp_discard
73         mov     x0, x19
74 #else
75         mov     x0, x1
76 #endif
77
78         /* This returns the thread pointer so no need to save it */
79         bl      ptrauth_switch
80 #ifdef PERTHREAD_SSP
81         mov     x19, x0
82 #endif
83         /* This returns the thread pcb */
84         bl      pmap_switch
85         mov     x4, x0
86 #ifdef PERTHREAD_SSP
87         /* Update the per-thread stack canary pointer. */
88         add     x19, x19, #(TD_MD_CANARY)
89         msr     sp_el0, x19
90 #endif
91
92         /* If we are single stepping, enable it */
93         ldr     w5, [x4, #PCB_FLAGS]
94         set_step_flag w5, x6
95
96         /* Restore the registers */
97         ldp     x5, x6, [x4, #PCB_SP]
98         mov     sp, x5
99         msr     tpidr_el0, x6
100         ldr     x6, [x4, #PCB_TPIDRRO]
101         msr     tpidrro_el0, x6
102         ldp     x19, x20, [x4, #PCB_REGS + (PCB_X19 + 0) * 8]
103         ldp     x21, x22, [x4, #PCB_REGS + (PCB_X19 + 2) * 8]
104         ldp     x23, x24, [x4, #PCB_REGS + (PCB_X19 + 4) * 8]
105         ldp     x25, x26, [x4, #PCB_REGS + (PCB_X19 + 6) * 8]
106         ldp     x27, x28, [x4, #PCB_REGS + (PCB_X19 + 8) * 8]
107         ldp     x29, lr, [x4, #PCB_REGS + (PCB_X19 + 10) * 8]
108
109         ret
110 END(cpu_throw)
111
112 /*
113  * void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx)
114  *
115  * x0 = old
116  * x1 = new
117  * x2 = mtx
118  * x3 to x7, x16 and x17 are caller saved
119  */
120 ENTRY(cpu_switch)
121         /*
122          * Save the old context.
123          */
124         ldr     x4, [x0, #TD_PCB]
125
126         /* Store the callee-saved registers */
127         stp     x19, x20, [x4, #PCB_REGS + (PCB_X19 + 0) * 8]
128         stp     x21, x22, [x4, #PCB_REGS + (PCB_X19 + 2) * 8]
129         stp     x23, x24, [x4, #PCB_REGS + (PCB_X19 + 4) * 8]
130         stp     x25, x26, [x4, #PCB_REGS + (PCB_X19 + 6) * 8]
131         stp     x27, x28, [x4, #PCB_REGS + (PCB_X19 + 8) * 8]
132         stp     x29, lr, [x4, #PCB_REGS + (PCB_X19 + 10) * 8]
133         /* And the old stack pointer */
134         mov     x5, sp
135         mrs     x6, tpidrro_el0
136         str     x6, [x4, #PCB_TPIDRRO]
137         mrs     x6, tpidr_el0
138         stp     x5, x6, [x4, #PCB_SP]
139
140         /* If we were single stepping, disable it */
141         ldr     w5, [x4, #PCB_FLAGS]
142         clear_step_flag w5, x6
143
144         mov     x19, x0
145         mov     x20, x1
146         mov     x21, x2
147
148 #ifdef VFP
149         /* Load the pcb address */
150         mov     x1, x4
151         bl      vfp_save_state
152         mov     x0, x20
153 #else
154         mov     x0, x1
155 #endif
156
157         /* This returns the thread pointer so no need to save it */
158         bl      ptrauth_switch
159         /* This returns the thread pcb */
160         bl      pmap_switch
161         /* Move the new pcb out of the way */
162         mov     x4, x0
163
164         mov     x2, x21
165         mov     x1, x20
166         mov     x0, x19
167 #ifdef PERTHREAD_SSP
168         /* Update the per-thread stack canary pointer. */
169         add     x20, x20, #(TD_MD_CANARY)
170         msr     sp_el0, x20
171 #endif
172
173         /*
174          * Release the old thread.
175          */
176         stlr    x2, [x0, #TD_LOCK]
177 #if defined(SCHED_ULE) && defined(SMP)
178         /* Spin if TD_LOCK points to a blocked_lock */
179         ldr     x2, =_C_LABEL(blocked_lock)
180 1:
181         ldar    x3, [x1, #TD_LOCK]
182         cmp     x3, x2
183         b.eq    1b
184 #endif
185
186         /* If we are single stepping, enable it */
187         ldr     w5, [x4, #PCB_FLAGS]
188         set_step_flag w5, x6
189
190         /* Restore the registers */
191         ldp     x5, x6, [x4, #PCB_SP]
192         mov     sp, x5
193         msr     tpidr_el0, x6
194         ldr     x6, [x4, #PCB_TPIDRRO]
195         msr     tpidrro_el0, x6
196         ldp     x19, x20, [x4, #PCB_REGS + (PCB_X19 + 0) * 8]
197         ldp     x21, x22, [x4, #PCB_REGS + (PCB_X19 + 2) * 8]
198         ldp     x23, x24, [x4, #PCB_REGS + (PCB_X19 + 4) * 8]
199         ldp     x25, x26, [x4, #PCB_REGS + (PCB_X19 + 6) * 8]
200         ldp     x27, x28, [x4, #PCB_REGS + (PCB_X19 + 8) * 8]
201         ldp     x29, lr, [x4, #PCB_REGS + (PCB_X19 + 10) * 8]
202
203         ret
204 END(cpu_switch)
205
206 ENTRY(fork_trampoline)
207         mov     x0, x19
208         mov     x1, x20
209         mov     x2, sp
210         mov     fp, #0  /* Stack traceback stops here. */
211         bl      _C_LABEL(fork_exit)
212
213         /*
214          * Disable interrupts as we are setting userspace specific
215          * state that we won't handle correctly in an interrupt while
216          * in the kernel.
217          */
218         msr     daifset, #(DAIF_D | DAIF_INTR)
219
220         ldr     x0, [x18, #PC_CURTHREAD]
221         bl      ptrauth_enter_el0
222
223         /* Restore sp, lr, elr, and spsr */
224         ldp     x18, lr, [sp, #TF_SP]
225         ldp     x10, x11, [sp, #TF_ELR]
226         msr     sp_el0, x18
227         msr     spsr_el1, x11
228         msr     elr_el1, x10
229
230         /* Restore the CPU registers */
231         ldp     x0, x1, [sp, #TF_X + 0 * 8]
232         ldp     x2, x3, [sp, #TF_X + 2 * 8]
233         ldp     x4, x5, [sp, #TF_X + 4 * 8]
234         ldp     x6, x7, [sp, #TF_X + 6 * 8]
235         ldp     x8, x9, [sp, #TF_X + 8 * 8]
236         ldp     x10, x11, [sp, #TF_X + 10 * 8]
237         ldp     x12, x13, [sp, #TF_X + 12 * 8]
238         ldp     x14, x15, [sp, #TF_X + 14 * 8]
239         ldp     x16, x17, [sp, #TF_X + 16 * 8]
240         ldp     x18, x19, [sp, #TF_X + 18 * 8]
241         ldp     x20, x21, [sp, #TF_X + 20 * 8]
242         ldp     x22, x23, [sp, #TF_X + 22 * 8]
243         ldp     x24, x25, [sp, #TF_X + 24 * 8]
244         ldp     x26, x27, [sp, #TF_X + 26 * 8]
245         ldp     x28, x29, [sp, #TF_X + 28 * 8]
246
247         /*
248          * No need for interrupts reenabling since PSR
249          * will be set to the desired value anyway.
250          */
251         ERET
252         
253 END(fork_trampoline)
254
255 ENTRY(savectx)
256         /* Store the callee-saved registers */
257         stp     x19, x20, [x0, #PCB_REGS + (PCB_X19 + 0) * 8]
258         stp     x21, x22, [x0, #PCB_REGS + (PCB_X19 + 2) * 8]
259         stp     x23, x24, [x0, #PCB_REGS + (PCB_X19 + 4) * 8]
260         stp     x25, x26, [x0, #PCB_REGS + (PCB_X19 + 6) * 8]
261         stp     x27, x28, [x0, #PCB_REGS + (PCB_X19 + 8) * 8]
262         stp     x29, lr, [x0, #PCB_REGS + (PCB_X19 + 10) * 8]
263         /* And the old stack pointer */
264         mov     x5, sp
265         mrs     x6, tpidrro_el0
266         str     x6, [x0, #PCB_TPIDRRO]
267         mrs     x6, tpidr_el0
268         stp     x5, x6, [x0, #PCB_SP]
269
270         /* Store the VFP registers */
271 #ifdef VFP
272         mov     x28, lr
273         mov     x1, x0                  /* move pcb to the correct register */
274         mov     x0, xzr                 /* td = NULL */
275         bl      vfp_save_state
276         mov     lr, x28
277 #endif
278
279         ret
280 END(savectx)
281