cpuswitch.S revision 1.49 1 1.49 scw /* $NetBSD: cpuswitch.S,v 1.49 2007/09/15 09:25:21 scw Exp $ */
2 1.1 chris
3 1.1 chris /*
4 1.30 scw * Copyright 2003 Wasabi Systems, Inc.
5 1.30 scw * All rights reserved.
6 1.30 scw *
7 1.30 scw * Written by Steve C. Woodford for Wasabi Systems, Inc.
8 1.30 scw *
9 1.30 scw * Redistribution and use in source and binary forms, with or without
10 1.30 scw * modification, are permitted provided that the following conditions
11 1.30 scw * are met:
12 1.30 scw * 1. Redistributions of source code must retain the above copyright
13 1.30 scw * notice, this list of conditions and the following disclaimer.
14 1.30 scw * 2. Redistributions in binary form must reproduce the above copyright
15 1.30 scw * notice, this list of conditions and the following disclaimer in the
16 1.30 scw * documentation and/or other materials provided with the distribution.
17 1.30 scw * 3. All advertising materials mentioning features or use of this software
18 1.30 scw * must display the following acknowledgement:
19 1.30 scw * This product includes software developed for the NetBSD Project by
20 1.30 scw * Wasabi Systems, Inc.
21 1.30 scw * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.30 scw * or promote products derived from this software without specific prior
23 1.30 scw * written permission.
24 1.30 scw *
25 1.30 scw * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.30 scw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.30 scw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.30 scw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.30 scw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.30 scw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.30 scw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.30 scw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.30 scw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.30 scw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.30 scw * POSSIBILITY OF SUCH DAMAGE.
36 1.30 scw */
37 1.30 scw /*
38 1.1 chris * Copyright (c) 1994-1998 Mark Brinicombe.
39 1.1 chris * Copyright (c) 1994 Brini.
40 1.1 chris * All rights reserved.
41 1.1 chris *
42 1.1 chris * This code is derived from software written for Brini by Mark Brinicombe
43 1.1 chris *
44 1.1 chris * Redistribution and use in source and binary forms, with or without
45 1.1 chris * modification, are permitted provided that the following conditions
46 1.1 chris * are met:
47 1.1 chris * 1. Redistributions of source code must retain the above copyright
48 1.1 chris * notice, this list of conditions and the following disclaimer.
49 1.1 chris * 2. Redistributions in binary form must reproduce the above copyright
50 1.1 chris * notice, this list of conditions and the following disclaimer in the
51 1.1 chris * documentation and/or other materials provided with the distribution.
52 1.1 chris * 3. All advertising materials mentioning features or use of this software
53 1.1 chris * must display the following acknowledgement:
54 1.1 chris * This product includes software developed by Brini.
55 1.1 chris * 4. The name of the company nor the name of the author may be used to
56 1.1 chris * endorse or promote products derived from this software without specific
57 1.1 chris * prior written permission.
58 1.1 chris *
59 1.1 chris * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
60 1.1 chris * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
61 1.1 chris * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
62 1.1 chris * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
63 1.1 chris * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
64 1.1 chris * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
65 1.1 chris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 1.1 chris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 1.1 chris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 1.1 chris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 1.1 chris * SUCH DAMAGE.
70 1.1 chris *
71 1.1 chris * RiscBSD kernel project
72 1.1 chris *
73 1.1 chris * cpuswitch.S
74 1.1 chris *
75 1.1 chris * cpu switching functions
76 1.1 chris *
77 1.1 chris * Created : 15/10/94
78 1.1 chris */
79 1.1 chris
80 1.1 chris #include "opt_armfpe.h"
81 1.30 scw #include "opt_arm32_pmap.h"
82 1.19 bjh21 #include "opt_multiprocessor.h"
83 1.36 martin #include "opt_lockdebug.h"
84 1.1 chris
85 1.1 chris #include "assym.h"
86 1.46 briggs #include <arm/arm32/pte.h>
87 1.1 chris #include <machine/param.h>
88 1.1 chris #include <machine/cpu.h>
89 1.1 chris #include <machine/frame.h>
90 1.1 chris #include <machine/asm.h>
91 1.1 chris
92 1.34 kristerw /* LINTSTUB: include <sys/param.h> */
93 1.34 kristerw
94 1.1 chris #undef IRQdisable
95 1.1 chris #undef IRQenable
96 1.1 chris
97 1.1 chris /*
98 1.1 chris * New experimental definitions of IRQdisable and IRQenable
99 1.1 chris * These keep FIQ's enabled since FIQ's are special.
100 1.1 chris */
101 1.1 chris
102 1.1 chris #define IRQdisable \
103 1.13 thorpej mrs r14, cpsr ; \
104 1.1 chris orr r14, r14, #(I32_bit) ; \
105 1.13 thorpej msr cpsr_c, r14 ; \
106 1.1 chris
107 1.1 chris #define IRQenable \
108 1.13 thorpej mrs r14, cpsr ; \
109 1.1 chris bic r14, r14, #(I32_bit) ; \
110 1.13 thorpej msr cpsr_c, r14 ; \
111 1.1 chris
112 1.30 scw /*
113 1.30 scw * These are used for switching the translation table/DACR.
114 1.30 scw * Since the vector page can be invalid for a short time, we must
115 1.30 scw * disable both regular IRQs *and* FIQs.
116 1.30 scw *
117 1.30 scw * XXX: This is not necessary if the vector table is relocated.
118 1.30 scw */
119 1.30 scw #define IRQdisableALL \
120 1.30 scw mrs r14, cpsr ; \
121 1.30 scw orr r14, r14, #(I32_bit | F32_bit) ; \
122 1.30 scw msr cpsr_c, r14
123 1.30 scw
124 1.30 scw #define IRQenableALL \
125 1.30 scw mrs r14, cpsr ; \
126 1.30 scw bic r14, r14, #(I32_bit | F32_bit) ; \
127 1.30 scw msr cpsr_c, r14
128 1.30 scw
129 1.1 chris .text
130 1.1 chris
131 1.19 bjh21 #ifdef MULTIPROCESSOR
132 1.19 bjh21 .Lcpu_info_store:
133 1.19 bjh21 .word _C_LABEL(cpu_info_store)
134 1.29 thorpej .Lcurlwp:
135 1.19 bjh21 /* FIXME: This is bogus in the general case. */
136 1.29 thorpej .word _C_LABEL(cpu_info_store) + CI_CURLWP
137 1.22 bjh21
138 1.22 bjh21 .Lcurpcb:
139 1.22 bjh21 .word _C_LABEL(cpu_info_store) + CI_CURPCB
140 1.19 bjh21 #else
141 1.29 thorpej .Lcurlwp:
142 1.29 thorpej .word _C_LABEL(curlwp)
143 1.1 chris
144 1.17 thorpej .Lcurpcb:
145 1.1 chris .word _C_LABEL(curpcb)
146 1.22 bjh21 #endif
147 1.1 chris
148 1.17 thorpej .Lcpufuncs:
149 1.1 chris .word _C_LABEL(cpufuncs)
150 1.1 chris
151 1.22 bjh21 #ifndef MULTIPROCESSOR
152 1.1 chris .data
153 1.1 chris .global _C_LABEL(curpcb)
154 1.1 chris _C_LABEL(curpcb):
155 1.1 chris .word 0x00000000
156 1.1 chris .text
157 1.22 bjh21 #endif
158 1.1 chris
159 1.17 thorpej .Lblock_userspace_access:
160 1.1 chris .word _C_LABEL(block_userspace_access)
161 1.1 chris
162 1.30 scw
163 1.1 chris /*
164 1.47 yamt * struct lwp *
165 1.47 yamt * cpu_switchto(struct lwp *current, struct lwp *next)
166 1.48 skrll *
167 1.47 yamt * Switch to the specified next LWP
168 1.47 yamt * Arguments:
169 1.16 thorpej *
170 1.29 thorpej * r0 'struct lwp *' of the current LWP
171 1.47 yamt * r1 'struct lwp *' of the LWP to switch to
172 1.1 chris */
173 1.47 yamt ENTRY(cpu_switchto)
174 1.28 bjh21 stmfd sp!, {r4-r7, lr}
175 1.1 chris
176 1.47 yamt mov r6, r1 /* save new lwp */
177 1.47 yamt mov r4, r0 /* save old lwp, it's the return value */
178 1.7 chris
179 1.1 chris IRQdisable
180 1.7 chris
181 1.19 bjh21 #ifdef MULTIPROCESSOR
182 1.19 bjh21 /* XXX use curcpu() */
183 1.19 bjh21 ldr r0, .Lcpu_info_store
184 1.29 thorpej str r0, [r6, #(L_CPU)]
185 1.19 bjh21 #else
186 1.29 thorpej /* l->l_cpu initialized in fork1() for single-processor */
187 1.19 bjh21 #endif
188 1.1 chris
189 1.29 thorpej /* We have a new curlwp now so make a note it */
190 1.29 thorpej ldr r7, .Lcurlwp
191 1.1 chris str r6, [r7]
192 1.1 chris
193 1.1 chris /* Hook in a new pcb */
194 1.17 thorpej ldr r7, .Lcurpcb
195 1.29 thorpej ldr r0, [r6, #(L_ADDR)]
196 1.1 chris str r0, [r7]
197 1.1 chris
198 1.1 chris /* At this point we can allow IRQ's again. */
199 1.1 chris IRQenable
200 1.1 chris
201 1.47 yamt /* rem: r4 = old lwp */
202 1.43 skrll /* rem: r6 = new lwp */
203 1.4 chris /* rem: interrupts are enabled */
204 1.1 chris
205 1.1 chris /*
206 1.47 yamt * If the old lwp on entry to cpu_switchto was zero then the
207 1.1 chris * process that called it was exiting. This means that we do
208 1.1 chris * not need to save the current context. Instead we can jump
209 1.1 chris * straight to restoring the context for the new process.
210 1.1 chris */
211 1.47 yamt teq r4, #0x00000000
212 1.49 scw ldreq r9, [r6, #(L_ADDR)]
213 1.49 scw beq .Ldo_switch
214 1.1 chris
215 1.47 yamt /* rem: r4 = old lwp */
216 1.43 skrll /* rem: r6 = new lwp */
217 1.4 chris /* rem: interrupts are enabled */
218 1.1 chris
219 1.48 skrll /* Save old context */
220 1.1 chris
221 1.29 thorpej /* Get the user structure for the old lwp. */
222 1.47 yamt ldr r1, [r4, #(L_ADDR)]
223 1.1 chris
224 1.29 thorpej /* Save all the registers in the old lwp's pcb */
225 1.37 scw #ifndef __XSCALE__
226 1.28 bjh21 add r7, r1, #(PCB_R8)
227 1.28 bjh21 stmia r7, {r8-r13}
228 1.37 scw #else
229 1.37 scw strd r8, [r1, #(PCB_R8)]
230 1.37 scw strd r10, [r1, #(PCB_R10)]
231 1.37 scw strd r12, [r1, #(PCB_R12)]
232 1.37 scw #endif
233 1.1 chris
234 1.1 chris /*
235 1.29 thorpej * NOTE: We can now use r8-r13 until it is time to restore
236 1.29 thorpej * them for the new process.
237 1.29 thorpej */
238 1.29 thorpej
239 1.47 yamt /* rem: r1 = old lwp PCB */
240 1.47 yamt /* rem: r4 = old lwp */
241 1.47 yamt /* rem: r6 = new lwp */
242 1.47 yamt /* rem: interrupts are enabled */
243 1.47 yamt
244 1.29 thorpej /* Remember the old PCB. */
245 1.29 thorpej mov r8, r1
246 1.29 thorpej
247 1.29 thorpej /* r1 now free! */
248 1.29 thorpej
249 1.29 thorpej /* Get the user structure for the new process in r9 */
250 1.29 thorpej ldr r9, [r6, #(L_ADDR)]
251 1.29 thorpej
252 1.29 thorpej /*
253 1.1 chris * This can be optimised... We know we want to go from SVC32
254 1.1 chris * mode to UND32 mode
255 1.1 chris */
256 1.13 thorpej mrs r3, cpsr
257 1.1 chris bic r2, r3, #(PSR_MODE)
258 1.1 chris orr r2, r2, #(PSR_UND32_MODE | I32_bit)
259 1.13 thorpej msr cpsr_c, r2
260 1.1 chris
261 1.29 thorpej str sp, [r8, #(PCB_UND_SP)]
262 1.1 chris
263 1.13 thorpej msr cpsr_c, r3 /* Restore the old mode */
264 1.1 chris
265 1.48 skrll /* What else needs to be saved? Only FPA stuff when that is supported */
266 1.1 chris
267 1.48 skrll /* Restore saved context */
268 1.1 chris
269 1.47 yamt /* rem: r4 = old lwp */
270 1.29 thorpej /* rem: r6 = new lwp */
271 1.29 thorpej /* rem: r9 = new PCB */
272 1.9 thorpej /* rem: interrupts are enabled */
273 1.9 thorpej
274 1.49 scw .Ldo_switch:
275 1.49 scw mov r0, r4
276 1.49 scw mov r1, r6
277 1.49 scw bl _C_LABEL(pmap_switch)
278 1.30 scw
279 1.30 scw
280 1.47 yamt /* rem: r4 = old lwp */
281 1.29 thorpej /* rem: r6 = new lwp */
282 1.29 thorpej /* rem: r9 = new PCB */
283 1.29 thorpej
284 1.1 chris /*
285 1.1 chris * This can be optimised... We know we want to go from SVC32
286 1.1 chris * mode to UND32 mode
287 1.1 chris */
288 1.13 thorpej mrs r3, cpsr
289 1.1 chris bic r2, r3, #(PSR_MODE)
290 1.1 chris orr r2, r2, #(PSR_UND32_MODE)
291 1.13 thorpej msr cpsr_c, r2
292 1.1 chris
293 1.29 thorpej ldr sp, [r9, #(PCB_UND_SP)]
294 1.1 chris
295 1.13 thorpej msr cpsr_c, r3 /* Restore the old mode */
296 1.1 chris
297 1.28 bjh21 /* Restore all the save registers */
298 1.37 scw #ifndef __XSCALE__
299 1.29 thorpej add r7, r9, #PCB_R8
300 1.28 bjh21 ldmia r7, {r8-r13}
301 1.28 bjh21
302 1.29 thorpej sub r7, r7, #PCB_R8 /* restore PCB pointer */
303 1.37 scw #else
304 1.37 scw mov r7, r9
305 1.37 scw ldr r8, [r7, #(PCB_R8)]
306 1.37 scw ldr r9, [r7, #(PCB_R9)]
307 1.37 scw ldr r10, [r7, #(PCB_R10)]
308 1.37 scw ldr r11, [r7, #(PCB_R11)]
309 1.37 scw ldr r12, [r7, #(PCB_R12)]
310 1.37 scw ldr r13, [r7, #(PCB_SP)]
311 1.37 scw #endif
312 1.29 thorpej
313 1.29 thorpej ldr r5, [r6, #(L_PROC)] /* fetch the proc for below */
314 1.29 thorpej
315 1.47 yamt /* rem: r4 = old lwp */
316 1.29 thorpej /* rem: r5 = new lwp's proc */
317 1.29 thorpej /* rem: r6 = new lwp */
318 1.29 thorpej /* rem: r7 = new pcb */
319 1.18 thorpej
320 1.1 chris #ifdef ARMFPE
321 1.29 thorpej add r0, r7, #(USER_SIZE) & 0x00ff
322 1.1 chris add r0, r0, #(USER_SIZE) & 0xff00
323 1.1 chris bl _C_LABEL(arm_fpe_core_changecontext)
324 1.1 chris #endif
325 1.1 chris
326 1.1 chris /* We can enable interrupts again */
327 1.30 scw IRQenableALL
328 1.1 chris
329 1.47 yamt /* rem: r4 = old lwp */
330 1.29 thorpej /* rem: r5 = new lwp's proc */
331 1.29 thorpej /* rem: r6 = new lwp */
332 1.18 thorpej /* rem: r7 = new PCB */
333 1.18 thorpej
334 1.18 thorpej /*
335 1.18 thorpej * Check for restartable atomic sequences (RAS).
336 1.18 thorpej */
337 1.18 thorpej
338 1.39 dsl ldr r2, [r5, #(P_RASLIST)]
339 1.38 scw ldr r1, [r7, #(PCB_TF)] /* r1 = trapframe (used below) */
340 1.18 thorpej teq r2, #0 /* p->p_nras == 0? */
341 1.18 thorpej bne .Lswitch_do_ras /* no, check for one */
342 1.18 thorpej
343 1.14 briggs .Lswitch_return:
344 1.47 yamt /* cpu_switchto returns the old lwp */
345 1.29 thorpej mov r0, r4
346 1.47 yamt /* lwp_trampoline expects new lwp as it's second argument */
347 1.47 yamt mov r1, r6
348 1.1 chris
349 1.1 chris /*
350 1.1 chris * Pull the registers that got pushed when either savectx() or
351 1.47 yamt * cpu_switchto() was called and return.
352 1.1 chris */
353 1.28 bjh21 ldmfd sp!, {r4-r7, pc}
354 1.18 thorpej
355 1.18 thorpej .Lswitch_do_ras:
356 1.38 scw ldr r1, [r1, #(TF_PC)] /* second ras_lookup() arg */
357 1.29 thorpej mov r0, r5 /* first ras_lookup() arg */
358 1.18 thorpej bl _C_LABEL(ras_lookup)
359 1.18 thorpej cmn r0, #1 /* -1 means "not in a RAS" */
360 1.38 scw ldrne r1, [r7, #(PCB_TF)]
361 1.38 scw strne r0, [r1, #(TF_PC)]
362 1.18 thorpej b .Lswitch_return
363 1.1 chris
364 1.1 chris
365 1.7 chris /* LINTSTUB: Func: void savectx(struct pcb *pcb) */
366 1.1 chris ENTRY(savectx)
367 1.1 chris /*
368 1.1 chris * r0 = pcb
369 1.1 chris */
370 1.1 chris
371 1.1 chris /* Push registers.*/
372 1.28 bjh21 stmfd sp!, {r4-r7, lr}
373 1.1 chris
374 1.1 chris /* Store all the registers in the process's pcb */
375 1.37 scw #ifndef __XSCALE__
376 1.28 bjh21 add r2, r0, #(PCB_R8)
377 1.28 bjh21 stmia r2, {r8-r13}
378 1.37 scw #else
379 1.37 scw strd r8, [r0, #(PCB_R8)]
380 1.37 scw strd r10, [r0, #(PCB_R10)]
381 1.37 scw strd r12, [r0, #(PCB_R12)]
382 1.37 scw #endif
383 1.1 chris
384 1.1 chris /* Pull the regs of the stack */
385 1.28 bjh21 ldmfd sp!, {r4-r7, pc}
386 1.1 chris
387 1.47 yamt ENTRY(lwp_trampoline)
388 1.47 yamt bl _C_LABEL(lwp_startup)
389 1.38 scw
390 1.1 chris mov r0, r5
391 1.1 chris mov r1, sp
392 1.24 bjh21 mov lr, pc
393 1.1 chris mov pc, r4
394 1.1 chris
395 1.1 chris /* Kill irq's */
396 1.13 thorpej mrs r0, cpsr
397 1.1 chris orr r0, r0, #(I32_bit)
398 1.13 thorpej msr cpsr_c, r0
399 1.1 chris
400 1.1 chris PULLFRAME
401 1.1 chris
402 1.1 chris movs pc, lr /* Exit */
403