cpuswitch.S revision 1.26 1 1.26 bjh21 /* $NetBSD: cpuswitch.S,v 1.26 2002/10/18 21:32:57 bjh21 Exp $ */
2 1.1 chris
3 1.1 chris /*
4 1.1 chris * Copyright (c) 1994-1998 Mark Brinicombe.
5 1.1 chris * Copyright (c) 1994 Brini.
6 1.1 chris * All rights reserved.
7 1.1 chris *
8 1.1 chris * This code is derived from software written for Brini by Mark Brinicombe
9 1.1 chris *
10 1.1 chris * Redistribution and use in source and binary forms, with or without
11 1.1 chris * modification, are permitted provided that the following conditions
12 1.1 chris * are met:
13 1.1 chris * 1. Redistributions of source code must retain the above copyright
14 1.1 chris * notice, this list of conditions and the following disclaimer.
15 1.1 chris * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 chris * notice, this list of conditions and the following disclaimer in the
17 1.1 chris * documentation and/or other materials provided with the distribution.
18 1.1 chris * 3. All advertising materials mentioning features or use of this software
19 1.1 chris * must display the following acknowledgement:
20 1.1 chris * This product includes software developed by Brini.
21 1.1 chris * 4. The name of the company nor the name of the author may be used to
22 1.1 chris * endorse or promote products derived from this software without specific
23 1.1 chris * prior written permission.
24 1.1 chris *
25 1.1 chris * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 1.1 chris * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 1.1 chris * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 1.1 chris * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 1.1 chris * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 1.1 chris * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 1.1 chris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 1.1 chris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 1.1 chris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 1.1 chris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 1.1 chris * SUCH DAMAGE.
36 1.1 chris *
37 1.1 chris * RiscBSD kernel project
38 1.1 chris *
39 1.1 chris * cpuswitch.S
40 1.1 chris *
41 1.1 chris * cpu switching functions
42 1.1 chris *
43 1.1 chris * Created : 15/10/94
44 1.1 chris */
45 1.1 chris
46 1.1 chris #include "opt_armfpe.h"
47 1.19 bjh21 #include "opt_multiprocessor.h"
48 1.1 chris
49 1.1 chris #include "assym.h"
50 1.1 chris #include <machine/param.h>
51 1.1 chris #include <machine/cpu.h>
52 1.1 chris #include <machine/frame.h>
53 1.1 chris #include <machine/asm.h>
54 1.1 chris
55 1.1 chris #undef IRQdisable
56 1.1 chris #undef IRQenable
57 1.1 chris
58 1.1 chris /*
59 1.1 chris * New experimental definitions of IRQdisable and IRQenable
60 1.1 chris * These keep FIQ's enabled since FIQ's are special.
61 1.1 chris */
62 1.1 chris
63 1.1 chris #define IRQdisable \
64 1.13 thorpej mrs r14, cpsr ; \
65 1.1 chris orr r14, r14, #(I32_bit) ; \
66 1.13 thorpej msr cpsr_c, r14 ; \
67 1.1 chris
68 1.1 chris #define IRQenable \
69 1.13 thorpej mrs r14, cpsr ; \
70 1.1 chris bic r14, r14, #(I32_bit) ; \
71 1.13 thorpej msr cpsr_c, r14 ; \
72 1.1 chris
73 1.1 chris .text
74 1.1 chris
75 1.17 thorpej .Lwhichqs:
76 1.1 chris .word _C_LABEL(sched_whichqs)
77 1.1 chris
78 1.17 thorpej .Lqs:
79 1.1 chris .word _C_LABEL(sched_qs)
80 1.1 chris
81 1.1 chris /*
82 1.1 chris * cpuswitch()
83 1.1 chris *
84 1.1 chris * preforms a process context switch.
85 1.1 chris * This function has several entry points
86 1.1 chris */
87 1.1 chris
88 1.19 bjh21 #ifdef MULTIPROCESSOR
89 1.19 bjh21 .Lcpu_info_store:
90 1.19 bjh21 .word _C_LABEL(cpu_info_store)
91 1.19 bjh21 .Lcurproc:
92 1.19 bjh21 /* FIXME: This is bogus in the general case. */
93 1.19 bjh21 .word _C_LABEL(cpu_info_store) + CI_CURPROC
94 1.22 bjh21
95 1.22 bjh21 .Lcurpcb:
96 1.22 bjh21 .word _C_LABEL(cpu_info_store) + CI_CURPCB
97 1.19 bjh21 #else
98 1.17 thorpej .Lcurproc:
99 1.1 chris .word _C_LABEL(curproc)
100 1.1 chris
101 1.17 thorpej .Lcurpcb:
102 1.1 chris .word _C_LABEL(curpcb)
103 1.22 bjh21 #endif
104 1.1 chris
105 1.17 thorpej .Lwant_resched:
106 1.1 chris .word _C_LABEL(want_resched)
107 1.1 chris
108 1.17 thorpej .Lcpufuncs:
109 1.1 chris .word _C_LABEL(cpufuncs)
110 1.1 chris
111 1.22 bjh21 #ifndef MULTIPROCESSOR
112 1.1 chris .data
113 1.1 chris .global _C_LABEL(curpcb)
114 1.1 chris _C_LABEL(curpcb):
115 1.1 chris .word 0x00000000
116 1.1 chris .text
117 1.22 bjh21 #endif
118 1.1 chris
119 1.17 thorpej .Lblock_userspace_access:
120 1.1 chris .word _C_LABEL(block_userspace_access)
121 1.1 chris
122 1.15 thorpej .Lcpu_do_powersave:
123 1.15 thorpej .word _C_LABEL(cpu_do_powersave)
124 1.15 thorpej
125 1.1 chris /*
126 1.1 chris * Idle loop, exercised while waiting for a process to wake up.
127 1.16 thorpej *
128 1.16 thorpej * NOTE: When we jump back to .Lswitch_search, we must have a
129 1.16 thorpej * pointer to whichqs in r7, which is what it is when we arrive
130 1.16 thorpej * here.
131 1.1 chris */
132 1.7 chris /* LINTSTUB: Ignore */
133 1.4 chris ASENTRY_NP(idle)
134 1.19 bjh21 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
135 1.7 chris bl _C_LABEL(sched_unlock_idle)
136 1.7 chris #endif
137 1.16 thorpej ldr r3, .Lcpu_do_powersave
138 1.16 thorpej
139 1.1 chris /* Enable interrupts */
140 1.1 chris IRQenable
141 1.1 chris
142 1.15 thorpej /* If we don't want to sleep, use a simpler loop. */
143 1.16 thorpej ldr r3, [r3] /* r3 = cpu_do_powersave */
144 1.15 thorpej teq r3, #0
145 1.16 thorpej bne 2f
146 1.16 thorpej
147 1.16 thorpej /* Non-powersave idle. */
148 1.16 thorpej 1: /* should maybe do uvm pageidlezero stuff here */
149 1.16 thorpej ldr r3, [r7] /* r3 = whichqs */
150 1.16 thorpej teq r3, #0x00000000
151 1.16 thorpej bne .Lswitch_search
152 1.16 thorpej b 1b
153 1.15 thorpej
154 1.16 thorpej 2: /* Powersave idle. */
155 1.17 thorpej ldr r4, .Lcpufuncs
156 1.16 thorpej 3: ldr r3, [r7] /* r3 = whichqs */
157 1.15 thorpej teq r3, #0x00000000
158 1.15 thorpej bne .Lswitch_search
159 1.15 thorpej
160 1.15 thorpej /* if saving power, don't want to pageidlezero */
161 1.1 chris mov r0, #0
162 1.21 bjh21 adr lr, 3b
163 1.15 thorpej ldr pc, [r4, #(CF_SLEEP)]
164 1.15 thorpej /* loops back around */
165 1.15 thorpej
166 1.1 chris
167 1.1 chris /*
168 1.1 chris * Find a new process to run, save the current context and
169 1.1 chris * load the new context
170 1.1 chris */
171 1.1 chris
172 1.1 chris ENTRY(cpu_switch)
173 1.1 chris /*
174 1.1 chris * Local register usage. Some of these registers are out of date.
175 1.1 chris * r1 = oldproc
176 1.1 chris * r3 = whichqs
177 1.1 chris * r4 = queue
178 1.1 chris * r5 = &qs[queue]
179 1.1 chris * r6 = newproc
180 1.1 chris * r7 = scratch
181 1.1 chris */
182 1.26 bjh21 mov ip, sp
183 1.26 bjh21 stmfd sp!, {r4-r10, fp, ip, lr, pc}
184 1.26 bjh21 sub fp, ip, #4
185 1.1 chris
186 1.1 chris /*
187 1.1 chris * Get the current process and indicate that there is no longer
188 1.11 thorpej * a valid process (curproc = 0). Zero the current PCB pointer
189 1.11 thorpej * while we're at it.
190 1.1 chris */
191 1.17 thorpej ldr r7, .Lcurproc
192 1.17 thorpej ldr r6, .Lcurpcb
193 1.1 chris mov r0, #0x00000000
194 1.11 thorpej ldr r1, [r7] /* r1 = curproc */
195 1.11 thorpej str r0, [r7] /* curproc = NULL */
196 1.11 thorpej str r0, [r6] /* curpcb = NULL */
197 1.1 chris
198 1.10 thorpej /* stash the old proc while we call functions */
199 1.10 thorpej mov r5, r1
200 1.1 chris
201 1.19 bjh21 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
202 1.7 chris /* release the sched_lock before handling interrupts */
203 1.7 chris bl _C_LABEL(sched_unlock_idle)
204 1.7 chris #endif
205 1.7 chris
206 1.7 chris /* Lower the spl level to spl0 and get the current spl level. */
207 1.5 thorpej #ifdef __NEWINTR
208 1.5 thorpej mov r0, #(IPL_NONE)
209 1.5 thorpej bl _C_LABEL(_spllower)
210 1.5 thorpej #else /* ! __NEWINTR */
211 1.1 chris #ifdef spl0
212 1.1 chris mov r0, #(_SPL_0)
213 1.1 chris bl _C_LABEL(splx)
214 1.1 chris #else
215 1.1 chris bl _C_LABEL(spl0)
216 1.5 thorpej #endif /* spl0 */
217 1.5 thorpej #endif /* __NEWINTR */
218 1.1 chris
219 1.1 chris /* Push the old spl level onto the stack */
220 1.1 chris str r0, [sp, #-0x0004]!
221 1.1 chris
222 1.1 chris /* First phase : find a new process */
223 1.1 chris
224 1.17 thorpej ldr r7, .Lwhichqs
225 1.16 thorpej
226 1.7 chris /* rem: r5 = old proc */
227 1.16 thorpej /* rem: r7 = &whichqs */
228 1.7 chris
229 1.14 briggs .Lswitch_search:
230 1.1 chris IRQdisable
231 1.19 bjh21 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
232 1.7 chris bl _C_LABEL(sched_lock_idle)
233 1.7 chris #endif
234 1.7 chris
235 1.1 chris /* Do we have any active queues */
236 1.1 chris ldr r3, [r7]
237 1.1 chris
238 1.1 chris /* If not we must idle until we do. */
239 1.1 chris teq r3, #0x00000000
240 1.4 chris beq _ASM_LABEL(idle)
241 1.7 chris
242 1.10 thorpej /* put old proc back in r1 */
243 1.7 chris mov r1, r5
244 1.1 chris
245 1.1 chris /* rem: r1 = old proc */
246 1.1 chris /* rem: r3 = whichqs */
247 1.1 chris /* rem: interrupts are disabled */
248 1.1 chris
249 1.1 chris /*
250 1.1 chris * We have found an active queue. Currently we do not know which queue
251 1.1 chris * is active just that one of them is.
252 1.1 chris */
253 1.1 chris /* this is the ffs algorithm devised by d.seal and posted to
254 1.1 chris * comp.sys.arm on 16 Feb 1994.
255 1.1 chris */
256 1.1 chris rsb r5, r3, #0
257 1.1 chris ands r0, r3, r5
258 1.1 chris
259 1.17 thorpej adr r5, .Lcpu_switch_ffs_table
260 1.1 chris
261 1.3 chris /* X = R0 */
262 1.3 chris orr r4, r0, r0, lsl #4 /* r4 = X * 0x11 */
263 1.3 chris orr r4, r4, r4, lsl #6 /* r4 = X * 0x451 */
264 1.3 chris rsb r4, r4, r4, lsl #16 /* r4 = X * 0x0450fbaf */
265 1.1 chris
266 1.1 chris /* used further down, saves SA stall */
267 1.17 thorpej ldr r6, .Lqs
268 1.1 chris
269 1.3 chris /* now lookup in table indexed on top 6 bits of a4 */
270 1.1 chris ldrb r4, [ r5, r4, lsr #26 ]
271 1.1 chris
272 1.1 chris /* rem: r0 = bit mask of chosen queue (1 << r4) */
273 1.1 chris /* rem: r1 = old proc */
274 1.1 chris /* rem: r3 = whichqs */
275 1.1 chris /* rem: r4 = queue number */
276 1.1 chris /* rem: interrupts are disabled */
277 1.1 chris
278 1.1 chris /* Get the address of the queue (&qs[queue]) */
279 1.1 chris add r5, r6, r4, lsl #3
280 1.1 chris
281 1.1 chris /*
282 1.1 chris * Get the process from the queue and place the next process in
283 1.1 chris * the queue at the head. This basically unlinks the process at
284 1.1 chris * the head of the queue.
285 1.1 chris */
286 1.1 chris ldr r6, [r5, #(P_FORW)]
287 1.1 chris
288 1.1 chris /* rem: r6 = new process */
289 1.1 chris ldr r7, [r6, #(P_FORW)]
290 1.1 chris str r7, [r5, #(P_FORW)]
291 1.1 chris
292 1.1 chris /*
293 1.1 chris * Test to see if the queue is now empty. If the head of the queue
294 1.1 chris * points to the queue itself then there are no more processes in
295 1.1 chris * the queue. We can therefore clear the queue not empty flag held
296 1.1 chris * in r3.
297 1.1 chris */
298 1.1 chris
299 1.1 chris teq r5, r7
300 1.1 chris biceq r3, r3, r0
301 1.1 chris
302 1.1 chris /* rem: r0 = bit mask of chosen queue (1 << r4) - NOT NEEDED AN MORE */
303 1.1 chris
304 1.1 chris /* Fix the back pointer for the process now at the head of the queue. */
305 1.1 chris ldr r0, [r6, #(P_BACK)]
306 1.1 chris str r0, [r7, #(P_BACK)]
307 1.1 chris
308 1.1 chris /* Update the RAM copy of the queue not empty flags word. */
309 1.17 thorpej ldr r7, .Lwhichqs
310 1.1 chris str r3, [r7]
311 1.1 chris
312 1.1 chris /* rem: r1 = old proc */
313 1.1 chris /* rem: r3 = whichqs - NOT NEEDED ANY MORE */
314 1.1 chris /* rem: r4 = queue number - NOT NEEDED ANY MORE */
315 1.1 chris /* rem: r6 = new process */
316 1.1 chris /* rem: interrupts are disabled */
317 1.1 chris
318 1.1 chris /* Clear the want_resched flag */
319 1.17 thorpej ldr r7, .Lwant_resched
320 1.1 chris mov r0, #0x00000000
321 1.1 chris str r0, [r7]
322 1.1 chris
323 1.1 chris /*
324 1.1 chris * Clear the back pointer of the process we have removed from
325 1.1 chris * the head of the queue. The new process is isolated now.
326 1.1 chris */
327 1.1 chris str r0, [r6, #(P_BACK)]
328 1.1 chris
329 1.19 bjh21 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
330 1.7 chris /*
331 1.7 chris * unlock the sched_lock, but leave interrupts off, for now.
332 1.7 chris */
333 1.7 chris mov r7, r1
334 1.7 chris bl _C_LABEL(sched_unlock_idle)
335 1.7 chris mov r1, r7
336 1.7 chris #endif
337 1.7 chris
338 1.19 bjh21 #ifdef MULTIPROCESSOR
339 1.19 bjh21 /* XXX use curcpu() */
340 1.19 bjh21 ldr r0, .Lcpu_info_store
341 1.19 bjh21 str r0, [r6, #(P_CPU)]
342 1.19 bjh21 #else
343 1.1 chris /* p->p_cpu initialized in fork1() for single-processor */
344 1.19 bjh21 #endif
345 1.1 chris
346 1.1 chris /* Process is now on a processor. */
347 1.1 chris mov r0, #SONPROC /* p->p_stat = SONPROC */
348 1.1 chris strb r0, [r6, #(P_STAT)]
349 1.1 chris
350 1.1 chris /* We have a new curproc now so make a note it */
351 1.17 thorpej ldr r7, .Lcurproc
352 1.1 chris str r6, [r7]
353 1.1 chris
354 1.1 chris /* Hook in a new pcb */
355 1.17 thorpej ldr r7, .Lcurpcb
356 1.1 chris ldr r0, [r6, #(P_ADDR)]
357 1.1 chris str r0, [r7]
358 1.1 chris
359 1.1 chris /* At this point we can allow IRQ's again. */
360 1.1 chris IRQenable
361 1.1 chris
362 1.1 chris /* rem: r1 = old proc */
363 1.1 chris /* rem: r6 = new process */
364 1.4 chris /* rem: interrupts are enabled */
365 1.1 chris
366 1.1 chris /*
367 1.1 chris * If the new process is the same as the process that called
368 1.1 chris * cpu_switch() then we do not need to save and restore any
369 1.1 chris * contexts. This means we can make a quick exit.
370 1.1 chris * The test is simple if curproc on entry (now in r1) is the
371 1.1 chris * same as the proc removed from the queue we can jump to the exit.
372 1.1 chris */
373 1.1 chris teq r1, r6
374 1.14 briggs beq .Lswitch_return
375 1.1 chris
376 1.9 thorpej /* Remember the old process in r0 */
377 1.9 thorpej mov r0, r1
378 1.9 thorpej
379 1.1 chris /*
380 1.1 chris * If the curproc on entry to cpu_switch was zero then the
381 1.1 chris * process that called it was exiting. This means that we do
382 1.1 chris * not need to save the current context. Instead we can jump
383 1.1 chris * straight to restoring the context for the new process.
384 1.1 chris */
385 1.9 thorpej teq r0, #0x00000000
386 1.14 briggs beq .Lswitch_exited
387 1.1 chris
388 1.9 thorpej /* rem: r0 = old proc */
389 1.1 chris /* rem: r6 = new process */
390 1.4 chris /* rem: interrupts are enabled */
391 1.1 chris
392 1.1 chris /* Stage two : Save old context */
393 1.1 chris
394 1.1 chris /* Get the user structure for the old process. */
395 1.9 thorpej ldr r1, [r0, #(P_ADDR)]
396 1.1 chris
397 1.26 bjh21 /* Save the remaining registers in the old process's pcb */
398 1.26 bjh21 add r7, r1, #(PCB_R11)
399 1.26 bjh21 stmia r7, {r11-r13}
400 1.1 chris
401 1.1 chris /*
402 1.1 chris * This can be optimised... We know we want to go from SVC32
403 1.1 chris * mode to UND32 mode
404 1.1 chris */
405 1.13 thorpej mrs r3, cpsr
406 1.1 chris bic r2, r3, #(PSR_MODE)
407 1.1 chris orr r2, r2, #(PSR_UND32_MODE | I32_bit)
408 1.13 thorpej msr cpsr_c, r2
409 1.1 chris
410 1.1 chris str sp, [r1, #(PCB_UND_SP)]
411 1.1 chris
412 1.13 thorpej msr cpsr_c, r3 /* Restore the old mode */
413 1.1 chris
414 1.1 chris /* rem: r0 = old proc */
415 1.4 chris /* rem: r1 = old pcb */
416 1.1 chris /* rem: r6 = new process */
417 1.4 chris /* rem: interrupts are enabled */
418 1.1 chris
419 1.1 chris /* What else needs to be saved Only FPA stuff when that is supported */
420 1.1 chris
421 1.9 thorpej /* r1 now free! */
422 1.9 thorpej
423 1.1 chris /* Third phase : restore saved context */
424 1.1 chris
425 1.9 thorpej /* rem: r0 = old proc */
426 1.9 thorpej /* rem: r6 = new process */
427 1.9 thorpej /* rem: interrupts are enabled */
428 1.9 thorpej
429 1.9 thorpej /*
430 1.9 thorpej * Don't allow user space access between the purge and the switch.
431 1.9 thorpej */
432 1.17 thorpej ldr r3, .Lblock_userspace_access
433 1.9 thorpej mov r1, #0x00000001
434 1.9 thorpej mov r2, #0x00000000
435 1.9 thorpej str r1, [r3]
436 1.1 chris
437 1.1 chris stmfd sp!, {r0-r3}
438 1.17 thorpej ldr r1, .Lcpufuncs
439 1.23 bjh21 mov lr, pc
440 1.9 thorpej ldr pc, [r1, #CF_IDCACHE_WBINV_ALL]
441 1.1 chris ldmfd sp!, {r0-r3}
442 1.1 chris
443 1.14 briggs .Lcs_cache_purge_skipped:
444 1.1 chris /* At this point we need to kill IRQ's again. */
445 1.1 chris IRQdisable
446 1.1 chris
447 1.9 thorpej /*
448 1.9 thorpej * Interrupts are disabled so we can allow user space accesses again
449 1.1 chris * as none will occur until interrupts are re-enabled after the
450 1.1 chris * switch.
451 1.1 chris */
452 1.1 chris str r2, [r3]
453 1.1 chris
454 1.1 chris /* Get the user structure for the new process in r1 */
455 1.1 chris ldr r1, [r6, #(P_ADDR)]
456 1.1 chris
457 1.1 chris /* Get the pagedir physical address for the process. */
458 1.1 chris ldr r0, [r1, #(PCB_PAGEDIR)]
459 1.1 chris
460 1.1 chris /* Switch the memory to the new process */
461 1.17 thorpej ldr r3, .Lcpufuncs
462 1.23 bjh21 mov lr, pc
463 1.1 chris ldr pc, [r3, #CF_CONTEXT_SWITCH]
464 1.1 chris
465 1.1 chris /*
466 1.1 chris * This can be optimised... We know we want to go from SVC32
467 1.1 chris * mode to UND32 mode
468 1.1 chris */
469 1.13 thorpej mrs r3, cpsr
470 1.1 chris bic r2, r3, #(PSR_MODE)
471 1.1 chris orr r2, r2, #(PSR_UND32_MODE)
472 1.13 thorpej msr cpsr_c, r2
473 1.1 chris
474 1.1 chris ldr sp, [r1, #(PCB_UND_SP)]
475 1.1 chris
476 1.13 thorpej msr cpsr_c, r3 /* Restore the old mode */
477 1.1 chris
478 1.26 bjh21 /* Restore the saved registers from the PCB */
479 1.26 bjh21 add r7, r1, #PCB_R11
480 1.26 bjh21 ldmia r7, {r11-r13}
481 1.1 chris
482 1.18 thorpej mov r7, r1 /* preserve PCB pointer */
483 1.18 thorpej
484 1.1 chris #ifdef ARMFPE
485 1.1 chris add r0, r1, #(USER_SIZE) & 0x00ff
486 1.1 chris add r0, r0, #(USER_SIZE) & 0xff00
487 1.1 chris bl _C_LABEL(arm_fpe_core_changecontext)
488 1.1 chris #endif
489 1.1 chris
490 1.1 chris /* We can enable interrupts again */
491 1.1 chris IRQenable
492 1.1 chris
493 1.18 thorpej /* rem: r6 = new proc */
494 1.18 thorpej /* rem: r7 = new PCB */
495 1.18 thorpej
496 1.18 thorpej /*
497 1.18 thorpej * Check for restartable atomic sequences (RAS).
498 1.18 thorpej */
499 1.18 thorpej
500 1.18 thorpej ldr r2, [r6, #(P_NRAS)]
501 1.18 thorpej ldr r4, [r7, #(PCB_TF)] /* r4 = trapframe (used below) */
502 1.18 thorpej teq r2, #0 /* p->p_nras == 0? */
503 1.18 thorpej bne .Lswitch_do_ras /* no, check for one */
504 1.18 thorpej
505 1.14 briggs .Lswitch_return:
506 1.1 chris
507 1.1 chris /* Get the spl level from the stack and update the current spl level */
508 1.1 chris ldr r0, [sp], #0x0004
509 1.1 chris bl _C_LABEL(splx)
510 1.1 chris
511 1.1 chris /* cpu_switch returns the proc it switched to. */
512 1.1 chris mov r0, r6
513 1.1 chris
514 1.1 chris /*
515 1.1 chris * Pull the registers that got pushed when either savectx() or
516 1.1 chris * cpu_switch() was called and return.
517 1.1 chris */
518 1.26 bjh21 ldmdb fp, {r4-r10, fp, sp, pc}
519 1.18 thorpej
520 1.18 thorpej .Lswitch_do_ras:
521 1.18 thorpej ldr r1, [r4, #(TF_PC)] /* second ras_lookup() arg */
522 1.18 thorpej mov r0, r6 /* first ras_lookup() arg */
523 1.18 thorpej bl _C_LABEL(ras_lookup)
524 1.18 thorpej cmn r0, #1 /* -1 means "not in a RAS" */
525 1.18 thorpej strne r0, [r4, #(TF_PC)]
526 1.18 thorpej b .Lswitch_return
527 1.1 chris
528 1.14 briggs .Lswitch_exited:
529 1.9 thorpej /*
530 1.9 thorpej * We skip the cache purge because switch_exit() already did
531 1.9 thorpej * it. Load up registers the way Lcs_cache_purge_skipped
532 1.9 thorpej * expects. Userspace access already blocked in switch_exit().
533 1.9 thorpej */
534 1.17 thorpej ldr r3, .Lblock_userspace_access
535 1.9 thorpej mov r2, #0x00000000
536 1.14 briggs b .Lcs_cache_purge_skipped
537 1.9 thorpej
538 1.7 chris /*
539 1.8 thorpej * void switch_exit(struct proc *p, struct proc *p0);
540 1.7 chris * Switch to proc0's saved context and deallocate the address space and kernel
541 1.7 chris * stack for p. Then jump into cpu_switch(), as if we were in proc0 all along.
542 1.7 chris */
543 1.1 chris
544 1.8 thorpej /* LINTSTUB: Func: void switch_exit(struct proc *p, struct proc *p0) */
545 1.1 chris ENTRY(switch_exit)
546 1.1 chris /*
547 1.1 chris * r0 = proc
548 1.1 chris * r1 = proc0
549 1.1 chris */
550 1.1 chris
551 1.1 chris mov r3, r0
552 1.1 chris
553 1.1 chris /* In case we fault */
554 1.17 thorpej ldr r0, .Lcurproc
555 1.1 chris mov r2, #0x00000000
556 1.1 chris str r2, [r0]
557 1.1 chris
558 1.17 thorpej /* ldr r0, .Lcurpcb
559 1.1 chris str r2, [r0]*/
560 1.9 thorpej
561 1.9 thorpej /*
562 1.9 thorpej * Don't allow user space access between the purge and the switch.
563 1.9 thorpej */
564 1.17 thorpej ldr r0, .Lblock_userspace_access
565 1.9 thorpej mov r2, #0x00000001
566 1.9 thorpej str r2, [r0]
567 1.1 chris
568 1.1 chris /* Switch to proc0 context */
569 1.1 chris
570 1.1 chris stmfd sp!, {r0-r3}
571 1.1 chris
572 1.17 thorpej ldr r0, .Lcpufuncs
573 1.23 bjh21 mov lr, pc
574 1.6 thorpej ldr pc, [r0, #CF_IDCACHE_WBINV_ALL]
575 1.1 chris
576 1.1 chris ldmfd sp!, {r0-r3}
577 1.1 chris
578 1.1 chris IRQdisable
579 1.1 chris
580 1.1 chris ldr r2, [r1, #(P_ADDR)]
581 1.1 chris ldr r0, [r2, #(PCB_PAGEDIR)]
582 1.1 chris
583 1.1 chris /* Switch the memory to the new process */
584 1.17 thorpej ldr r4, .Lcpufuncs
585 1.23 bjh21 mov lr, pc
586 1.1 chris ldr pc, [r4, #CF_CONTEXT_SWITCH]
587 1.1 chris
588 1.1 chris /* Restore all the save registers */
589 1.26 bjh21 add r7, r2, #PCB_R11
590 1.26 bjh21 ldmia r7, {r11-r13}
591 1.1 chris
592 1.1 chris /* This is not really needed ! */
593 1.1 chris /* Yes it is for the su and fu routines */
594 1.17 thorpej ldr r0, .Lcurpcb
595 1.1 chris str r2, [r0]
596 1.1 chris
597 1.1 chris IRQenable
598 1.1 chris
599 1.1 chris /* str r3, [sp, #-0x0004]!*/
600 1.1 chris
601 1.1 chris /*
602 1.1 chris * Schedule the vmspace and stack to be freed.
603 1.1 chris */
604 1.1 chris mov r0, r3 /* exit2(p) */
605 1.1 chris bl _C_LABEL(exit2)
606 1.1 chris
607 1.1 chris /* Paranoia */
608 1.17 thorpej ldr r1, .Lcurproc
609 1.1 chris mov r0, #0x00000000
610 1.1 chris str r0, [r1]
611 1.1 chris
612 1.17 thorpej ldr r7, .Lwhichqs /* r7 = &whichqs */
613 1.8 thorpej mov r5, #0x00000000 /* r5 = old proc = NULL */
614 1.14 briggs b .Lswitch_search
615 1.1 chris
616 1.7 chris /* LINTSTUB: Func: void savectx(struct pcb *pcb) */
617 1.1 chris ENTRY(savectx)
618 1.1 chris /*
619 1.1 chris * r0 = pcb
620 1.1 chris */
621 1.1 chris
622 1.1 chris /* Push registers.*/
623 1.26 bjh21 mov ip, sp
624 1.26 bjh21 stmfd sp!, {r4-r10, fp, ip, lr, pc}
625 1.26 bjh21 sub fp, ip, #4
626 1.1 chris
627 1.1 chris /* Store all the registers in the process's pcb */
628 1.26 bjh21 add r2, r0, #(PCB_R11)
629 1.26 bjh21 stmia r2, {r11-r13}
630 1.1 chris
631 1.1 chris /* Pull the regs of the stack */
632 1.26 bjh21 ldmdb fp, {r4-r10, fp, sp, pc}
633 1.1 chris
634 1.1 chris ENTRY(proc_trampoline)
635 1.19 bjh21 #ifdef MULTIPROCESSOR
636 1.19 bjh21 bl _C_LABEL(proc_trampoline_mp)
637 1.19 bjh21 #endif
638 1.1 chris mov r0, r5
639 1.1 chris mov r1, sp
640 1.24 bjh21 mov lr, pc
641 1.1 chris mov pc, r4
642 1.1 chris
643 1.1 chris /* Kill irq's */
644 1.13 thorpej mrs r0, cpsr
645 1.1 chris orr r0, r0, #(I32_bit)
646 1.13 thorpej msr cpsr_c, r0
647 1.1 chris
648 1.1 chris PULLFRAME
649 1.1 chris
650 1.1 chris movs pc, lr /* Exit */
651 1.1 chris
652 1.17 thorpej .type .Lcpu_switch_ffs_table, _ASM_TYPE_OBJECT;
653 1.17 thorpej .Lcpu_switch_ffs_table:
654 1.1 chris /* same as ffs table but all nums are -1 from that */
655 1.1 chris /* 0 1 2 3 4 5 6 7 */
656 1.1 chris .byte 0, 0, 1, 12, 2, 6, 0, 13 /* 0- 7 */
657 1.1 chris .byte 3, 0, 7, 0, 0, 0, 0, 14 /* 8-15 */
658 1.1 chris .byte 10, 4, 0, 0, 8, 0, 0, 25 /* 16-23 */
659 1.1 chris .byte 0, 0, 0, 0, 0, 21, 27, 15 /* 24-31 */
660 1.1 chris .byte 31, 11, 5, 0, 0, 0, 0, 0 /* 32-39 */
661 1.1 chris .byte 9, 0, 0, 24, 0, 0, 20, 26 /* 40-47 */
662 1.1 chris .byte 30, 0, 0, 0, 0, 23, 0, 19 /* 48-55 */
663 1.1 chris .byte 29, 0, 22, 18, 28, 17, 16, 0 /* 56-63 */
664 1.1 chris
665 1.1 chris /* End of cpuswitch.S */
666