Home | History | Annotate | Line # | Download | only in arm32
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