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