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