cpuswitch.S revision 1.3.2.9 1 /* $NetBSD: cpuswitch.S,v 1.3.2.9 2002/06/24 22:03:50 nathanw Exp $ */
2
3 /*
4 * Copyright (c) 1994-1998 Mark Brinicombe.
5 * Copyright (c) 1994 Brini.
6 * All rights reserved.
7 *
8 * This code is derived from software written for Brini by Mark Brinicombe
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Brini.
21 * 4. The name of the company nor the name of the author may be used to
22 * endorse or promote products derived from this software without specific
23 * prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * RiscBSD kernel project
38 *
39 * cpuswitch.S
40 *
41 * cpu switching functions
42 *
43 * Created : 15/10/94
44 */
45
46 #include "opt_armfpe.h"
47
48 #include "assym.h"
49 #include <machine/param.h>
50 #include <machine/cpu.h>
51 #include <machine/frame.h>
52 #include <machine/asm.h>
53
54 #undef IRQdisable
55 #undef IRQenable
56
57 /*
58 * New experimental definitions of IRQdisable and IRQenable
59 * These keep FIQ's enabled since FIQ's are special.
60 */
61
62 #define IRQdisable \
63 mrs r14, cpsr_all ; \
64 orr r14, r14, #(I32_bit) ; \
65 msr cpsr_all, r14 ; \
66
67 #define IRQenable \
68 mrs r14, cpsr_all ; \
69 bic r14, r14, #(I32_bit) ; \
70 msr cpsr_all, r14 ; \
71
72 /*
73 * setrunqueue() and remrunqueue()
74 *
75 * Functions to add and remove a process for the run queue.
76 */
77
78 .text
79
80 Lwhichqs:
81 .word _C_LABEL(sched_whichqs)
82
83 Lqs:
84 .word _C_LABEL(sched_qs)
85
86 /*
87 * On entry
88 * r0 = lwp
89 */
90
91 ENTRY(setrunqueue)
92 /*
93 * Local register usage
94 * r0 = process
95 * r1 = queue
96 * r2 = &qs[queue] and temp
97 * r3 = temp
98 * r12 = whichqs
99 */
100 #ifdef DIAGNOSTIC
101 ldr r1, [r0, #(L_BACK)]
102 teq r1, #0x00000000
103 bne Lsetrunqueue_erg
104
105 ldr r1, [r0, #(L_WCHAN)]
106 teq r1, #0x00000000
107 bne Lsetrunqueue_erg
108 #endif
109
110 /* Get the priority of the queue */
111 ldrb r1, [r0, #(L_PRIORITY)]
112 mov r1, r1, lsr #2
113
114 /* Indicate that there is a process on this queue */
115 ldr r12, Lwhichqs
116 ldr r2, [r12]
117 mov r3, #0x00000001
118 mov r3, r3, lsl r1
119 orr r2, r2, r3
120 str r2, [r12]
121
122 /* Get the address of the queue */
123 ldr r2, Lqs
124 add r1, r2, r1, lsl # 3
125
126 /* Hook the process in */
127 str r1, [r0, #(L_FORW)]
128 ldr r2, [r1, #(L_BACK)]
129
130 str r0, [r1, #(L_BACK)]
131 #ifdef DIAGNOSTIC
132 teq r2, #0x00000000
133 beq Lsetrunqueue_erg
134 #endif
135 str r0, [r2, #(L_FORW)]
136 str r2, [r0, #(L_BACK)]
137
138 mov pc, lr
139
140 #ifdef DIAGNOSTIC
141 Lsetrunqueue_erg:
142 mov r2, r1
143 mov r1, r0
144 add r0, pc, #Ltext1 - . - 8
145 bl _C_LABEL(printf)
146
147 ldr r2, Lqs
148 ldr r1, [r2]
149 add r0, pc, #Ltext2 - . - 8
150 b _C_LABEL(panic)
151
152 Ltext1:
153 .asciz "setrunqueue : %08x %08x\n"
154 Ltext2:
155 .asciz "setrunqueue : [qs]=%08x qs=%08x\n"
156 .align 0
157 #endif
158
159 /*
160 * On entry
161 * r0 = lwp
162 */
163
164 ENTRY(remrunqueue)
165 /*
166 * Local register usage
167 * r0 = oldproc
168 * r1 = queue
169 * r2 = &qs[queue] and scratch
170 * r3 = scratch
171 * r12 = whichqs
172 */
173
174 /* Get the priority of the queue */
175 ldrb r1, [r0, #(L_PRIORITY)]
176 mov r1, r1, lsr #2
177
178 /* Unhook the process */
179 ldr r2, [r0, #(L_FORW)]
180 ldr r3, [r0, #(L_BACK)]
181
182 str r3, [r2, #(L_BACK)]
183 str r2, [r3, #(L_FORW)]
184
185 /* If the queue is now empty clear the queue not empty flag */
186 teq r2, r3
187
188 /* This could be reworked to avoid the use of r4 */
189 ldreq r12, Lwhichqs
190 ldreq r2, [r12]
191 moveq r3, #0x00000001
192 moveq r3, r3, lsl r1
193 biceq r2, r2, r3
194 streq r2, [r12]
195
196 /* Remove the back pointer for the process */
197 mov r1, #0x00000000
198 str r1, [r0, #(L_BACK)]
199
200 mov pc, lr
201
202
203 /*
204 * cpuswitch()
205 *
206 * preforms a process context switch.
207 * This function has several entry points
208 */
209
210 Lcurlwp:
211 .word _C_LABEL(curlwp)
212
213 Lcurpcb:
214 .word _C_LABEL(curpcb)
215
216 Lwant_resched:
217 .word _C_LABEL(want_resched)
218
219 Lcpufuncs:
220 .word _C_LABEL(cpufuncs)
221
222 .data
223 .global _C_LABEL(curpcb)
224 _C_LABEL(curpcb):
225 .word 0x00000000
226 .text
227
228 Lblock_userspace_access:
229 .word _C_LABEL(block_userspace_access)
230
231 /*
232 * Idle loop, exercised while waiting for a process to wake up.
233 */
234 /* LINTSTUB: Ignore */
235 ASENTRY_NP(idle)
236
237 #if defined(LOCKDEBUG)
238 bl _C_LABEL(sched_unlock_idle)
239 #endif
240 /* Enable interrupts */
241 IRQenable
242
243 ldr r3, Lcpufuncs
244 mov r0, #0
245 add lr, pc, #Lidle_slept - . - 8
246 ldr pc, [r3, #CF_SLEEP]
247
248 /* should also call the uvm pageidlezero stuff */
249
250 Lidle_slept:
251
252 /* Disable interrupts while we check for an active queue */
253 IRQdisable
254 #if defined(LOCKDEBUG)
255 bl _C_LABEL(sched_lock_idle)
256 #endif
257 ldr r7, Lwhichqs
258 ldr r3, [r7]
259 teq r3, #0x00000000
260
261 beq _ASM_LABEL(idle)
262 b Lidle_ret
263
264 /*
265 * Find a new lwp to run, save the current context and
266 * load the new context
267 *
268 * Arguments:
269 * r0 'struct lwp *' of the current LWP
270 */
271
272 ENTRY(cpu_switch)
273 /*
274 * Local register usage. Some of these registers are out of date.
275 * r1 = oldlwp
276 * r2 = spl level
277 * r3 = whichqs
278 * r4 = queue
279 * r5 = &qs[queue]
280 * r6 = newlwp
281 * r7 = scratch
282 */
283 stmfd sp!, {r4-r7, lr}
284
285 /*
286 * Get the current lwp and indicate that there is no longer
287 * a valid process (curlwp = 0)
288 */
289 ldr r7, Lcurlwp
290 ldr r1, [r7]
291 mov r0, #0x00000000
292 str r0, [r7]
293
294 /* Zero the pcb */
295 ldr r7, Lcurpcb
296 str r0, [r7]
297
298 /* stash the old proc */
299 mov r7, r1
300
301 #if defined(LOCKDEBUG)
302 /* release the sched_lock before handling interrupts */
303 bl _C_LABEL(sched_unlock_idle)
304 #endif
305
306 /* Lower the spl level to spl0 and get the current spl level. */
307 #ifdef __NEWINTR
308 mov r0, #(IPL_NONE)
309 bl _C_LABEL(_spllower)
310 #else /* ! __NEWINTR */
311 #ifdef spl0
312 mov r0, #(_SPL_0)
313 bl _C_LABEL(splx)
314 #else
315 bl _C_LABEL(spl0)
316 #endif /* spl0 */
317 #endif /* __NEWINTR */
318
319 /* Push the old spl level onto the stack */
320 str r0, [sp, #-0x0004]!
321
322 mov r5, r7
323
324 /* First phase : find a new lwp */
325
326 /* rem: r5 = old lwp */
327
328
329 Lswitch_search:
330 IRQdisable
331 #if defined(LOCKDEBUG)
332 bl _C_LABEL(sched_lock_idle)
333 #endif
334
335
336 /* Do we have any active queues */
337 ldr r7, Lwhichqs
338 ldr r3, [r7]
339
340 /* If not we must idle until we do. */
341 teq r3, #0x00000000
342 beq _ASM_LABEL(idle)
343 Lidle_ret:
344
345 /* restore old proc */
346 mov r1, r5
347
348 /* rem: r1 = old lwp */
349 /* rem: r3 = whichqs */
350 /* rem: interrupts are disabled */
351
352 /*
353 * We have found an active queue. Currently we do not know which queue
354 * is active just that one of them is.
355 */
356 /* this is the ffs algorithm devised by d.seal and posted to
357 * comp.sys.arm on 16 Feb 1994.
358 */
359 rsb r5, r3, #0
360 ands r0, r3, r5
361
362 adr r5, Lcpu_switch_ffs_table
363
364 /* X = R0 */
365 orr r4, r0, r0, lsl #4 /* r4 = X * 0x11 */
366 orr r4, r4, r4, lsl #6 /* r4 = X * 0x451 */
367 rsb r4, r4, r4, lsl #16 /* r4 = X * 0x0450fbaf */
368
369 /* used further down, saves SA stall */
370 ldr r6, Lqs
371
372 /* now lookup in table indexed on top 6 bits of a4 */
373 ldrb r4, [ r5, r4, lsr #26 ]
374
375 /* rem: r0 = bit mask of chosen queue (1 << r4) */
376 /* rem: r1 = old lwp */
377 /* rem: r3 = whichqs */
378 /* rem: r4 = queue number */
379 /* rem: interrupts are disabled */
380
381 /* Get the address of the queue (&qs[queue]) */
382 add r5, r6, r4, lsl #3
383
384 /*
385 * Get the lwp from the queue and place the next process in
386 * the queue at the head. This basically unlinks the lwp at
387 * the head of the queue.
388 */
389 ldr r6, [r5, #(L_FORW)]
390
391 /* rem: r6 = new lwp */
392 ldr r7, [r6, #(L_FORW)]
393 str r7, [r5, #(L_FORW)]
394
395 /*
396 * Test to see if the queue is now empty. If the head of the queue
397 * points to the queue itself then there are no more lwps in
398 * the queue. We can therefore clear the queue not empty flag held
399 * in r3.
400 */
401
402 teq r5, r7
403 biceq r3, r3, r0
404
405 /* rem: r0 = bit mask of chosen queue (1 << r4) - NOT NEEDED AN MORE */
406
407 /* Fix the back pointer for the lwp now at the head of the queue. */
408 ldr r0, [r6, #(L_BACK)]
409 str r0, [r7, #(L_BACK)]
410
411 /* Update the RAM copy of the queue not empty flags word. */
412 ldr r7, Lwhichqs
413 str r3, [r7]
414
415 /* rem: r1 = old lwp */
416 /* rem: r3 = whichqs - NOT NEEDED ANY MORE */
417 /* rem: r4 = queue number - NOT NEEDED ANY MORE */
418 /* rem: r6 = new lwp */
419 /* rem: interrupts are disabled */
420
421 /* Clear the want_resched flag */
422 ldr r7, Lwant_resched
423 mov r0, #0x00000000
424 str r0, [r7]
425
426 /*
427 * Clear the back pointer of the lwp we have removed from
428 * the head of the queue. The new lwp is isolated now.
429 */
430 str r0, [r6, #(L_BACK)]
431
432 switch_resume:
433 #if defined(LOCKDEBUG)
434 /*
435 * unlock the sched_lock, but leave interrupts off, for now.
436 */
437 mov r7, r1
438 bl _C_LABEL(sched_unlock_idle)
439 mov r1, r7
440 #endif
441
442 /* l->l_cpu initialized in fork1() for single-processor */
443
444 /* Process is now on a processor. */
445 mov r0, #LSONPROC /* l->l_stat = LSONPROC */
446 str r0, [r6, #(L_STAT)]
447
448 /* We have a new curlwp now so make a note it */
449 ldr r7, Lcurlwp
450 str r6, [r7]
451
452 /* Hook in a new pcb */
453 ldr r7, Lcurpcb
454 ldr r0, [r6, #(L_ADDR)]
455 str r0, [r7]
456
457 /* At this point we can allow IRQ's again. */
458 IRQenable
459
460 /* rem: r1 = old lwp */
461 /* rem: r4 = return value */
462 /* rem: r6 = new process */
463 /* rem: interrupts are enabled */
464
465 /*
466 * If the new process is the same as the process that called
467 * cpu_switch() then we do not need to save and restore any
468 * contexts. This means we can make a quick exit.
469 * The test is simple if curlwp on entry (now in r1) is the
470 * same as the proc removed from the queue we can jump to the exit.
471 */
472 teq r1, r6
473 moveq r4, #0x00000000 /* default to "didn't switch" */
474 beq switch_return
475
476 /*
477 * At this point, we are guaranteed to be switching to
478 * a new lwp.
479 */
480 mov r4, #0x00000001
481
482 /*
483 * If the curlwp on entry to cpu_switch was zero then the
484 * process that called it was exiting. This means that we do
485 * not need to save the current context. Instead we can jump
486 * straight to restoring the context for the new process.
487 */
488 teq r1, #0x00000000
489 beq switch_exited
490
491 /* rem: r1 = old proc */
492 /* rem: r4 = return value */
493 /* rem: r6 = new process */
494 /* rem: interrupts are enabled */
495
496 /* Stage two : Save old context */
497
498 /* Remember the old process in r0 */
499 mov r0, r1
500
501 /* Get the user structure for the old process. */
502 ldr r1, [r1, #(L_ADDR)]
503
504 /* Save all the registers in the old process's pcb */
505 add r7, r1, #(PCB_R8)
506 stmia r7, {r8-r13}
507
508 /*
509 * This can be optimised... We know we want to go from SVC32
510 * mode to UND32 mode
511 */
512 mrs r3, cpsr_all
513 bic r2, r3, #(PSR_MODE)
514 orr r2, r2, #(PSR_UND32_MODE | I32_bit)
515 msr cpsr_all, r2
516
517 str sp, [r1, #(PCB_UND_SP)]
518
519 msr cpsr_all, r3 /* Restore the old mode */
520
521 /* rem: r0 = old proc */
522 /* rem: r1 = old pcb */
523 /* rem: r4 = return value */
524 /* rem: r6 = new process */
525 /* rem: interrupts are enabled */
526
527 /* What else needs to be saved Only FPA stuff when that is supported */
528
529 /* Third phase : restore saved context */
530
531 switch_exited:
532 /* Don't allow user space access beween the purge and the switch */
533 ldr r3, Lblock_userspace_access
534 ldr r2, [r3]
535 orr r0, r2, #1
536 str r0, [r3]
537
538 stmfd sp!, {r0-r3}
539 ldr r0, Lcpufuncs
540 add lr, pc, #Lcs_cache_purged - . - 8
541 ldr pc, [r0, #CF_IDCACHE_WBINV_ALL]
542
543 Lcs_cache_purged:
544 ldmfd sp!, {r0-r3}
545
546 /* At this point we need to kill IRQ's again. */
547 IRQdisable
548
549 /* Interrupts are disabled so we can allow user space accesses again
550 * as none will occur until interrupts are re-enabled after the
551 * switch.
552 */
553 str r2, [r3]
554
555 /* Get the user structure for the new process in r1 */
556 ldr r1, [r6, #(L_ADDR)]
557
558 /* Get the pagedir physical address for the process. */
559 ldr r0, [r1, #(PCB_PAGEDIR)]
560
561 /* Switch the memory to the new process */
562 ldr r3, Lcpufuncs
563 add lr, pc, #Lcs_context_switched - . - 8
564 ldr pc, [r3, #CF_CONTEXT_SWITCH]
565
566 Lcs_context_switched:
567 /*
568 * This can be optimised... We know we want to go from SVC32
569 * mode to UND32 mode
570 */
571 mrs r3, cpsr_all
572 bic r2, r3, #(PSR_MODE)
573 orr r2, r2, #(PSR_UND32_MODE)
574 msr cpsr_all, r2
575
576 ldr sp, [r1, #(PCB_UND_SP)]
577
578 msr cpsr_all, r3 /* Restore the old mode */
579
580 /* Restore all the save registers */
581 add r7, r1, #PCB_R8
582 ldmia r7, {r8-r13}
583
584 #ifdef ARMFPE
585 add r0, r1, #(USER_SIZE) & 0x00ff
586 add r0, r0, #(USER_SIZE) & 0xff00
587 bl _C_LABEL(arm_fpe_core_changecontext)
588 #endif
589
590 /* We can enable interrupts again */
591 IRQenable
592
593 switch_return:
594
595 /* Get the spl level from the stack and update the current spl level */
596 ldr r0, [sp], #0x0004
597 bl _C_LABEL(splx)
598
599 /* cpu_switch returns 1 == switched, 0 == didn't switch */
600 mov r0, r4
601
602 /*
603 * Pull the registers that got pushed when either savectx() or
604 * cpu_switch() was called and return.
605 */
606 ldmfd sp!, {r4-r7, pc}
607
608 /*
609 * cpu_preempt(struct lwp *current, struct lwp *next)
610 * Switch to the specified next LWP
611 * Arguments:
612 *
613 * r0 'struct lwp *' of the current LWP
614 * r1 'struct lwp *' of the LWP to switch to
615 */
616 ENTRY(cpu_preempt)
617 stmfd sp!, {r4-r7, lr}
618
619 /* stash the lwp parameters */
620 mov r6, r0 /* save old lwp */
621 mov r7, r1 /* save new lwp */
622
623 #if defined(LOCKDEBUG)
624 bl _C_LABEL(sched_unlock_idle)
625 #endif
626
627 /* Lower the spl level to spl0 and get the current spl level. */
628 #ifdef __NEWINTR
629 mov r0, #(IPL_NONE)
630 bl _C_LABEL(_spllower)
631 #else
632 #ifdef spl0
633 mov r0, #(_SPL_0)
634 bl _C_LABEL(splx)
635 #else
636 bl _C_LABEL(spl0)
637 #endif /* spl0 */
638 #endif /* __NEWINTR */
639
640 /* Push the old spl level onto the stack */
641 str r0, [sp, #-0x0004]!
642
643 mov r0, r6 /* restore old lwp */
644 mov r1, r7 /* restore new lwp */
645
646 /* rem: r1 = new lwp */
647
648 IRQdisable
649 #if defined(LOCKDEBUG)
650 bl _C_LABEL(sched_lock_idle)
651 #endif
652
653 /* Do we have any active queues? */
654 ldr r7, Lwhichqs
655 ldr r3, [r7]
656
657 /* If none, panic! */
658 teq r3, #0x00000000
659 beq preempt_noqueues
660
661 /* rem: r0 = old lwp */
662 /* rem: r1 = new lwp */
663 /* rem: r3 = whichqs */
664 /* rem: r7 = &whichqs */
665 /* rem: interrupts are disabled */
666
667 /* Compute the queue bit corresponding to the new lwp. */
668 ldrb r4, [r1, #(L_PRIORITY)]
669 mov r2, #0x00000001
670 mov r4, r4, lsr #2 /* queue number */
671 mov r2, r2, lsl r4 /* queue bit */
672
673 /* rem: r0 = old lwp */
674 /* rem: r1 = new lwp */
675 /* rem: r2 = queue bit */
676 /* rem: r3 = whichqs */
677 /* rem: r4 = queue number */
678 /* rem: r7 = &whichqs */
679
680 /*
681 * Unlink the lwp from the queue.
682 */
683 ldr r5, [r1, #(L_BACK)] /* r5 = l->l_back */
684 mov r6, #0x00000000
685 str r6, [r1, #(L_BACK)] /* firewall: l->l_back = NULL */
686 ldr r6, [r1, #(L_FORW)] /* r6 = l->l_forw */
687 str r5, [r6, #(L_BACK)] /* r6->l_back = r5 */
688 str r6, [r5, #(L_FORW)] /* r5->l_forw = r6 */
689
690 teq r5, r6 /* see if queue is empty */
691 biceq r3, r3, r2 /* clear bit if so */
692 streq r3, [r7] /* store it back if so */
693
694 /* rem: r2 (queue bit) now free */
695 /* rem: r3 (whichqs) now free */
696 /* rem: r7 (&whichqs) now free */
697
698 /*
699 * Okay, set up registers the way cpu_switch() wants them,
700 * and jump into the middle of it (where we bring up the
701 * new process).
702 */
703 mov r6, r1 /* r6 = new lwp */
704 mov r1, r0 /* r1 = old lwp */
705 b switch_resume
706
707 preempt_noqueues:
708 add r0, pc, #preemptpanic - . - 8
709 bl _C_LABEL(panic)
710
711 preemptpanic:
712 .asciz "cpu_preempt: whichqs empty"
713 .align 0
714
715 Llwp0:
716 .word _C_LABEL(lwp0)
717
718 Lkernel_map:
719 .word _C_LABEL(kernel_map)
720
721 /*
722 * void switch_exit(struct proc *p);
723 * Switch to proc0's saved context and deallocate the address space and kernel
724 * stack for p. Then jump into cpu_switch(), as if we were in proc0 all along.
725 */
726
727 /* LINTSTUB: Func: void switch_exit(struct proc *p) */
728 ENTRY(switch_exit)
729 /*
730 * r0 = lwp
731 * r1 = lwp0
732 */
733
734 mov r3, r0
735 ldr r1, Llwp0
736
737 /* In case we fault */
738 ldr r0, Lcurlwp
739 mov r2, #0x00000000
740 str r2, [r0]
741
742 /* ldr r0, Lcurpcb
743 str r2, [r0]*/
744
745 /* Switch to lwp0 context */
746
747 stmfd sp!, {r0-r3}
748
749 ldr r0, Lcpufuncs
750 add lr, pc, #Lse_cache_purged - . - 8
751 ldr pc, [r0, #CF_IDCACHE_WBINV_ALL]
752
753 Lse_cache_purged:
754 ldmfd sp!, {r0-r3}
755
756 IRQdisable
757
758 ldr r2, [r1, #(L_ADDR)]
759 ldr r0, [r2, #(PCB_PAGEDIR)]
760
761 /* Switch the memory to the new process */
762 ldr r4, Lcpufuncs
763 add lr, pc, #Lse_context_switched - . - 8
764 ldr pc, [r4, #CF_CONTEXT_SWITCH]
765
766 Lse_context_switched:
767 /* Restore all the save registers */
768 add r7, r2, #PCB_R8
769 ldmia r7, {r8-r13}
770
771 /* This is not really needed ! */
772 /* Yes it is for the su and fu routines */
773 ldr r0, Lcurpcb
774 str r2, [r0]
775
776 IRQenable
777
778 /* str r3, [sp, #-0x0004]!*/
779
780 /*
781 * Schedule the vmspace and stack to be freed.
782 */
783 mov r0, r3 /* exit2(l) */
784 bl _C_LABEL(exit2)
785
786 /* Paranoia */
787 mov r0, #0x00000000
788 ldr r1, Lcurlwp
789 str r0, [r1]
790
791 ldr r1, Llwp0
792 b Lswitch_search
793
794 ENTRY(switch_lwp_exit)
795 /*
796 * r0 = lwp
797 * r1 = lwp0
798 */
799
800 mov r3, r0
801 ldr r1, Llwp0
802
803 /* In case we fault */
804 mov r2, #0x00000000
805 ldr r0, Lcurlwp
806 str r2, [r0]
807
808 /* ldr r0, Lcurpcb
809 str r2, [r0]*/
810
811 /* Switch to lwp0 context */
812
813 stmfd sp!, {r0-r3}
814
815 ldr r0, Lcpufuncs
816 add lr, pc, #Lsle_cache_purged - . - 8
817 ldr pc, [r0, #CF_IDCACHE_WBINV_ALL]
818
819 Lsle_cache_purged:
820 ldmfd sp!, {r0-r3}
821
822 IRQdisable
823
824 ldr r2, [r1, #(L_ADDR)]
825 ldr r0, [r2, #(PCB_PAGEDIR)]
826
827 /* Switch the memory to the new process */
828 ldr r4, Lcpufuncs
829 add lr, pc, #Lsle_context_switched - . - 8
830 ldr pc, [r4, #CF_CONTEXT_SWITCH]
831
832 Lsle_context_switched:
833 /* Restore all the save registers */
834 add r7, r2, #PCB_R8
835 ldmia r7, {r8-r13}
836
837 /* This is not really needed ! */
838 /* Yes it is for the su and fu routines */
839 ldr r0, Lcurpcb
840 str r2, [r0]
841
842 IRQenable
843
844 /* str r3, [sp, #-0x0004]!*/
845
846 /*
847 * Schedule the vmspace and stack to be freed.
848 */
849 mov r0, r3 /* lwp_exit2(l) */
850 bl _C_LABEL(lwp_exit2)
851
852 /* Paranoia */
853 ldr r1, Lcurlwp
854 mov r0, #0x00000000
855 str r0, [r1]
856
857 ldr r5, Llwp0
858 b Lswitch_search
859
860 /* LINTSTUB: Func: void savectx(struct pcb *pcb) */
861 ENTRY(savectx)
862 /*
863 * r0 = pcb
864 */
865
866 /* Push registers.*/
867 stmfd sp!, {r4-r7, lr}
868
869 /* Store all the registers in the process's pcb */
870 add r2, r0, #(PCB_R8)
871 stmia r2, {r8-r13}
872
873 /* Pull the regs of the stack */
874 ldmfd sp!, {r4-r7, pc}
875
876 ENTRY(proc_trampoline)
877 add lr, pc, #(trampoline_return - . - 8)
878 mov r0, r5
879 mov r1, sp
880 mov pc, r4
881
882 trampoline_return:
883 /* Kill irq's */
884 mrs r0, cpsr_all
885 orr r0, r0, #(I32_bit)
886 msr cpsr_all, r0
887
888 PULLFRAME
889
890 movs pc, lr /* Exit */
891
892 .type Lcpu_switch_ffs_table, _ASM_TYPE_OBJECT;
893 Lcpu_switch_ffs_table:
894 /* same as ffs table but all nums are -1 from that */
895 /* 0 1 2 3 4 5 6 7 */
896 .byte 0, 0, 1, 12, 2, 6, 0, 13 /* 0- 7 */
897 .byte 3, 0, 7, 0, 0, 0, 0, 14 /* 8-15 */
898 .byte 10, 4, 0, 0, 8, 0, 0, 25 /* 16-23 */
899 .byte 0, 0, 0, 0, 0, 21, 27, 15 /* 24-31 */
900 .byte 31, 11, 5, 0, 0, 0, 0, 0 /* 32-39 */
901 .byte 9, 0, 0, 24, 0, 0, 20, 26 /* 40-47 */
902 .byte 30, 0, 0, 0, 0, 23, 0, 19 /* 48-55 */
903 .byte 29, 0, 22, 18, 28, 17, 16, 0 /* 56-63 */
904
905 /* End of cpuswitch.S */
906