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