Home | History | Annotate | Line # | Download | only in arm32
cpuswitch.S revision 1.24
      1  1.24    bjh21 /*	$NetBSD: cpuswitch.S,v 1.24 2002/10/14 22:32:50 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 /*
     74   1.1    chris  * setrunqueue() and remrunqueue()
     75   1.1    chris  *
     76   1.1    chris  * Functions to add and remove a process for the run queue.
     77   1.1    chris  */
     78   1.1    chris 
     79   1.1    chris 	.text
     80   1.1    chris 
     81  1.17  thorpej .Lwhichqs:
     82   1.1    chris 	.word	_C_LABEL(sched_whichqs)
     83   1.1    chris 
     84  1.17  thorpej .Lqs:
     85   1.1    chris 	.word	_C_LABEL(sched_qs)
     86   1.1    chris 
     87   1.1    chris /*
     88   1.1    chris  * On entry
     89   1.1    chris  *	r0 = process
     90   1.1    chris  */
     91   1.1    chris 
     92   1.1    chris ENTRY(setrunqueue)
     93   1.1    chris 	/*
     94   1.1    chris 	 * Local register usage
     95   1.1    chris 	 * 	r0 = process
     96   1.1    chris 	 * 	r1 = queue
     97   1.1    chris 	 * 	r2 = &qs[queue] and temp
     98   1.1    chris 	 * 	r3 = temp
     99   1.1    chris 	 *	r12 = whichqs
    100   1.1    chris 	 */
    101   1.1    chris #ifdef DIAGNOSTIC
    102   1.1    chris 	ldr	r1, [r0, #(P_BACK)]
    103   1.1    chris 	teq	r1, #0x00000000
    104  1.14   briggs 	bne	.Lsetrunqueue_erg
    105   1.1    chris 
    106   1.1    chris 	ldr	r1, [r0, #(P_WCHAN)]
    107   1.1    chris 	teq	r1, #0x00000000
    108  1.14   briggs 	bne	.Lsetrunqueue_erg
    109   1.1    chris #endif
    110   1.1    chris 
    111   1.1    chris 	/* Get the priority of the queue */
    112   1.1    chris 	ldrb	r1, [r0, #(P_PRIORITY)]
    113   1.1    chris 
    114   1.1    chris 	/* Indicate that there is a process on this queue */
    115  1.17  thorpej 	ldr	r12, .Lwhichqs
    116  1.12    chris 	mov	r1, r1, lsr #2
    117   1.1    chris 	ldr	r2, [r12]
    118   1.1    chris 	mov	r3, #0x00000001
    119   1.1    chris 	mov	r3, r3, lsl r1
    120   1.1    chris 	orr	r2, r2, r3
    121   1.1    chris 	str	r2, [r12]
    122   1.1    chris 
    123   1.1    chris 	/* Get the address of the queue */
    124  1.17  thorpej 	ldr	r2, .Lqs
    125   1.1    chris 	add	r1, r2, r1, lsl # 3
    126   1.1    chris 
    127   1.1    chris 	/* Hook the process in */
    128   1.1    chris 	str	r1, [r0, #(P_FORW)]
    129   1.1    chris 	ldr	r2, [r1, #(P_BACK)]
    130   1.1    chris 
    131   1.1    chris 	str	r0, [r1, #(P_BACK)]
    132   1.1    chris #ifdef DIAGNOSTIC
    133   1.1    chris 	teq	r2, #0x00000000
    134  1.14   briggs 	beq	.Lsetrunqueue_erg
    135   1.1    chris #endif
    136   1.1    chris 	str	r0, [r2, #(P_FORW)]
    137   1.1    chris 	str	r2, [r0, #(P_BACK)]
    138   1.1    chris 
    139   1.1    chris 	mov	pc, lr
    140   1.1    chris 
    141   1.1    chris #ifdef DIAGNOSTIC
    142  1.14   briggs .Lsetrunqueue_erg:
    143   1.1    chris 	mov	r2, r1
    144   1.1    chris 	mov	r1, r0
    145  1.23    bjh21 	adr	r0, .Ltext1
    146   1.1    chris 	bl	_C_LABEL(printf)
    147   1.1    chris 
    148  1.17  thorpej 	ldr	r2, .Lqs
    149   1.1    chris 	ldr	r1, [r2]
    150  1.23    bjh21 	adr	r0, .Ltext2
    151   1.1    chris 	b	_C_LABEL(panic)
    152   1.1    chris 
    153  1.17  thorpej .Ltext1:
    154   1.1    chris 	.asciz	"setrunqueue : %08x %08x\n"
    155  1.17  thorpej .Ltext2:
    156   1.1    chris 	.asciz	"setrunqueue : [qs]=%08x qs=%08x\n"
    157   1.1    chris 	.align	0
    158   1.1    chris #endif
    159   1.1    chris 
    160   1.1    chris /*
    161   1.1    chris  * On entry
    162   1.1    chris  *	r0 = process
    163   1.1    chris  */
    164   1.1    chris 
    165   1.1    chris ENTRY(remrunqueue)
    166   1.1    chris 	/*
    167   1.1    chris 	 * Local register usage
    168   1.1    chris 	 *	r0 = oldproc
    169   1.1    chris 	 * 	r1 = queue
    170   1.1    chris 	 * 	r2 = &qs[queue] and scratch
    171   1.1    chris 	 *	r3 = scratch
    172   1.1    chris 	 *	r12 = whichqs
    173   1.1    chris 	 */
    174   1.1    chris 
    175   1.1    chris 	/* Get the priority of the queue */
    176   1.1    chris 	ldrb	r1, [r0, #(P_PRIORITY)]
    177   1.1    chris 	mov	r1, r1, lsr #2
    178   1.1    chris 
    179   1.1    chris 	/* Unhook the process */
    180   1.1    chris 	ldr	r2, [r0, #(P_FORW)]
    181   1.1    chris 	ldr	r3, [r0, #(P_BACK)]
    182   1.1    chris 
    183   1.1    chris 	str	r3, [r2, #(P_BACK)]
    184   1.1    chris 	str	r2, [r3, #(P_FORW)]
    185   1.1    chris 
    186   1.1    chris 	/* If the queue is now empty clear the queue not empty flag */
    187   1.1    chris 	teq	r2, r3
    188   1.1    chris 
    189   1.1    chris 	/* This could be reworked to avoid the use of r4 */
    190  1.17  thorpej 	ldreq	r12, .Lwhichqs
    191  1.12    chris 	moveq	r3, #0x00000001
    192   1.1    chris 	ldreq	r2, [r12]
    193   1.1    chris 	moveq	r3, r3, lsl r1
    194   1.1    chris 	biceq	r2, r2, r3
    195   1.1    chris 	streq	r2, [r12]
    196   1.1    chris 
    197   1.1    chris 	/* Remove the back pointer for the process */
    198   1.1    chris 	mov	r1, #0x00000000
    199   1.1    chris 	str	r1, [r0, #(P_BACK)]
    200   1.1    chris 
    201   1.1    chris 	mov	pc, lr
    202   1.1    chris 
    203   1.1    chris 
    204   1.1    chris /*
    205   1.1    chris  * cpuswitch()
    206   1.1    chris  *
    207   1.1    chris  * preforms a process context switch.
    208   1.1    chris  * This function has several entry points
    209   1.1    chris  */
    210   1.1    chris 
    211  1.19    bjh21 #ifdef MULTIPROCESSOR
    212  1.19    bjh21 .Lcpu_info_store:
    213  1.19    bjh21 	.word	_C_LABEL(cpu_info_store)
    214  1.19    bjh21 .Lcurproc:
    215  1.19    bjh21 	/* FIXME: This is bogus in the general case. */
    216  1.19    bjh21 	.word	_C_LABEL(cpu_info_store) + CI_CURPROC
    217  1.22    bjh21 
    218  1.22    bjh21 .Lcurpcb:
    219  1.22    bjh21 	.word	_C_LABEL(cpu_info_store) + CI_CURPCB
    220  1.19    bjh21 #else
    221  1.17  thorpej .Lcurproc:
    222   1.1    chris 	.word	_C_LABEL(curproc)
    223   1.1    chris 
    224  1.17  thorpej .Lcurpcb:
    225   1.1    chris 	.word	_C_LABEL(curpcb)
    226  1.22    bjh21 #endif
    227   1.1    chris 
    228  1.17  thorpej .Lwant_resched:
    229   1.1    chris 	.word	_C_LABEL(want_resched)
    230   1.1    chris 
    231  1.17  thorpej .Lcpufuncs:
    232   1.1    chris 	.word	_C_LABEL(cpufuncs)
    233   1.1    chris 
    234  1.22    bjh21 #ifndef MULTIPROCESSOR
    235   1.1    chris 	.data
    236   1.1    chris 	.global	_C_LABEL(curpcb)
    237   1.1    chris _C_LABEL(curpcb):
    238   1.1    chris 	.word	0x00000000
    239   1.1    chris 	.text
    240  1.22    bjh21 #endif
    241   1.1    chris 
    242  1.17  thorpej .Lblock_userspace_access:
    243   1.1    chris 	.word	_C_LABEL(block_userspace_access)
    244   1.1    chris 
    245  1.15  thorpej .Lcpu_do_powersave:
    246  1.15  thorpej 	.word	_C_LABEL(cpu_do_powersave)
    247  1.15  thorpej 
    248   1.1    chris /*
    249   1.1    chris  * Idle loop, exercised while waiting for a process to wake up.
    250  1.16  thorpej  *
    251  1.16  thorpej  * NOTE: When we jump back to .Lswitch_search, we must have a
    252  1.16  thorpej  * pointer to whichqs in r7, which is what it is when we arrive
    253  1.16  thorpej  * here.
    254   1.1    chris  */
    255   1.7    chris /* LINTSTUB: Ignore */
    256   1.4    chris ASENTRY_NP(idle)
    257  1.19    bjh21 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
    258   1.7    chris 	bl	_C_LABEL(sched_unlock_idle)
    259   1.7    chris #endif
    260  1.16  thorpej 	ldr	r3, .Lcpu_do_powersave
    261  1.16  thorpej 
    262   1.1    chris 	/* Enable interrupts */
    263   1.1    chris 	IRQenable
    264   1.1    chris 
    265  1.15  thorpej 	/* If we don't want to sleep, use a simpler loop. */
    266  1.16  thorpej 	ldr	r3, [r3]		/* r3 = cpu_do_powersave */
    267  1.15  thorpej 	teq	r3, #0
    268  1.16  thorpej 	bne	2f
    269  1.16  thorpej 
    270  1.16  thorpej 	/* Non-powersave idle. */
    271  1.16  thorpej 1:	/* should maybe do uvm pageidlezero stuff here */
    272  1.16  thorpej 	ldr	r3, [r7]		/* r3 = whichqs */
    273  1.16  thorpej 	teq	r3, #0x00000000
    274  1.16  thorpej 	bne	.Lswitch_search
    275  1.16  thorpej 	b	1b
    276  1.15  thorpej 
    277  1.16  thorpej 2:	/* Powersave idle. */
    278  1.17  thorpej 	ldr	r4, .Lcpufuncs
    279  1.16  thorpej 3:	ldr	r3, [r7]		/* r3 = whichqs */
    280  1.15  thorpej 	teq	r3, #0x00000000
    281  1.15  thorpej 	bne	.Lswitch_search
    282  1.15  thorpej 
    283  1.15  thorpej 	/* if saving power, don't want to pageidlezero */
    284   1.1    chris 	mov	r0, #0
    285  1.21    bjh21 	adr	lr, 3b
    286  1.15  thorpej 	ldr	pc, [r4, #(CF_SLEEP)]
    287  1.15  thorpej 	/* loops back around */
    288  1.15  thorpej 
    289   1.1    chris 
    290   1.1    chris /*
    291   1.1    chris  * Find a new process to run, save the current context and
    292   1.1    chris  * load the new context
    293   1.1    chris  */
    294   1.1    chris 
    295   1.1    chris ENTRY(cpu_switch)
    296   1.1    chris /*
    297   1.1    chris  * Local register usage. Some of these registers are out of date.
    298   1.1    chris  * r1 = oldproc
    299   1.1    chris  * r3 = whichqs
    300   1.1    chris  * r4 = queue
    301   1.1    chris  * r5 = &qs[queue]
    302   1.1    chris  * r6 = newproc
    303   1.1    chris  * r7 = scratch
    304   1.1    chris  */
    305   1.1    chris 	stmfd	sp!, {r4-r7, lr}
    306   1.1    chris 
    307   1.1    chris 	/*
    308   1.1    chris 	 * Get the current process and indicate that there is no longer
    309  1.11  thorpej 	 * a valid process (curproc = 0).  Zero the current PCB pointer
    310  1.11  thorpej 	 * while we're at it.
    311   1.1    chris 	 */
    312  1.17  thorpej 	ldr	r7, .Lcurproc
    313  1.17  thorpej 	ldr	r6, .Lcurpcb
    314   1.1    chris 	mov	r0, #0x00000000
    315  1.11  thorpej 	ldr	r1, [r7]		/* r1 = curproc */
    316  1.11  thorpej 	str	r0, [r7]		/* curproc = NULL */
    317  1.11  thorpej 	str	r0, [r6]		/* curpcb = NULL */
    318   1.1    chris 
    319  1.10  thorpej 	/* stash the old proc while we call functions */
    320  1.10  thorpej 	mov	r5, r1
    321   1.1    chris 
    322  1.19    bjh21 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
    323   1.7    chris 	/* release the sched_lock before handling interrupts */
    324   1.7    chris 	bl	_C_LABEL(sched_unlock_idle)
    325   1.7    chris #endif
    326   1.7    chris 
    327   1.7    chris 	/* Lower the spl level to spl0 and get the current spl level. */
    328   1.5  thorpej #ifdef __NEWINTR
    329   1.5  thorpej 	mov	r0, #(IPL_NONE)
    330   1.5  thorpej 	bl	_C_LABEL(_spllower)
    331   1.5  thorpej #else /* ! __NEWINTR */
    332   1.1    chris #ifdef spl0
    333   1.1    chris 	mov	r0, #(_SPL_0)
    334   1.1    chris 	bl	_C_LABEL(splx)
    335   1.1    chris #else
    336   1.1    chris 	bl	_C_LABEL(spl0)
    337   1.5  thorpej #endif /* spl0 */
    338   1.5  thorpej #endif /* __NEWINTR */
    339   1.1    chris 
    340   1.1    chris 	/* Push the old spl level onto the stack */
    341   1.1    chris 	str	r0, [sp, #-0x0004]!
    342   1.1    chris 
    343   1.1    chris 	/* First phase : find a new process */
    344   1.1    chris 
    345  1.17  thorpej 	ldr	r7, .Lwhichqs
    346  1.16  thorpej 
    347   1.7    chris 	/* rem: r5 = old proc */
    348  1.16  thorpej 	/* rem: r7 = &whichqs */
    349   1.7    chris 
    350  1.14   briggs .Lswitch_search:
    351   1.1    chris 	IRQdisable
    352  1.19    bjh21 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
    353   1.7    chris 	bl	_C_LABEL(sched_lock_idle)
    354   1.7    chris #endif
    355   1.7    chris 
    356   1.1    chris 	/* Do we have any active queues  */
    357   1.1    chris 	ldr	r3, [r7]
    358   1.1    chris 
    359   1.1    chris 	/* If not we must idle until we do. */
    360   1.1    chris 	teq	r3, #0x00000000
    361   1.4    chris 	beq	_ASM_LABEL(idle)
    362   1.7    chris 
    363  1.10  thorpej 	/* put old proc back in r1 */
    364   1.7    chris 	mov	r1, r5
    365   1.1    chris 
    366   1.1    chris 	/* rem: r1 = old proc */
    367   1.1    chris 	/* rem: r3 = whichqs */
    368   1.1    chris 	/* rem: interrupts are disabled */
    369   1.1    chris 
    370   1.1    chris 	/*
    371   1.1    chris 	 * We have found an active queue. Currently we do not know which queue
    372   1.1    chris 	 * is active just that one of them is.
    373   1.1    chris 	 */
    374   1.1    chris 	/* this is the ffs algorithm devised by d.seal and posted to
    375   1.1    chris 	 * comp.sys.arm on 16 Feb 1994.
    376   1.1    chris 	 */
    377   1.1    chris  	rsb	r5, r3, #0
    378   1.1    chris  	ands	r0, r3, r5
    379   1.1    chris 
    380  1.17  thorpej 	adr	r5, .Lcpu_switch_ffs_table
    381   1.1    chris 
    382   1.3    chris 				    /* X = R0 */
    383   1.3    chris 	orr	r4, r0, r0, lsl #4  /* r4 = X * 0x11 */
    384   1.3    chris 	orr	r4, r4, r4, lsl #6  /* r4 = X * 0x451 */
    385   1.3    chris 	rsb	r4, r4, r4, lsl #16 /* r4 = X * 0x0450fbaf */
    386   1.1    chris 
    387   1.1    chris 	/* used further down, saves SA stall */
    388  1.17  thorpej 	ldr	r6, .Lqs
    389   1.1    chris 
    390   1.3    chris 	/* now lookup in table indexed on top 6 bits of a4 */
    391   1.1    chris 	ldrb	r4, [ r5, r4, lsr #26 ]
    392   1.1    chris 
    393   1.1    chris 	/* rem: r0 = bit mask of chosen queue (1 << r4) */
    394   1.1    chris 	/* rem: r1 = old proc */
    395   1.1    chris 	/* rem: r3 = whichqs */
    396   1.1    chris 	/* rem: r4 = queue number */
    397   1.1    chris 	/* rem: interrupts are disabled */
    398   1.1    chris 
    399   1.1    chris 	/* Get the address of the queue (&qs[queue]) */
    400   1.1    chris 	add	r5, r6, r4, lsl #3
    401   1.1    chris 
    402   1.1    chris 	/*
    403   1.1    chris 	 * Get the process from the queue and place the next process in
    404   1.1    chris 	 * the queue at the head. This basically unlinks the process at
    405   1.1    chris 	 * the head of the queue.
    406   1.1    chris 	 */
    407   1.1    chris 	ldr	r6, [r5, #(P_FORW)]
    408   1.1    chris 
    409   1.1    chris 	/* rem: r6 = new process */
    410   1.1    chris 	ldr	r7, [r6, #(P_FORW)]
    411   1.1    chris 	str	r7, [r5, #(P_FORW)]
    412   1.1    chris 
    413   1.1    chris 	/*
    414   1.1    chris 	 * Test to see if the queue is now empty. If the head of the queue
    415   1.1    chris 	 * points to the queue itself then there are no more processes in
    416   1.1    chris 	 * the queue. We can therefore clear the queue not empty flag held
    417   1.1    chris 	 * in r3.
    418   1.1    chris 	 */
    419   1.1    chris 
    420   1.1    chris 	teq	r5, r7
    421   1.1    chris 	biceq	r3, r3, r0
    422   1.1    chris 
    423   1.1    chris 	/* rem: r0 = bit mask of chosen queue (1 << r4) - NOT NEEDED AN MORE */
    424   1.1    chris 
    425   1.1    chris 	/* Fix the back pointer for the process now at the head of the queue. */
    426   1.1    chris 	ldr	r0, [r6, #(P_BACK)]
    427   1.1    chris 	str	r0, [r7, #(P_BACK)]
    428   1.1    chris 
    429   1.1    chris 	/* Update the RAM copy of the queue not empty flags word. */
    430  1.17  thorpej 	ldr	r7, .Lwhichqs
    431   1.1    chris 	str	r3, [r7]
    432   1.1    chris 
    433   1.1    chris 	/* rem: r1 = old proc */
    434   1.1    chris 	/* rem: r3 = whichqs - NOT NEEDED ANY MORE */
    435   1.1    chris 	/* rem: r4 = queue number - NOT NEEDED ANY MORE */
    436   1.1    chris 	/* rem: r6 = new process */
    437   1.1    chris 	/* rem: interrupts are disabled */
    438   1.1    chris 
    439   1.1    chris 	/* Clear the want_resched flag */
    440  1.17  thorpej 	ldr	r7, .Lwant_resched
    441   1.1    chris 	mov	r0, #0x00000000
    442   1.1    chris 	str	r0, [r7]
    443   1.1    chris 
    444   1.1    chris 	/*
    445   1.1    chris 	 * Clear the back pointer of the process we have removed from
    446   1.1    chris 	 * the head of the queue. The new process is isolated now.
    447   1.1    chris 	 */
    448   1.1    chris 	str	r0, [r6, #(P_BACK)]
    449   1.1    chris 
    450  1.19    bjh21 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
    451   1.7    chris 	/*
    452   1.7    chris 	 * unlock the sched_lock, but leave interrupts off, for now.
    453   1.7    chris 	 */
    454   1.7    chris 	mov	r7, r1
    455   1.7    chris 	bl	_C_LABEL(sched_unlock_idle)
    456   1.7    chris 	mov	r1, r7
    457   1.7    chris #endif
    458   1.7    chris 
    459  1.19    bjh21 #ifdef MULTIPROCESSOR
    460  1.19    bjh21 	/* XXX use curcpu() */
    461  1.19    bjh21 	ldr	r0, .Lcpu_info_store
    462  1.19    bjh21 	str	r0, [r6, #(P_CPU)]
    463  1.19    bjh21 #else
    464   1.1    chris 	/* p->p_cpu initialized in fork1() for single-processor */
    465  1.19    bjh21 #endif
    466   1.1    chris 
    467   1.1    chris 	/* Process is now on a processor. */
    468   1.1    chris 	mov	r0, #SONPROC			/* p->p_stat = SONPROC */
    469   1.1    chris 	strb	r0, [r6, #(P_STAT)]
    470   1.1    chris 
    471   1.1    chris 	/* We have a new curproc now so make a note it */
    472  1.17  thorpej 	ldr	r7, .Lcurproc
    473   1.1    chris 	str	r6, [r7]
    474   1.1    chris 
    475   1.1    chris 	/* Hook in a new pcb */
    476  1.17  thorpej 	ldr	r7, .Lcurpcb
    477   1.1    chris 	ldr	r0, [r6, #(P_ADDR)]
    478   1.1    chris 	str	r0, [r7]
    479   1.1    chris 
    480   1.1    chris 	/* At this point we can allow IRQ's again. */
    481   1.1    chris 	IRQenable
    482   1.1    chris 
    483   1.1    chris 	/* rem: r1 = old proc */
    484   1.1    chris 	/* rem: r6 = new process */
    485   1.4    chris 	/* rem: interrupts are enabled */
    486   1.1    chris 
    487   1.1    chris 	/*
    488   1.1    chris 	 * If the new process is the same as the process that called
    489   1.1    chris 	 * cpu_switch() then we do not need to save and restore any
    490   1.1    chris 	 * contexts. This means we can make a quick exit.
    491   1.1    chris 	 * The test is simple if curproc on entry (now in r1) is the
    492   1.1    chris 	 * same as the proc removed from the queue we can jump to the exit.
    493   1.1    chris 	 */
    494   1.1    chris 	teq	r1, r6
    495  1.14   briggs 	beq	.Lswitch_return
    496   1.1    chris 
    497   1.9  thorpej 	/* Remember the old process in r0 */
    498   1.9  thorpej 	mov	r0, r1
    499   1.9  thorpej 
    500   1.1    chris 	/*
    501   1.1    chris 	 * If the curproc on entry to cpu_switch was zero then the
    502   1.1    chris 	 * process that called it was exiting. This means that we do
    503   1.1    chris 	 * not need to save the current context. Instead we can jump
    504   1.1    chris 	 * straight to restoring the context for the new process.
    505   1.1    chris 	 */
    506   1.9  thorpej 	teq	r0, #0x00000000
    507  1.14   briggs 	beq	.Lswitch_exited
    508   1.1    chris 
    509   1.9  thorpej 	/* rem: r0 = old proc */
    510   1.1    chris 	/* rem: r6 = new process */
    511   1.4    chris 	/* rem: interrupts are enabled */
    512   1.1    chris 
    513   1.1    chris 	/* Stage two : Save old context */
    514   1.1    chris 
    515   1.1    chris 	/* Get the user structure for the old process. */
    516   1.9  thorpej 	ldr	r1, [r0, #(P_ADDR)]
    517   1.1    chris 
    518   1.1    chris 	/* Save all the registers in the old process's pcb */
    519   1.1    chris 	add	r7, r1, #(PCB_R8)
    520   1.1    chris 	stmia	r7, {r8-r13}
    521   1.1    chris 
    522   1.1    chris 	/*
    523   1.1    chris 	 * This can be optimised... We know we want to go from SVC32
    524   1.1    chris 	 * mode to UND32 mode
    525   1.1    chris 	 */
    526  1.13  thorpej         mrs	r3, cpsr
    527   1.1    chris 	bic	r2, r3, #(PSR_MODE)
    528   1.1    chris 	orr	r2, r2, #(PSR_UND32_MODE | I32_bit)
    529  1.13  thorpej         msr	cpsr_c, r2
    530   1.1    chris 
    531   1.1    chris 	str	sp, [r1, #(PCB_UND_SP)]
    532   1.1    chris 
    533  1.13  thorpej         msr	cpsr_c, r3		/* Restore the old mode */
    534   1.1    chris 
    535   1.1    chris 	/* rem: r0 = old proc */
    536   1.4    chris 	/* rem: r1 = old pcb */
    537   1.1    chris 	/* rem: r6 = new process */
    538   1.4    chris 	/* rem: interrupts are enabled */
    539   1.1    chris 
    540   1.1    chris 	/* What else needs to be saved  Only FPA stuff when that is supported */
    541   1.1    chris 
    542   1.9  thorpej 	/* r1 now free! */
    543   1.9  thorpej 
    544   1.1    chris 	/* Third phase : restore saved context */
    545   1.1    chris 
    546   1.9  thorpej 	/* rem: r0 = old proc */
    547   1.9  thorpej 	/* rem: r6 = new process */
    548   1.9  thorpej 	/* rem: interrupts are enabled */
    549   1.9  thorpej 
    550   1.9  thorpej 	/*
    551   1.9  thorpej 	 * Don't allow user space access between the purge and the switch.
    552   1.9  thorpej 	 */
    553  1.17  thorpej 	ldr	r3, .Lblock_userspace_access
    554   1.9  thorpej 	mov	r1, #0x00000001
    555   1.9  thorpej 	mov	r2, #0x00000000
    556   1.9  thorpej 	str	r1, [r3]
    557   1.1    chris 
    558   1.1    chris 	stmfd	sp!, {r0-r3}
    559  1.17  thorpej 	ldr	r1, .Lcpufuncs
    560  1.23    bjh21 	mov	lr, pc
    561   1.9  thorpej 	ldr	pc, [r1, #CF_IDCACHE_WBINV_ALL]
    562   1.1    chris 	ldmfd	sp!, {r0-r3}
    563   1.1    chris 
    564  1.14   briggs .Lcs_cache_purge_skipped:
    565   1.1    chris 	/* At this point we need to kill IRQ's again. */
    566   1.1    chris 	IRQdisable
    567   1.1    chris 
    568   1.9  thorpej 	/*
    569   1.9  thorpej 	 * Interrupts are disabled so we can allow user space accesses again
    570   1.1    chris 	 * as none will occur until interrupts are re-enabled after the
    571   1.1    chris 	 * switch.
    572   1.1    chris 	 */
    573   1.1    chris 	str	r2, [r3]
    574   1.1    chris 
    575   1.1    chris 	/* Get the user structure for the new process in r1 */
    576   1.1    chris 	ldr	r1, [r6, #(P_ADDR)]
    577   1.1    chris 
    578   1.1    chris 	/* Get the pagedir physical address for the process. */
    579   1.1    chris 	ldr	r0, [r1, #(PCB_PAGEDIR)]
    580   1.1    chris 
    581   1.1    chris 	/* Switch the memory to the new process */
    582  1.17  thorpej 	ldr	r3, .Lcpufuncs
    583  1.23    bjh21 	mov	lr, pc
    584   1.1    chris 	ldr	pc, [r3, #CF_CONTEXT_SWITCH]
    585   1.1    chris 
    586   1.1    chris 	/*
    587   1.1    chris 	 * This can be optimised... We know we want to go from SVC32
    588   1.1    chris 	 * mode to UND32 mode
    589   1.1    chris 	 */
    590  1.13  thorpej         mrs	r3, cpsr
    591   1.1    chris 	bic	r2, r3, #(PSR_MODE)
    592   1.1    chris 	orr	r2, r2, #(PSR_UND32_MODE)
    593  1.13  thorpej         msr	cpsr_c, r2
    594   1.1    chris 
    595   1.1    chris 	ldr	sp, [r1, #(PCB_UND_SP)]
    596   1.1    chris 
    597  1.13  thorpej         msr	cpsr_c, r3		/* Restore the old mode */
    598   1.1    chris 
    599   1.1    chris 	/* Restore all the save registers */
    600   1.1    chris 	add	r7, r1, #PCB_R8
    601   1.1    chris 	ldmia	r7, {r8-r13}
    602   1.1    chris 
    603  1.18  thorpej 	mov	r7, r1			/* preserve PCB pointer */
    604  1.18  thorpej 
    605   1.1    chris #ifdef ARMFPE
    606   1.1    chris 	add	r0, r1, #(USER_SIZE) & 0x00ff
    607   1.1    chris 	add	r0, r0, #(USER_SIZE) & 0xff00
    608   1.1    chris 	bl	_C_LABEL(arm_fpe_core_changecontext)
    609   1.1    chris #endif
    610   1.1    chris 
    611   1.1    chris 	/* We can enable interrupts again */
    612   1.1    chris 	IRQenable
    613   1.1    chris 
    614  1.18  thorpej 	/* rem: r6 = new proc */
    615  1.18  thorpej 	/* rem: r7 = new PCB */
    616  1.18  thorpej 
    617  1.18  thorpej 	/*
    618  1.18  thorpej 	 * Check for restartable atomic sequences (RAS).
    619  1.18  thorpej 	 */
    620  1.18  thorpej 
    621  1.18  thorpej 	ldr	r2, [r6, #(P_NRAS)]
    622  1.18  thorpej 	ldr	r4, [r7, #(PCB_TF)]	/* r4 = trapframe (used below) */
    623  1.18  thorpej 	teq	r2, #0			/* p->p_nras == 0? */
    624  1.18  thorpej 	bne	.Lswitch_do_ras		/* no, check for one */
    625  1.18  thorpej 
    626  1.14   briggs .Lswitch_return:
    627   1.1    chris 
    628   1.1    chris 	/* Get the spl level from the stack and update the current spl level */
    629   1.1    chris 	ldr	r0, [sp], #0x0004
    630   1.1    chris 	bl	_C_LABEL(splx)
    631   1.1    chris 
    632   1.1    chris 	/* cpu_switch returns the proc it switched to. */
    633   1.1    chris 	mov	r0, r6
    634   1.1    chris 
    635   1.1    chris 	/*
    636   1.1    chris 	 * Pull the registers that got pushed when either savectx() or
    637   1.1    chris 	 * cpu_switch() was called and return.
    638   1.1    chris 	 */
    639   1.1    chris 	ldmfd	sp!, {r4-r7, pc}
    640  1.18  thorpej 
    641  1.18  thorpej .Lswitch_do_ras:
    642  1.18  thorpej 	ldr	r1, [r4, #(TF_PC)]	/* second ras_lookup() arg */
    643  1.18  thorpej 	mov	r0, r6			/* first ras_lookup() arg */
    644  1.18  thorpej 	bl	_C_LABEL(ras_lookup)
    645  1.18  thorpej 	cmn	r0, #1			/* -1 means "not in a RAS" */
    646  1.18  thorpej 	strne	r0, [r4, #(TF_PC)]
    647  1.18  thorpej 	b	.Lswitch_return
    648   1.1    chris 
    649  1.14   briggs .Lswitch_exited:
    650   1.9  thorpej 	/*
    651   1.9  thorpej 	 * We skip the cache purge because switch_exit() already did
    652   1.9  thorpej 	 * it.  Load up registers the way Lcs_cache_purge_skipped
    653   1.9  thorpej 	 * expects.  Userspace access already blocked in switch_exit().
    654   1.9  thorpej 	 */
    655  1.17  thorpej 	ldr	r3, .Lblock_userspace_access
    656   1.9  thorpej 	mov	r2, #0x00000000
    657  1.14   briggs 	b	.Lcs_cache_purge_skipped
    658   1.9  thorpej 
    659   1.7    chris /*
    660   1.8  thorpej  * void switch_exit(struct proc *p, struct proc *p0);
    661   1.7    chris  * Switch to proc0's saved context and deallocate the address space and kernel
    662   1.7    chris  * stack for p.  Then jump into cpu_switch(), as if we were in proc0 all along.
    663   1.7    chris  */
    664   1.1    chris 
    665   1.8  thorpej /* LINTSTUB: Func: void switch_exit(struct proc *p, struct proc *p0) */
    666   1.1    chris ENTRY(switch_exit)
    667   1.1    chris 	/*
    668   1.1    chris 	 * r0 = proc
    669   1.1    chris 	 * r1 = proc0
    670   1.1    chris 	 */
    671   1.1    chris 
    672   1.1    chris 	mov	r3, r0
    673   1.1    chris 
    674   1.1    chris 	/* In case we fault */
    675  1.17  thorpej 	ldr	r0, .Lcurproc
    676   1.1    chris 	mov	r2, #0x00000000
    677   1.1    chris 	str	r2, [r0]
    678   1.1    chris 
    679  1.17  thorpej /*	ldr	r0, .Lcurpcb
    680   1.1    chris 	str	r2, [r0]*/
    681   1.9  thorpej 
    682   1.9  thorpej 	/*
    683   1.9  thorpej 	 * Don't allow user space access between the purge and the switch.
    684   1.9  thorpej 	 */
    685  1.17  thorpej 	ldr	r0, .Lblock_userspace_access
    686   1.9  thorpej 	mov	r2, #0x00000001
    687   1.9  thorpej 	str	r2, [r0]
    688   1.1    chris 
    689   1.1    chris 	/* Switch to proc0 context */
    690   1.1    chris 
    691   1.1    chris 	stmfd	sp!, {r0-r3}
    692   1.1    chris 
    693  1.17  thorpej 	ldr	r0, .Lcpufuncs
    694  1.23    bjh21 	mov	lr, pc
    695   1.6  thorpej 	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
    696   1.1    chris 
    697   1.1    chris 	ldmfd	sp!, {r0-r3}
    698   1.1    chris 
    699   1.1    chris 	IRQdisable
    700   1.1    chris 
    701   1.1    chris 	ldr	r2, [r1, #(P_ADDR)]
    702   1.1    chris 	ldr	r0, [r2, #(PCB_PAGEDIR)]
    703   1.1    chris 
    704   1.1    chris 	/* Switch the memory to the new process */
    705  1.17  thorpej 	ldr	r4, .Lcpufuncs
    706  1.23    bjh21 	mov	lr, pc
    707   1.1    chris 	ldr	pc, [r4, #CF_CONTEXT_SWITCH]
    708   1.1    chris 
    709   1.1    chris 	/* Restore all the save registers */
    710   1.1    chris 	add	r7, r2, #PCB_R8
    711   1.1    chris 	ldmia	r7, {r8-r13}
    712   1.1    chris 
    713   1.1    chris 	/* This is not really needed ! */
    714   1.1    chris 	/* Yes it is for the su and fu routines */
    715  1.17  thorpej 	ldr	r0, .Lcurpcb
    716   1.1    chris 	str	r2, [r0]
    717   1.1    chris 
    718   1.1    chris 	IRQenable
    719   1.1    chris 
    720   1.1    chris /*	str	r3, [sp, #-0x0004]!*/
    721   1.1    chris 
    722   1.1    chris 	/*
    723   1.1    chris 	 * Schedule the vmspace and stack to be freed.
    724   1.1    chris 	 */
    725   1.1    chris 	mov	r0, r3			/* exit2(p) */
    726   1.1    chris 	bl	_C_LABEL(exit2)
    727   1.1    chris 
    728   1.1    chris 	/* Paranoia */
    729  1.17  thorpej 	ldr	r1, .Lcurproc
    730   1.1    chris 	mov	r0, #0x00000000
    731   1.1    chris 	str	r0, [r1]
    732   1.1    chris 
    733  1.17  thorpej 	ldr	r7, .Lwhichqs		/* r7 = &whichqs */
    734   1.8  thorpej 	mov	r5, #0x00000000		/* r5 = old proc = NULL */
    735  1.14   briggs 	b	.Lswitch_search
    736   1.1    chris 
    737   1.7    chris /* LINTSTUB: Func: void savectx(struct pcb *pcb) */
    738   1.1    chris ENTRY(savectx)
    739   1.1    chris 	/*
    740   1.1    chris 	 * r0 = pcb
    741   1.1    chris 	 */
    742   1.1    chris 
    743   1.1    chris 	/* Push registers.*/
    744   1.1    chris 	stmfd	sp!, {r4-r7, lr}
    745   1.1    chris 
    746   1.1    chris 	/* Store all the registers in the process's pcb */
    747   1.1    chris 	add	r2, r0, #(PCB_R8)
    748   1.1    chris 	stmia	r2, {r8-r13}
    749   1.1    chris 
    750   1.1    chris 	/* Pull the regs of the stack */
    751   1.1    chris 	ldmfd	sp!, {r4-r7, pc}
    752   1.1    chris 
    753   1.1    chris ENTRY(proc_trampoline)
    754  1.19    bjh21 #ifdef MULTIPROCESSOR
    755  1.19    bjh21 	bl	_C_LABEL(proc_trampoline_mp)
    756  1.19    bjh21 #endif
    757   1.1    chris 	mov	r0, r5
    758   1.1    chris 	mov	r1, sp
    759  1.24    bjh21 	mov	lr, pc
    760   1.1    chris 	mov	pc, r4
    761   1.1    chris 
    762   1.1    chris 	/* Kill irq's */
    763  1.13  thorpej         mrs     r0, cpsr
    764   1.1    chris         orr     r0, r0, #(I32_bit)
    765  1.13  thorpej         msr     cpsr_c, r0
    766   1.1    chris 
    767   1.1    chris 	PULLFRAME
    768   1.1    chris 
    769   1.1    chris 	movs	pc, lr			/* Exit */
    770   1.1    chris 
    771  1.17  thorpej 	.type .Lcpu_switch_ffs_table, _ASM_TYPE_OBJECT;
    772  1.17  thorpej .Lcpu_switch_ffs_table:
    773   1.1    chris /* same as ffs table but all nums are -1 from that */
    774   1.1    chris /*               0   1   2   3   4   5   6   7           */
    775   1.1    chris 	.byte	 0,  0,  1, 12,  2,  6,  0, 13  /*  0- 7 */
    776   1.1    chris 	.byte	 3,  0,  7,  0,  0,  0,  0, 14  /*  8-15 */
    777   1.1    chris 	.byte	10,  4,  0,  0,  8,  0,  0, 25  /* 16-23 */
    778   1.1    chris 	.byte	 0,  0,  0,  0,  0, 21, 27, 15  /* 24-31 */
    779   1.1    chris 	.byte	31, 11,  5,  0,  0,  0,  0,  0	/* 32-39 */
    780   1.1    chris 	.byte	 9,  0,  0, 24,  0,  0, 20, 26  /* 40-47 */
    781   1.1    chris 	.byte	30,  0,  0,  0,  0, 23,  0, 19  /* 48-55 */
    782   1.1    chris 	.byte   29,  0, 22, 18, 28, 17, 16,  0  /* 56-63 */
    783   1.1    chris 
    784   1.1    chris /* End of cpuswitch.S */
    785