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