]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/cswtch.s
xnu-792.21.3.tar.gz
[apple/xnu.git] / osfmk / ppc / cswtch.s
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31
32#include <ppc/asm.h>
33#include <ppc/proc_reg.h>
1c79356b
A
34#include <assym.s>
35#include <debug.h>
36#include <mach/ppc/vm_param.h>
37#include <ppc/exception.h>
9bccf70c 38#include <ppc/savearea.h>
1c79356b
A
39
40#define FPVECDBG 0
1c79356b
A
41
42 .text
43
44/*
55e303ae 45 * void machine_load_context(thread_t thread)
1c79356b 46 *
55e303ae
A
47 * Load the context for the first thread to run on a
48 * cpu, and go.
1c79356b
A
49 */
50
9bccf70c 51 .align 5
55e303ae 52 .globl EXT(machine_load_context)
1c79356b 53
55e303ae 54LEXT(machine_load_context)
91447636
A
55 mfsprg r6,1 ; Get the current activation
56 lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block
1c79356b 57 lwz r0,PP_INTSTACK_TOP_SS(r6)
1c79356b 58 stw r0,PP_ISTACKPTR(r6)
91447636 59 mr r9,r3 /* Set up the current thread */
55e303ae 60 mtsprg 1,r9
1c79356b 61 li r0,0 /* Clear a register */
55e303ae 62 lwz r3,ACT_MACT_PCB(r9) /* Get the savearea used */
1c79356b 63 mfmsr r5 /* Since we are passing control, get our MSR values */
55e303ae
A
64 lwz r11,SAVprev+4(r3) /* Get the previous savearea */
65 lwz r1,saver1+4(r3) /* Load new stack pointer */
ab86ba33 66 lwz r10,ACT_MACT_SPF(r9) /* Get the special flags */
55e303ae 67 stw r0,saver3+4(r3) /* Make sure we pass in a 0 for the continuation */
1c79356b 68 stw r0,FM_BACKPTR(r1) /* zero backptr */
55e303ae 69 stw r5,savesrr1+4(r3) /* Pass our MSR to the new guy */
1c79356b 70 stw r11,ACT_MACT_PCB(r9) /* Unstack our savearea */
ab86ba33 71 oris r10,r10,hi16(OnProc) /* Set OnProc bit */
55e303ae 72 stw r0,ACT_PREEMPT_CNT(r9) /* Enable preemption */
ab86ba33
A
73 stw r10,ACT_MACT_SPF(r9) /* Update the special flags */
74 stw r10,spcFlags(r6) /* Set per_proc copy of the special flags */
55e303ae 75 b EXT(exception_exit) /* Go for it */
1c79356b 76
55e303ae
A
77/* thread_t Switch_context(thread_t old,
78 * void (*cont)(void),
79 * thread_t new)
1c79356b
A
80 *
81 * Switch from one thread to another. If a continuation is supplied, then
82 * we do not need to save callee save registers.
83 *
84 */
85
91447636 86/* void Call_continuation( void (*continuation)(void), void *param, wait_result_t wresult, vm_offset_t stack_ptr)
1c79356b
A
87 */
88
9bccf70c
A
89 .align 5
90 .globl EXT(Call_continuation)
91
92LEXT(Call_continuation)
91447636
A
93 mtlr r3 /* continuation */
94 mr r3,r4 /* parameter */
95 mr r4,r5 /* wait result */
96 mr r1,r6 /* Load new stack pointer */
97 blrl /* Jump to the continuation */
98 mfsprg r3,1
99 b EXT(thread_terminate)
1c79356b
A
100
101/*
102 * Get the old kernel stack, and store into the thread structure.
103 * See if a continuation is supplied, and skip state save if so.
55e303ae
A
104 *
105 * Note that interrupts must be disabled before we get here (i.e., splsched)
1c79356b
A
106 */
107
b36670ce
A
108/*
109 * Switch_context(old, continuation, new)
110 *
111 * Context switches are double jumps. We pass the following to the
1c79356b
A
112 * context switch firmware call:
113 *
55e303ae 114 * R3 = switchee's savearea, virtual if continuation, low order physical for full switch
1c79356b
A
115 * R4 = old thread
116 * R5 = new SRR0
117 * R6 = new SRR1
55e303ae 118 * R7 = high order physical address of savearea for full switch
1c79356b
A
119 *
120 * savesrr0 is set to go to switch_in
121 * savesrr1 is set to uninterruptible with translation on
122 */
123
124
9bccf70c
A
125 .align 5
126 .globl EXT(Switch_context)
1c79356b 127
9bccf70c
A
128LEXT(Switch_context)
129
91447636 130 lwz r12,ACT_PER_PROC(r3) ; Get the per_proc block
1c79356b 131#if DEBUG
55e303ae
A
132 lwz r0,PP_ISTACKPTR(r12) ; (DEBUG/TRACE) make sure we are not
133 mr. r0,r0 ; (DEBUG/TRACE) on the interrupt
134 bne++ notonintstack ; (DEBUG/TRACE) stack
1c79356b
A
135 BREAKPOINT_TRAP
136notonintstack:
137#endif
de355530 138 lwz r8,ACT_MACT_PCB(r5) ; Get the PCB for the new guy
91447636 139 lwz r9,umwSpace(r5) ; Get user memory window address space
55e303ae 140 cmpwi cr1,r4,0 ; Remeber if there is a continuation - used waaaay down below
91447636
A
141 lwz r0,CTHREAD_SELF+0(r5) ; Pick up the user assist "word" (actually a double)
142 lwz r7,CTHREAD_SELF+4(r5) ; both halves
55e303ae 143 lwz r11,ACT_MACT_BTE(r5) ; Get BlueBox Task Environment
91447636
A
144 lwz r6,umwRelo(r5) ; Get user memory window relocation top
145 stw r12,ACT_PER_PROC(r5) ; Set per_proc in new activation
55e303ae 146 mtsprg 1,r5
91447636 147 lwz r2,umwRelo+4(r5) ; Get user memory window relocation bottom
de355530 148
91447636
A
149 stw r0,UAW+0(r12) ; Save the assist word for the "ultra fast path"
150 stw r7,UAW+4(r12)
55e303ae 151
1c79356b
A
152 lwz r7,ACT_MACT_SPF(r5) ; Get the special flags
153
91447636
A
154 sth r9,ppUMWmp+mpSpace(r12) ; Save the space
155 stw r6,ppUMWmp+mpNestReloc(r12) ; Save top part of physical address
156 stw r2,ppUMWmp+mpNestReloc+4(r12) ; Save bottom part of physical address
9bccf70c 157 stw r11,ppbbTaskEnv(r12) ; Save the bb task env
55e303ae 158 lwz r2,traceMask(0) ; Get the enabled traces
9bccf70c 159 stw r7,spcFlags(r12) ; Set per_proc copy of the special flags
1c79356b 160 lis r0,hi16(CutTrace) ; Trace FW call
55e303ae
A
161 mr. r2,r2 ; Any tracing going on?
162 lwz r11,SAVprev+4(r8) ; Get the previous of the switchee savearea
1c79356b 163 ori r0,r0,lo16(CutTrace) ; Trace FW call
55e303ae 164 beq++ cswNoTrc ; No trace today, dude...
b36670ce
A
165
166 li r2,0x4400 ; Trace ID
167 mr r6,r11 ; Trace prev savearea
1c79356b 168 sc ; Cut trace entry of context switch
1c79356b 169
55e303ae 170cswNoTrc: lwz r2,curctx(r5) ; Grab our current context pointer
9bccf70c
A
171 lwz r10,FPUowner(r12) ; Grab the owner of the FPU
172 lwz r9,VMXowner(r12) ; Grab the owner of the vector
55e303ae
A
173 mfmsr r6 ; Get the MSR because the switched to thread should inherit it
174 stw r11,ACT_MACT_PCB(r5) ; Dequeue the savearea we are switching to
175 li r0,1 ; Get set to hold off quickfret
176
177 rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off the FP
9bccf70c
A
178 cmplw r10,r2 ; Do we have the live float context?
179 lwz r10,FPUlevel(r2) ; Get the live level
55e303ae 180 mr r4,r3 ; Save our old thread to pass back
9bccf70c 181 cmplw cr5,r9,r2 ; Do we have the live vector context?
55e303ae
A
182 rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off the vector
183 stw r0,holdQFret(r12) ; Make sure we hold off releasing quickfret
184 bne++ cswnofloat ; Float is not ours...
9bccf70c
A
185
186 cmplw r10,r11 ; Is the level the same?
91447636 187 lhz r0,PP_CPU_NUMBER(r12) ; Get our CPU number
9bccf70c 188 lwz r5,FPUcpu(r2) ; Get the owning cpu
55e303ae 189 bne++ cswnofloat ; Level not the same, this is not live...
9bccf70c
A
190
191 cmplw r5,r0 ; Still owned by this cpu?
b36670ce 192 lwz r10,FPUsave(r2) ; Get the pointer to next saved context
55e303ae 193 bne++ cswnofloat ; CPU claimed by someone else...
9bccf70c
A
194
195 mr. r10,r10 ; Is there a savearea here?
196 ori r6,r6,lo16(MASK(MSR_FP)) ; Enable floating point
197
55e303ae 198 beq-- cswnofloat ; No savearea to check...
9bccf70c
A
199
200 lwz r3,SAVlevel(r10) ; Get the level
55e303ae 201 lwz r5,SAVprev+4(r10) ; Get the previous of this savearea
9bccf70c
A
202 cmplw r3,r11 ; Is it for the current level?
203
55e303ae 204 bne++ cswnofloat ; Nope...
9bccf70c
A
205
206 stw r5,FPUsave(r2) ; Pop off this savearea
55e303ae
A
207
208 rlwinm r3,r10,0,0,19 ; Move back to start of page
209
210 lwz r5,quickfret(r12) ; Get the first in quickfret list (top)
211 lwz r9,quickfret+4(r12) ; Get the first in quickfret list (bottom)
212 lwz r7,SACvrswap(r3) ; Get the virtual to real conversion (top)
213 lwz r3,SACvrswap+4(r3) ; Get the virtual to real conversion (bottom)
214 stw r5,SAVprev(r10) ; Link the old in (top)
215 stw r9,SAVprev+4(r10) ; Link the old in (bottom)
216 xor r3,r10,r3 ; Convert to physical
217 stw r7,quickfret(r12) ; Set the first in quickfret list (top)
218 stw r3,quickfret+4(r12) ; Set the first in quickfret list (bottom)
9bccf70c
A
219
220#if FPVECDBG
221 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
55e303ae 222 mr r7,r2 ; (TEST/DEBUG)
9bccf70c
A
223 li r2,0x4401 ; (TEST/DEBUG)
224 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
225 sc ; (TEST/DEBUG)
226 lhz r0,PP_CPU_NUMBER(r12) ; (TEST/DEBUG)
55e303ae 227 mr r2,r7 ; (TEST/DEBUG)
9bccf70c
A
228#endif
229
55e303ae 230cswnofloat: bne++ cr5,cswnovect ; Vector is not ours...
9bccf70c
A
231
232 lwz r10,VMXlevel(r2) ; Get the live level
233
234 cmplw r10,r11 ; Is the level the same?
91447636 235 lhz r0,PP_CPU_NUMBER(r12) ; Get our CPU number
9bccf70c 236 lwz r5,VMXcpu(r2) ; Get the owning cpu
55e303ae 237 bne++ cswnovect ; Level not the same, this is not live...
9bccf70c
A
238
239 cmplw r5,r0 ; Still owned by this cpu?
240 lwz r10,VMXsave(r2) ; Get the level
55e303ae 241 bne++ cswnovect ; CPU claimed by someone else...
9bccf70c
A
242
243 mr. r10,r10 ; Is there a savearea here?
244 oris r6,r6,hi16(MASK(MSR_VEC)) ; Enable vector
245
55e303ae 246 beq-- cswnovect ; No savearea to check...
9bccf70c
A
247
248 lwz r3,SAVlevel(r10) ; Get the level
55e303ae 249 lwz r5,SAVprev+4(r10) ; Get the previous of this savearea
9bccf70c
A
250 cmplw r3,r11 ; Is it for the current level?
251
55e303ae 252 bne++ cswnovect ; Nope...
9bccf70c
A
253
254 stw r5,VMXsave(r2) ; Pop off this savearea
55e303ae
A
255 rlwinm r3,r10,0,0,19 ; Move back to start of page
256
257 lwz r5,quickfret(r12) ; Get the first in quickfret list (top)
258 lwz r9,quickfret+4(r12) ; Get the first in quickfret list (bottom)
259 lwz r2,SACvrswap(r3) ; Get the virtual to real conversion (top)
260 lwz r3,SACvrswap+4(r3) ; Get the virtual to real conversion (bottom)
261 stw r5,SAVprev(r10) ; Link the old in (top)
262 stw r9,SAVprev+4(r10) ; Link the old in (bottom)
263 xor r3,r10,r3 ; Convert to physical
264 stw r2,quickfret(r12) ; Set the first in quickfret list (top)
265 stw r3,quickfret+4(r12) ; Set the first in quickfret list (bottom)
9bccf70c
A
266
267#if FPVECDBG
268 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
269 li r2,0x4501 ; (TEST/DEBUG)
270 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
271 sc ; (TEST/DEBUG)
272#endif
273
55e303ae
A
274cswnovect: li r0,0 ; Get set to release quickfret holdoff
275 rlwinm r11,r8,0,0,19 ; Switch to savearea base
276 lis r9,hi16(EXT(switch_in)) ; Get top of switch in routine
277 lwz r5,savesrr0+4(r8) ; Set up the new SRR0
b36670ce
A
278;
279; Note that the low-level code requires the R7 contain the high order half of the savearea's
280; physical address. This is hack city, but it is the way it is.
281;
55e303ae
A
282 lwz r7,SACvrswap(r11) ; Get the high order V to R translation
283 lwz r11,SACvrswap+4(r11) ; Get the low order V to R translation
284 ori r9,r9,lo16(EXT(switch_in)) ; Bottom half of switch in
285 stw r0,holdQFret(r12) ; Make sure we release quickfret holdoff
286 stw r9,savesrr0+4(r8) ; Make us jump to the switch in routine
9bccf70c 287
55e303ae 288 lwz r9,SAVflags(r8) /* Get the flags */
9bccf70c 289 lis r0,hi16(SwitchContextCall) /* Top part of switch context */
91447636 290 li r10,(MASK(MSR_ME)|MASK(MSR_DR)) /* Get the switcher's MSR */
de355530 291 ori r0,r0,lo16(SwitchContextCall) /* Bottom part of switch context */
55e303ae
A
292 stw r10,savesrr1+4(r8) /* Set up for switch in */
293 rlwinm r9,r9,0,15,13 /* Reset the syscall flag */
294 xor r3,r11,r8 /* Get the physical address of the new context save area */
1c79356b 295 stw r9,SAVflags(r8) /* Set the flags */
9bccf70c
A
296
297 bne cr1,swtchtocont ; Switch to the continuation
1c79356b
A
298 sc /* Switch to the new context */
299
300/* We come back here in the new thread context
301 * R4 was set to hold the old thread pointer, but switch_in will put it into
302 * R3 where it belongs.
303 */
304 blr /* Jump into the new thread */
9bccf70c
A
305
306;
307; This is where we go when a continuation is set. We are actually
308; killing off the old context of the new guy so we need to pop off
309; any float or vector states for the ditched level.
310;
311; Note that we do the same kind of thing a chkfac in hw_exceptions.s
312;
313
1c79356b 314
9bccf70c 315swtchtocont:
55e303ae
A
316
317 stw r5,savesrr0+4(r8) ; Set the pc
318 stw r6,savesrr1+4(r8) ; Set the next MSR to use
319 stw r4,saver3+4(r8) ; Make sure we pass back the old thread
320 mr r3,r8 ; Pass in the virtual address of savearea
9bccf70c
A
321
322 b EXT(exception_exit) ; Blocking on continuation, toss old context...
1c79356b
A
323
324
325
326/*
327 * All switched to threads come here first to clean up the old thread.
328 * We need to do the following contortions because we need to keep
329 * the LR clean. And because we need to manipulate the savearea chain
330 * with translation on. If we could, this should be done in lowmem_vectors
331 * before translation is turned on. But we can't, dang it!
332 *
91447636
A
333 * switch_in() runs with DR on and IR off
334 *
55e303ae 335 * R3 = switcher's savearea (32-bit virtual)
1c79356b
A
336 * saver4 = old thread in switcher's save
337 * saver5 = new SRR0 in switcher's save
338 * saver6 = new SRR1 in switcher's save
339
340
341 */
342
9bccf70c
A
343
344 .align 5
345 .globl EXT(switch_in)
346
347LEXT(switch_in)
1c79356b 348
55e303ae
A
349 lwz r4,saver4+4(r3) ; Get the old thread
350 lwz r5,saver5+4(r3) ; Get the srr0 value
351
352 mfsprg r0,2 ; Get feature flags
91447636 353 mr r9,r4 ; Get the switched from ACT
55e303ae
A
354 lwz r6,saver6+4(r3) ; Get the srr1 value
355 rlwinm. r0,r0,0,pf64Bitb,pf64Bitb ; Check for 64-bit
356 lwz r10,ACT_MACT_PCB(r9) ; Get the top PCB on the old thread
1c79356b 357
55e303ae
A
358 stw r3,ACT_MACT_PCB(r9) ; Put the new one on top
359 stw r10,SAVprev+4(r3) ; Chain on the old one
de355530 360
55e303ae 361 mr r3,r4 ; Pass back the old thread
1c79356b 362
55e303ae
A
363 mtsrr0 r5 ; Set return point
364 mtsrr1 r6 ; Set return MSR
365
366 bne++ siSixtyFour ; Go do 64-bit...
1c79356b 367
55e303ae
A
368 rfi ; Jam...
369
370siSixtyFour:
371 rfid ; Jam...
1c79356b
A
372
373/*
9bccf70c 374 * void fpu_save(facility_context ctx)
1c79356b 375 *
9bccf70c
A
376 * Note that there are some oddities here when we save a context we are using.
377 * It is really not too cool to do this, but what the hey... Anyway,
378 * we turn fpus and vecs off before we leave., The oddity is that if you use fpus after this, the
379 * savearea containing the context just saved will go away. So, bottom line is
380 * that don't use fpus until after you are done with the saved context.
1c79356b 381 */
9bccf70c
A
382 .align 5
383 .globl EXT(fpu_save)
1c79356b 384
9bccf70c
A
385LEXT(fpu_save)
386
55e303ae
A
387 lis r2,hi16(MASK(MSR_VEC)) ; Get the vector enable
388 li r12,lo16(MASK(MSR_EE)) ; Get the EE bit
389 ori r2,r2,lo16(MASK(MSR_FP)) ; Get FP
9bccf70c
A
390
391 mfmsr r0 ; Get the MSR
55e303ae
A
392 andc r0,r0,r2 ; Clear FP, VEC
393 andc r2,r0,r12 ; Clear EE
9bccf70c 394 ori r2,r2,MASK(MSR_FP) ; Enable the floating point feature for now also
9bccf70c 395 mtmsr r2 ; Set the MSR
1c79356b 396 isync
9bccf70c 397
91447636
A
398 mfsprg r6,1 ; Get the current activation
399 lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block
9bccf70c
A
400 lwz r12,FPUowner(r6) ; Get the context ID for owner
401
1c79356b 402#if FPVECDBG
9bccf70c
A
403 mr r7,r0 ; (TEST/DEBUG)
404 li r4,0 ; (TEST/DEBUG)
405 mr r10,r3 ; (TEST/DEBUG)
406 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
407 mr. r3,r12 ; (TEST/DEBUG)
408 li r2,0x6F00 ; (TEST/DEBUG)
409 li r5,0 ; (TEST/DEBUG)
55e303ae 410 beq-- noowneryet ; (TEST/DEBUG)
9bccf70c
A
411 lwz r4,FPUlevel(r12) ; (TEST/DEBUG)
412 lwz r5,FPUsave(r12) ; (TEST/DEBUG)
413
414noowneryet: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
415 sc ; (TEST/DEBUG)
416 mr r0,r7 ; (TEST/DEBUG)
417 mr r3,r10 ; (TEST/DEBUG)
1c79356b 418#endif
9bccf70c
A
419 mflr r2 ; Save the return address
420
b36670ce 421 cmplw r3,r12 ; Is the specified context live?
9bccf70c 422 lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number
b36670ce
A
423 lwz r9,FPUcpu(r3) ; Get the cpu that context was last on
424 bne-- fsret ; Nobody owns the FPU, no save required...
1c79356b 425
b36670ce
A
426 cmplw r9,r11 ; Was the context for this processor?
427 la r5,FPUsync(r3) ; Point to the sync word
428 bne-- fsret ; Facility not last used on this processor...
0b4e3aa0 429
b36670ce
A
430;
431; It looks like we need to save this one.
432;
433; First, make sure that the live context block is not mucked with while
434; we are trying to save it on out. Then we will give it the final check.
435;
436
437 lis r9,ha16(EXT(LockTimeOut)) ; Get the high part
438 mftb r8 ; Get the time now
439 lwz r9,lo16(EXT(LockTimeOut))(r9) ; Get the timeout value
440 b fssync0a ; Jump to the lock...
1c79356b 441
9bccf70c 442 .align 5
1c79356b 443
b36670ce
A
444fssync0: li r7,lgKillResv ; Get killing field
445 stwcx. r7,0,r7 ; Kill reservation
446
447fssync0a: lwz r7,0(r5) ; Sniff the lock
448 mftb r10 ; Is it time yet?
449 cmplwi cr1,r7,0 ; Is it locked?
450 sub r10,r10,r8 ; How long have we been spinning?
451 cmplw r10,r9 ; Has it been too long?
452 bgt-- fstimeout ; Way too long, panic...
453 bne-- cr1,fssync0a ; Yea, still locked so sniff harder...
454
455fssync1: lwarx r7,0,r5 ; Get the sync word
456 li r12,1 ; Get the lock
457 mr. r7,r7 ; Is it unlocked?
458 bne-- fssync0
459 stwcx. r12,0,r5 ; Store lock and test reservation
460 bne-- fssync1 ; Try again if lost reservation...
461
462 isync ; Toss speculation
463
464 lwz r12,FPUowner(r6) ; Get the context ID for owner
465 cmplw r3,r12 ; Check again if we own the FPU?
466 bne-- fsretlk ; Go unlock and return since we no longer own context
467
468 lwz r5,FPUcpu(r12) ; Get the cpu that context was last on
469 lwz r7,FPUsave(r12) ; Get the current FPU savearea for the thread
470 cmplw r5,r11 ; Is this for the same processor?
9bccf70c 471 lwz r9,FPUlevel(r12) ; Get our current level indicator
b36670ce 472 bne-- fsretlk ; Not the same processor, skip any save...
1c79356b 473
b36670ce
A
474 cmplwi r7,0 ; Have we ever saved this facility context?
475 beq-- fsneedone ; Never saved it, so go do it...
1c79356b 476
b36670ce
A
477 lwz r8,SAVlevel(r7) ; Get the level of this savearea
478 cmplw r9,r8 ; Correct level?
479 beq-- fsretlk ; The current level is already saved, bail out...
1c79356b 480
9bccf70c
A
481fsneedone: bl EXT(save_get) ; Get a savearea for the context
482
91447636
A
483 mfsprg r6,1 ; Get the current activation
484 lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block
9bccf70c
A
485 li r4,SAVfloat ; Get floating point tag
486 lwz r12,FPUowner(r6) ; Get back our thread
487 stb r4,SAVflags+2(r3) ; Mark this savearea as a float
9bccf70c 488 lwz r4,facAct(r12) ; Get the activation associated with live context
9bccf70c
A
489 lwz r8,FPUsave(r12) ; Get the current top floating point savearea
490 stw r4,SAVact(r3) ; Indicate the right activation for this context
491 lwz r9,FPUlevel(r12) ; Get our current level indicator again
492 stw r3,FPUsave(r12) ; Set this as the most current floating point context
55e303ae 493 stw r8,SAVprev+4(r3) ; And then chain this in front
1c79356b 494
9bccf70c 495 stw r9,SAVlevel(r3) ; Show level in savearea
1c79356b 496
55e303ae
A
497 bl fp_store ; save all 32 FPRs in the save area at r3
498 mtlr r2 ; Restore return
b36670ce
A
499
500fsretlk: li r7,0 ; Get the unlock value
501 eieio ; Make sure that these updates make it out
502 stw r7,FPUsync(r12) ; Unlock it
503
9bccf70c 504fsret: mtmsr r0 ; Put interrupts on if they were and floating point off
1c79356b
A
505 isync
506
507 blr
508
b36670ce
A
509fstimeout: mr r4,r5 ; Set the lock address
510 mr r5,r7 ; Set the lock word data
511 lis r3,hi16(fstimeout_str) ; Get the failed lck message
512 ori r3,r3,lo16(fstimeout_str) ; Get the failed lck message
513 bl EXT(panic)
514 BREAKPOINT_TRAP ; We die here anyway
515
516 .data
517fstimeout_str:
518 STRINGD "fpu_save: timeout on sync lock (0x%08X), value = 0x%08X\n\000"
519 .text
520
9bccf70c 521
1c79356b
A
522/*
523 * fpu_switch()
524 *
525 * Entered to handle the floating-point unavailable exception and
526 * switch fpu context
527 *
528 * This code is run in virtual address mode on with interrupts off.
529 *
530 * Upon exit, the code returns to the users context with the floating
531 * point facility turned on.
532 *
533 * ENTRY: VM switched ON
534 * Interrupts OFF
535 * State is saved in savearea pointed to by R4.
536 * All other registers are free.
537 *
538 */
539
9bccf70c
A
540 .align 5
541 .globl EXT(fpu_switch)
542
543LEXT(fpu_switch)
544
1c79356b 545#if DEBUG
1c79356b
A
546 lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter
547 ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter
548 lwz r1,0(r3)
549 addi r1,r1,1
550 stw r1,0(r3)
1c79356b
A
551#endif /* DEBUG */
552
91447636
A
553 mfsprg r17,1 ; Get the current activation
554 lwz r26,ACT_PER_PROC(r17) ; Get the per_proc block
55e303ae 555 mfmsr r19 ; Get the current MSR
1c79356b 556
9bccf70c
A
557 mr r25,r4 ; Save the entry savearea
558 lwz r22,FPUowner(r26) ; Get the thread that owns the FPU
9bccf70c 559 ori r19,r19,lo16(MASK(MSR_FP)) ; Enable the floating point feature
1c79356b 560
9bccf70c 561 mtmsr r19 ; Enable floating point instructions
1c79356b 562 isync
1c79356b 563
9bccf70c
A
564 lwz r27,ACT_MACT_PCB(r17) ; Get the current level
565 lwz r29,curctx(r17) ; Grab the current context anchor of the current thread
0b4e3aa0 566
9bccf70c
A
567; R22 has the "old" context anchor
568; R29 has the "new" context anchor
0b4e3aa0 569
1c79356b 570#if FPVECDBG
9bccf70c
A
571 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
572 li r2,0x7F01 ; (TEST/DEBUG)
573 mr r3,r22 ; (TEST/DEBUG)
574 mr r5,r29 ; (TEST/DEBUG)
575 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
576 sc ; (TEST/DEBUG)
1c79356b 577#endif
9bccf70c
A
578
579 lhz r16,PP_CPU_NUMBER(r26) ; Get the current CPU number
1c79356b 580
b36670ce
A
581 mr. r22,r22 ; See if there is any live FP status
582 la r15,FPUsync(r22) ; Point to the sync word
1c79356b 583
b36670ce 584 beq-- fsnosave ; No live context, so nothing to save...
1c79356b 585
9bccf70c 586 lwz r18,FPUcpu(r22) ; Get the last CPU we ran on
b36670ce
A
587 cmplw cr2,r22,r29 ; Are both old and new the same context?
588 lwz r30,FPUsave(r22) ; Get the top savearea
9bccf70c
A
589 cmplw r18,r16 ; Make sure we are on the right processor
590 lwz r31,FPUlevel(r22) ; Get the context level
b36670ce 591 cmplwi cr1,r30,0 ; Anything saved yet?
1c79356b 592
b36670ce 593 bne-- fsnosave ; No, not on the same processor...
9bccf70c 594
1c79356b 595;
9bccf70c
A
596; Check to see if the live context has already been saved.
597; Also check to see if all we are here just to re-enable the MSR
598; and handle specially if so.
1c79356b 599;
9bccf70c
A
600
601 cmplw r31,r27 ; See if the current and active levels are the same
602 crand cr0_eq,cr2_eq,cr0_eq ; Remember if both the levels and contexts are the same
1c79356b 603
b36670ce
A
604 beq-- fsthesame ; New and old are the same, just go enable...
605
606
607;
608; Note it turns out that on a G5, the following load has about a 50-50 chance of
609; taking a segment exception in a system that is doing heavy file I/O. We
610; make a dummy access right now in order to get that resolved before we take the lock.
611; We do not use the data returned because it may change over the lock
612;
613
614 beq-- cr1,fswsync ; Nothing saved, skip the probe attempt...
615 lwz r11,SAVlevel(r30) ; Touch the context in order to fault in the segment
616
617;
618; Make sure that the live context block is not mucked with while
619; we are trying to save it on out
620;
621
622fswsync: lis r11,ha16(EXT(LockTimeOut)) ; Get the high part
623 mftb r3 ; Get the time now
624 lwz r11,lo16(EXT(LockTimeOut))(r11) ; Get the timeout value
625 b fswsync0a ; Jump to the lock...
626
627 .align 5
628
629fswsync0: li r19,lgKillResv ; Get killing field
630 stwcx. r19,0,r19 ; Kill reservation
631
632fswsync0a: lwz r19,0(r15) ; Sniff the lock
633 mftb r18 ; Is it time yet?
634 cmplwi cr1,r19,0 ; Is it locked?
635 sub r18,r18,r3 ; How long have we been spinning?
636 cmplw r18,r11 ; Has it been too long?
637 bgt-- fswtimeout ; Way too long, panic...
638 bne-- cr1,fswsync0a ; Yea, still locked so sniff harder...
639
640fswsync1: lwarx r19,0,r15 ; Get the sync word
641 li r0,1 ; Get the lock
642 mr. r19,r19 ; Is it unlocked?
643 bne-- fswsync0
644 stwcx. r0,0,r15 ; Store lock and test reservation
645 bne-- fswsync1 ; Try again if lost reservation...
646
647 isync ; Toss speculation
9bccf70c 648
b36670ce
A
649;
650; Note that now that we have the lock, we need to check if anything changed.
651; Also note that the possible changes are limited. The context owner can
652; never change to a different thread or level although it can be invalidated.
653; A new context can not be pushed on top of us, but it can be popped. The
654; cpu indicator will always change if another processor mucked with any
655; contexts.
656;
657; It should be very rare that any of the context stuff changes across the lock.
658;
659
660 lwz r0,FPUowner(r26) ; Get the thread that owns the FPU again
661 lwz r11,FPUsave(r22) ; Get the top savearea again
662 lwz r18,FPUcpu(r22) ; Get the last CPU we ran on again
663 sub r0,r0,r22 ; Non-zero if we lost ownership, 0 if not
664 xor r11,r11,r30 ; Non-zero if saved context changed, 0 if not
665 xor r18,r18,r16 ; Non-zero if cpu changed, 0 if not
666 cmplwi cr1,r30,0 ; Is anything saved?
667 or r0,r0,r11 ; Zero only if both owner and context are unchanged
668 or. r0,r0,r18 ; Zero only if nothing has changed
669 li r3,0 ; Clear this
1c79356b 670
b36670ce
A
671 bne-- fsnosavelk ; Something has changed, so this is not ours to save...
672 beq-- cr1,fsmstsave ; There is no context saved yet...
673
9bccf70c 674 lwz r11,SAVlevel(r30) ; Get the level of top saved context
1c79356b 675
9bccf70c
A
676 cmplw r31,r11 ; Are live and saved the same?
677
1c79356b 678#if FPVECDBG
9bccf70c
A
679 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
680 li r2,0x7F02 ; (TEST/DEBUG)
b36670ce 681 mr r3,r11 ; (TEST/DEBUG)
9bccf70c
A
682 mr r5,r31 ; (TEST/DEBUG)
683 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
684 sc ; (TEST/DEBUG)
55e303ae 685 li r3,0 ; (TEST/DEBUG)
1c79356b 686#endif
9bccf70c 687
b36670ce 688 beq++ fsnosavelk ; Same level, so already saved...
1c79356b 689
9bccf70c
A
690fsmstsave: stw r3,FPUowner(r26) ; Kill the context now
691 eieio ; Make sure everyone sees it
692 bl EXT(save_get) ; Go get a savearea
55e303ae 693
b36670ce 694 lwz r12,facAct(r22) ; Get the activation associated with the context
55e303ae 695 stw r30,SAVprev+4(r3) ; Point us to the old context
9bccf70c
A
696 stw r31,SAVlevel(r3) ; Tag our level
697 li r7,SAVfloat ; Get the floating point ID
698 stw r12,SAVact(r3) ; Make sure we point to the right guy
699 stb r7,SAVflags+2(r3) ; Set that we have a floating point save area
b36670ce 700 stw r3,FPUsave(r22) ; Set this as the latest context savearea for the thread
55e303ae 701
1c79356b 702#if FPVECDBG
9bccf70c
A
703 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
704 li r2,0x7F03 ; (TEST/DEBUG)
705 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
706 sc ; (TEST/DEBUG)
1c79356b
A
707#endif
708
55e303ae 709 bl fp_store ; store all 32 FPRs
1c79356b 710
b36670ce
A
711fsnosavelk: li r7,0 ; Get the unlock value
712 eieio ; Make sure that these updates make it out
713 stw r7,FPUsync(r22) ; Unlock it.
714
1c79356b
A
715;
716; The context is all saved now and the facility is free.
717;
b36670ce 718; Check if we need to fill the registers with junk, because this level has
1c79356b
A
719; never used them before and some thieving bastard could hack the old values
720; of some thread! Just imagine what would happen if they could! Why, nothing
721; would be safe! My God! It is terrifying!
722;
b36670ce
A
723; Make sure that the live context block is not mucked with while
724; we are trying to load it up
725;
726
727fsnosave: la r15,FPUsync(r29) ; Point to the sync word
728 lis r11,ha16(EXT(LockTimeOut)) ; Get the high part
729 mftb r3 ; Get the time now
730 lwz r11,lo16(EXT(LockTimeOut))(r11) ; Get the timeout value
731 b fsnsync0a ; Jump to the lock...
732
733 .align 5
734
735fsnsync0: li r19,lgKillResv ; Get killing field
736 stwcx. r19,0,r19 ; Kill reservation
737
738fsnsync0a: lwz r19,0(r15) ; Sniff the lock
739 mftb r18 ; Is it time yet?
740 cmplwi cr1,r19,0 ; Is it locked?
741 sub r18,r18,r3 ; How long have we been spinning?
742 cmplw r18,r11 ; Has it been too long?
743 bgt-- fsntimeout ; Way too long, panic...
744 bne-- cr1,fsnsync0a ; Yea, still locked so sniff harder...
1c79356b 745
b36670ce
A
746fsnsync1: lwarx r19,0,r15 ; Get the sync word
747 li r0,1 ; Get the lock
748 mr. r19,r19 ; Is it unlocked?
749 bne-- fsnsync0 ; Unfortunately, it is locked...
750 stwcx. r0,0,r15 ; Store lock and test reservation
751 bne-- fsnsync1 ; Try again if lost reservation...
752
753 isync ; Toss speculation
0b4e3aa0 754
b36670ce 755 lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one
9bccf70c
A
756 lwz r19,FPUcpu(r29) ; Get the last CPU we ran on
757 lwz r14,FPUsave(r29) ; Point to the top of the "new" context stack
0b4e3aa0 758
9bccf70c
A
759 stw r16,FPUcpu(r29) ; Claim context for us
760 eieio
0b4e3aa0 761
1c79356b 762#if FPVECDBG
9bccf70c
A
763 lwz r13,FPUlevel(r29) ; (TEST/DEBUG)
764 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
765 li r2,0x7F04 ; (TEST/DEBUG)
766 mr r1,r15 ; (TEST/DEBUG)
767 mr r3,r14 ; (TEST/DEBUG)
768 mr r5,r13 ; (TEST/DEBUG)
769 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
770 sc ; (TEST/DEBUG)
1c79356b 771#endif
9bccf70c 772
91447636
A
773 lis r18,hi16(EXT(PerProcTable)) ; Set base PerProcTable
774 mulli r19,r19,ppeSize ; Find offset to the owner per_proc_entry
775 ori r18,r18,lo16(EXT(PerProcTable)) ; Set base PerProcTable
9bccf70c 776 li r16,FPUowner ; Displacement to float owner
91447636
A
777 add r19,r18,r19 ; Point to the owner per_proc_entry
778 lwz r19,ppe_vaddr(r19) ; Point to the owner per_proc
9bccf70c
A
779
780fsinvothr: lwarx r18,r16,r19 ; Get the owner
55e303ae
A
781 sub r0,r18,r29 ; Subtract one from the other
782 sub r11,r29,r18 ; Subtract the other from the one
783 or r11,r11,r0 ; Combine them
784 srawi r11,r11,31 ; Get a 0 if equal or -1 of not
785 and r18,r18,r11 ; Make 0 if same, unchanged if not
786 stwcx. r18,r16,r19 ; Try to invalidate it
787 bne-- fsinvothr ; Try again if there was a collision...
9bccf70c 788
55e303ae 789 cmplwi cr1,r14,0 ; Do we possibly have some context to load?
9bccf70c
A
790 la r11,savefp0(r14) ; Point to first line to bring in
791 stw r15,FPUlevel(r29) ; Set the "new" active level
792 eieio
793 stw r29,FPUowner(r26) ; Mark us as having the live context
1c79356b 794
55e303ae 795 beq++ cr1,MakeSureThatNoTerroristsCanHurtUsByGod ; No "new" context to load...
9bccf70c
A
796
797 dcbt 0,r11 ; Touch line in
798
9bccf70c 799 lwz r0,SAVlevel(r14) ; Get the level of first facility savearea
b36670ce 800 lwz r3,SAVprev+4(r14) ; Get the previous context
9bccf70c 801 cmplw r0,r15 ; Top level correct to load?
b36670ce 802 li r7,0 ; Get the unlock value
55e303ae 803 bne-- MakeSureThatNoTerroristsCanHurtUsByGod ; No, go initialize...
9bccf70c
A
804
805 stw r3,FPUsave(r29) ; Pop the context (we will toss the savearea later)
1c79356b
A
806
807#if FPVECDBG
9bccf70c
A
808 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
809 li r2,0x7F05 ; (TEST/DEBUG)
810 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
811 sc ; (TEST/DEBUG)
1c79356b
A
812#endif
813
b36670ce
A
814 eieio ; Make sure that these updates make it out
815 stw r7,FPUsync(r29) ; Unlock context now that the context save has been removed
816
55e303ae
A
817// Note this code is used both by 32- and 128-byte processors. This means six extra DCBTs
818// are executed on a 128-byte machine, but that is better than a mispredicted branch.
819
9bccf70c
A
820 la r11,savefp4(r14) ; Point to next line
821 dcbt 0,r11 ; Touch line in
1c79356b
A
822 lfd f0, savefp0(r14)
823 lfd f1,savefp1(r14)
1c79356b 824 lfd f2,savefp2(r14)
9bccf70c 825 la r11,savefp8(r14) ; Point to next line
1c79356b 826 lfd f3,savefp3(r14)
9bccf70c 827 dcbt 0,r11 ; Touch line in
1c79356b
A
828 lfd f4,savefp4(r14)
829 lfd f5,savefp5(r14)
830 lfd f6,savefp6(r14)
9bccf70c 831 la r11,savefp12(r14) ; Point to next line
1c79356b 832 lfd f7,savefp7(r14)
9bccf70c 833 dcbt 0,r11 ; Touch line in
1c79356b
A
834 lfd f8,savefp8(r14)
835 lfd f9,savefp9(r14)
836 lfd f10,savefp10(r14)
9bccf70c 837 la r11,savefp16(r14) ; Point to next line
1c79356b 838 lfd f11,savefp11(r14)
9bccf70c 839 dcbt 0,r11 ; Touch line in
1c79356b
A
840 lfd f12,savefp12(r14)
841 lfd f13,savefp13(r14)
842 lfd f14,savefp14(r14)
9bccf70c 843 la r11,savefp20(r14) ; Point to next line
1c79356b 844 lfd f15,savefp15(r14)
9bccf70c 845 dcbt 0,r11 ; Touch line in
1c79356b
A
846 lfd f16,savefp16(r14)
847 lfd f17,savefp17(r14)
848 lfd f18,savefp18(r14)
9bccf70c 849 la r11,savefp24(r14) ; Point to next line
1c79356b 850 lfd f19,savefp19(r14)
9bccf70c 851 dcbt 0,r11 ; Touch line in
1c79356b
A
852 lfd f20,savefp20(r14)
853 lfd f21,savefp21(r14)
9bccf70c 854 la r11,savefp28(r14) ; Point to next line
1c79356b
A
855 lfd f22,savefp22(r14)
856 lfd f23,savefp23(r14)
9bccf70c 857 dcbt 0,r11 ; Touch line in
1c79356b
A
858 lfd f24,savefp24(r14)
859 lfd f25,savefp25(r14)
860 lfd f26,savefp26(r14)
861 lfd f27,savefp27(r14)
862 lfd f28,savefp28(r14)
863 lfd f29,savefp29(r14)
864 lfd f30,savefp30(r14)
865 lfd f31,savefp31(r14)
866
9bccf70c
A
867 mr r3,r14 ; Get the old savearea (we popped it before)
868 bl EXT(save_ret) ; Toss it
869
55e303ae 870fsenable: lwz r8,savesrr1+4(r25) ; Get the msr of the interrupted guy
9bccf70c 871 ori r8,r8,MASK(MSR_FP) ; Enable the floating point feature
d7e50217
A
872 lwz r10,ACT_MACT_SPF(r17) ; Get the act special flags
873 lwz r11,spcFlags(r26) ; Get per_proc spec flags cause not in sync with act
1c79356b 874 oris r10,r10,hi16(floatUsed|floatCng) ; Set that we used floating point
d7e50217 875 oris r11,r11,hi16(floatUsed|floatCng) ; Set that we used floating point
9bccf70c 876 rlwinm. r0,r8,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are doing this for user state
55e303ae
A
877 stw r8,savesrr1+4(r25) ; Set the msr of the interrupted guy
878 mr r3,r25 ; Pass the virtual addres of savearea
b4c24cb9 879 beq- fsnuser ; We are not user state...
9bccf70c 880 stw r10,ACT_MACT_SPF(r17) ; Set the activation copy
d7e50217 881 stw r11,spcFlags(r26) ; Set per_proc copy
1c79356b
A
882
883fsnuser:
884#if FPVECDBG
9bccf70c
A
885 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
886 li r2,0x7F07 ; (TEST/DEBUG)
887 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
888 sc ; (TEST/DEBUG)
1c79356b 889#endif
1c79356b 890
9bccf70c 891 b EXT(exception_exit) ; Exit to the fray...
1c79356b
A
892
893/*
894 * Initialize the registers to some bogus value
895 */
896
897MakeSureThatNoTerroristsCanHurtUsByGod:
0b4e3aa0 898
1c79356b 899#if FPVECDBG
9bccf70c
A
900 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
901 li r2,0x7F06 ; (TEST/DEBUG)
902 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
903 sc ; (TEST/DEBUG)
1c79356b 904#endif
9bccf70c 905 lis r5,hi16(EXT(FloatInit)) ; Get top secret floating point init value address
b36670ce 906 li r7,0 ; Get the unlock value
9bccf70c 907 ori r5,r5,lo16(EXT(FloatInit)) ; Slam bottom
b36670ce
A
908 eieio ; Make sure that these updates make it out
909 stw r7,FPUsync(r29) ; Unlock it now that the context has been removed
910
9bccf70c
A
911 lfd f0,0(r5) ; Initialize FP0
912 fmr f1,f0 ; Do them all
1c79356b
A
913 fmr f2,f0
914 fmr f3,f0
915 fmr f4,f0
916 fmr f5,f0
917 fmr f6,f0
918 fmr f7,f0
919 fmr f8,f0
920 fmr f9,f0
921 fmr f10,f0
922 fmr f11,f0
923 fmr f12,f0
924 fmr f13,f0
925 fmr f14,f0
926 fmr f15,f0
927 fmr f16,f0
928 fmr f17,f0
1c79356b
A
929 fmr f18,f0
930 fmr f19,f0
931 fmr f20,f0
1c79356b
A
932 fmr f21,f0
933 fmr f22,f0
934 fmr f23,f0
935 fmr f24,f0
936 fmr f25,f0
937 fmr f26,f0
938 fmr f27,f0
939 fmr f28,f0
940 fmr f29,f0
941 fmr f30,f0
942 fmr f31,f0
9bccf70c
A
943 b fsenable ; Finish setting it all up...
944
1c79356b
A
945
946;
9bccf70c 947; We get here when we are switching to the same context at the same level and the context
b36670ce 948; is still live. Essentially, all we are doing is turning on the facility. It may have
9bccf70c
A
949; gotten turned off due to doing a context save for the current level or a context switch
950; back to the live guy.
1c79356b 951;
9bccf70c
A
952
953 .align 5
1c79356b 954
b36670ce
A
955
956fsthesamel: li r7,0 ; Get the unlock value
957 eieio ; Make sure that these updates make it out
958 stw r7,FPUsync(r22) ; Unlock it.
959
9bccf70c 960fsthesame:
1c79356b 961
9bccf70c
A
962#if FPVECDBG
963 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
964 li r2,0x7F0A ; (TEST/DEBUG)
965 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
966 sc ; (TEST/DEBUG)
967#endif
968 beq- cr1,fsenable ; Not saved yet, nothing to pop, go enable and exit...
1c79356b 969
9bccf70c 970 lwz r11,SAVlevel(r30) ; Get the level of top saved context
55e303ae 971 lwz r14,SAVprev+4(r30) ; Get the previous savearea
1c79356b 972
9bccf70c 973 cmplw r11,r31 ; Are live and saved the same?
1c79356b 974
b36670ce 975 bne++ fsenable ; Level not the same, nothing to pop, go enable and exit...
1c79356b 976
9bccf70c 977 mr r3,r30 ; Get the old savearea (we popped it before)
55e303ae 978 stw r14,FPUsave(r22) ; Pop the savearea from the stack
9bccf70c
A
979 bl EXT(save_ret) ; Toss it
980 b fsenable ; Go enable and exit...
981
b36670ce
A
982;
983; Note that we need to choke in this code rather than panic because there is no
984; stack.
985;
986
987fswtimeout: lis r0,hi16(Choke) ; Choke code
988 ori r0,r0,lo16(Choke) ; and the rest
989 li r3,failTimeout ; Timeout code
990 sc ; System ABEND
991
992fsntimeout: lis r0,hi16(Choke) ; Choke code
993 ori r0,r0,lo16(Choke) ; and the rest
994 li r3,failTimeout ; Timeout code
995 sc ; System ABEND
996
997vswtimeout0:
998 lis r0,hi16(Choke) ; Choke code
999 ori r0,r0,lo16(Choke) ; and the rest
1000 li r3,failTimeout ; Timeout code
1001 sc ; System ABEND
1002
1003vswtimeout1:
1004 lis r0,hi16(Choke) ; Choke code
1005 ori r0,r0,lo16(Choke) ; and the rest
1006 li r3,failTimeout ; Timeout code
1007 sc ; System ABEND
9bccf70c
A
1008
1009;
1010; This function invalidates any live floating point context for the passed in facility_context.
1011; This is intended to be called just before act_machine_sv_free tosses saveareas.
1012;
1013
1014 .align 5
1015 .globl EXT(toss_live_fpu)
1016
1017LEXT(toss_live_fpu)
1018
55e303ae 1019 lis r0,hi16(MASK(MSR_VEC)) ; Get VEC
9bccf70c 1020 mfmsr r9 ; Get the MSR
55e303ae 1021 ori r0,r0,lo16(MASK(MSR_FP)) ; Add in FP
9bccf70c 1022 rlwinm. r8,r9,0,MSR_FP_BIT,MSR_FP_BIT ; Are floats on right now?
55e303ae
A
1023 andc r9,r9,r0 ; Force off VEC and FP
1024 ori r0,r0,lo16(MASK(MSR_EE)) ; Turn off EE
1025 andc r0,r9,r0 ; Turn off EE now
9bccf70c
A
1026 mtmsr r0 ; No interruptions
1027 isync
1028 beq+ tlfnotours ; Floats off, can not be live here...
1029
91447636
A
1030 mfsprg r8,1 ; Get the current activation
1031 lwz r8,ACT_PER_PROC(r8) ; Get the per_proc block
9bccf70c
A
1032
1033;
1034; Note that at this point, since floats are on, we are the owner
1035; of live state on this processor
1c79356b 1036;
9bccf70c
A
1037
1038 lwz r6,FPUowner(r8) ; Get the thread that owns the floats
1039 li r0,0 ; Clear this just in case we need it
1040 cmplw r6,r3 ; Are we tossing our own context?
55e303ae 1041 bne-- tlfnotours ; Nope...
9bccf70c 1042
55e303ae 1043 lfd f1,Zero(0) ; Make a 0
9bccf70c
A
1044 mtfsf 0xFF,f1 ; Clear it
1045
1046tlfnotours: lwz r11,FPUcpu(r3) ; Get the cpu on which we last loaded context
91447636
A
1047 lis r12,hi16(EXT(PerProcTable)) ; Set base PerProcTable
1048 mulli r11,r11,ppeSize ; Find offset to the owner per_proc_entry
1049 ori r12,r12,lo16(EXT(PerProcTable)) ; Set base PerProcTable
9bccf70c 1050 li r10,FPUowner ; Displacement to float owner
91447636
A
1051 add r11,r12,r11 ; Point to the owner per_proc_entry
1052 lwz r11,ppe_vaddr(r11) ; Point to the owner per_proc
9bccf70c
A
1053
1054tlfinvothr: lwarx r12,r10,r11 ; Get the owner
9bccf70c 1055
55e303ae
A
1056 sub r0,r12,r3 ; Subtract one from the other
1057 sub r8,r3,r12 ; Subtract the other from the one
1058 or r8,r8,r0 ; Combine them
1059 srawi r8,r8,31 ; Get a 0 if equal or -1 of not
1060 and r12,r12,r8 ; Make 0 if same, unchanged if not
1061 stwcx. r12,r10,r11 ; Try to invalidate it
1062 bne-- tlfinvothr ; Try again if there was a collision...
1063
1064 mtmsr r9 ; Restore interruptions
9bccf70c
A
1065 isync ; Could be turning off floats here
1066 blr ; Leave...
1067
1c79356b
A
1068
1069/*
1070 * Altivec stuff is here. The techniques used are pretty identical to
1071 * the floating point. Except that we will honor the VRSAVE register
1072 * settings when loading and restoring registers.
1073 *
1074 * There are two indications of saved VRs: the VRSAVE register and the vrvalid
1075 * mask. VRSAVE is set by the vector user and represents the VRs that they
1076 * say that they are using. The vrvalid mask indicates which vector registers
1077 * are saved in the savearea. Whenever context is saved, it is saved according
1078 * to the VRSAVE register. It is loaded based on VRSAVE anded with
1079 * vrvalid (all other registers are splatted with 0s). This is done because we
1080 * don't want to load any registers we don't have a copy of, we want to set them
1081 * to zero instead.
1082 *
9bccf70c
A
1083 * Note that there are some oddities here when we save a context we are using.
1084 * It is really not too cool to do this, but what the hey... Anyway,
1085 * we turn vectors and fpu off before we leave.
1086 * The oddity is that if you use vectors after this, the
1087 * savearea containing the context just saved will go away. So, bottom line is
1088 * that don't use vectors until after you are done with the saved context.
1089 *
1c79356b
A
1090 */
1091
9bccf70c
A
1092 .align 5
1093 .globl EXT(vec_save)
1094
1095LEXT(vec_save)
1c79356b 1096
55e303ae
A
1097
1098 lis r2,hi16(MASK(MSR_VEC)) ; Get VEC
9bccf70c 1099 mfmsr r0 ; Get the MSR
55e303ae
A
1100 ori r2,r2,lo16(MASK(MSR_FP)) ; Add in FP
1101 andc r0,r0,r2 ; Force off VEC and FP
1102 ori r2,r2,lo16(MASK(MSR_EE)) ; Clear EE
1103 andc r2,r0,r2 ; Clear EE for now
9bccf70c 1104 oris r2,r2,hi16(MASK(MSR_VEC)) ; Enable the vector facility for now also
9bccf70c 1105 mtmsr r2 ; Set the MSR
1c79356b
A
1106 isync
1107
91447636
A
1108 mfsprg r6,1 ; Get the current activation
1109 lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block
9bccf70c
A
1110 lwz r12,VMXowner(r6) ; Get the context ID for owner
1111
1c79356b 1112#if FPVECDBG
b36670ce 1113 mr r11,r6 ; (TEST/DEBUG)
9bccf70c
A
1114 mr r7,r0 ; (TEST/DEBUG)
1115 li r4,0 ; (TEST/DEBUG)
1116 mr r10,r3 ; (TEST/DEBUG)
1117 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1118 mr. r3,r12 ; (TEST/DEBUG)
1119 li r2,0x5F00 ; (TEST/DEBUG)
1120 li r5,0 ; (TEST/DEBUG)
b36670ce
A
1121 lwz r6,liveVRS(r6) ; (TEST/DEBUG)
1122 beq-- noowneryeu ; (TEST/DEBUG)
9bccf70c
A
1123 lwz r4,VMXlevel(r12) ; (TEST/DEBUG)
1124 lwz r5,VMXsave(r12) ; (TEST/DEBUG)
1125
1126noowneryeu: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1127 sc ; (TEST/DEBUG)
1128 mr r0,r7 ; (TEST/DEBUG)
1129 mr r3,r10 ; (TEST/DEBUG)
b36670ce 1130 mr r6,r11 ; (TEST/DEBUG)
1c79356b 1131#endif
9bccf70c
A
1132 mflr r2 ; Save the return address
1133
b36670ce 1134 cmplw r3,r12 ; Is the specified context live?
9bccf70c 1135 lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number
b36670ce 1136 bne-- vsret ; We do not own the vector, no save required...
9bccf70c 1137 lwz r9,VMXcpu(r12) ; Get the cpu that context was last on
9bccf70c 1138
b36670ce
A
1139 cmplw r9,r11 ; Was the context for this processor?
1140 la r5,VMXsync(r3) ; Point to the sync word
1141 bne-- vsret ; Specified context is not live
9bccf70c 1142
b36670ce
A
1143;
1144; It looks like we need to save this one. Or possibly toss a saved one if
1145; the VRSAVE is 0.
1146;
1147; First, make sure that the live context block is not mucked with while
1148; we are trying to save it on out. Then we will give it the final check.
1149;
1150
1151 lis r9,ha16(EXT(LockTimeOut)) ; Get the high part
1152 mftb r8 ; Get the time now
1153 lwz r9,lo16(EXT(LockTimeOut))(r9) ; Get the timeout value
1154 b vssync0a ; Jump to the lock...
9bccf70c
A
1155
1156 .align 5
1157
b36670ce
A
1158vssync0: li r7,lgKillResv ; Get killing field
1159 stwcx. r7,0,r7 ; Kill reservation
1160
1161vssync0a: lwz r7,0(r5) ; Sniff the lock
1162 mftb r10 ; Is it time yet?
1163 cmplwi cr1,r7,0 ; Is it locked?
1164 sub r10,r10,r8 ; How long have we been spinning?
1165 cmplw r10,r9 ; Has it been too long?
1166 bgt-- vswtimeout0 ; Way too long, panic...
1167 bne-- cr1,vssync0a ; Yea, still locked so sniff harder...
1168
1169vssync1: lwarx r7,0,r5 ; Get the sync word
1170 li r12,1 ; Get the lock
1171 mr. r7,r7 ; Is it unlocked?
1172 bne-- vssync0 ; No, it is unlocked...
1173 stwcx. r12,0,r5 ; Store lock and test reservation
1174 bne-- vssync1 ; Try again if lost reservation...
1175
1176 isync ; Toss speculation
1177
1178 lwz r12,VMXowner(r6) ; Get the context ID for owner
1179 cmplw r3,r12 ; Check again if we own VMX?
9bccf70c 1180 lwz r10,liveVRS(r6) ; Get the right VRSave register
b36670ce 1181 bne-- vsretlk ; Go unlock and return since we no longer own context
9bccf70c 1182
b36670ce
A
1183 lwz r5,VMXcpu(r12) ; Get the cpu that context was last on
1184 lwz r7,VMXsave(r12) ; Get the current vector savearea for the thread
1185 cmplwi cr1,r10,0 ; Is VRsave set to 0?
1186 cmplw r5,r11 ; Is this for the same processor?
1187 lwz r9,VMXlevel(r12) ; Get our current level indicator
1188 bne-- vsretlk ; Not the same processor, skip any save...
9bccf70c 1189
b36670ce
A
1190 cmplwi r7,0 ; Have we ever saved this facility context?
1191 beq-- vsneedone ; Never saved it, so we need an area...
9bccf70c 1192
b36670ce
A
1193 lwz r8,SAVlevel(r7) ; Get the level this savearea is for
1194 cmplw r9,r8 ; Correct level?
1195 bne-- vsneedone ; Different level, so we need to save...
1c79356b 1196
b36670ce 1197 bne++ cr1,vsretlk ; VRsave is non-zero so we need to keep what is saved...
0b4e3aa0 1198
b36670ce
A
1199 lwz r4,SAVprev+4(r7) ; Pick up the previous area
1200 li r5,0 ; Assume we just dumped the last
1201 mr. r4,r4 ; Is there one?
9bccf70c 1202 stw r4,VMXsave(r12) ; Dequeue this savearea
b36670ce
A
1203 beq-- vsnomore ; We do not have another...
1204
1205 lwz r5,SAVlevel(r4) ; Get the level associated with save
1206
1207vsnomore: stw r5,VMXlevel(r12) ; Save the level
1208 li r7,0 ; Clear
1209 stw r7,VMXowner(r6) ; Show no live context here
9bccf70c 1210
55e303ae 1211vsbackout: mr r4,r0 ; restore the saved MSR
b36670ce
A
1212 eieio
1213 stw r7,VMXsync(r12) ; Unlock the context
1214
55e303ae 1215 b EXT(save_ret_wMSR) ; Toss the savearea and return from there...
9bccf70c
A
1216
1217 .align 5
1218
b36670ce 1219vsneedone: beq-- cr1,vsclrlive ; VRSave is zero, go blow away the context...
9bccf70c
A
1220
1221 bl EXT(save_get) ; Get a savearea for the context
1222
91447636
A
1223 mfsprg r6,1 ; Get the current activation
1224 lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block
9bccf70c
A
1225 li r4,SAVvector ; Get vector tag
1226 lwz r12,VMXowner(r6) ; Get back our context ID
1227 stb r4,SAVflags+2(r3) ; Mark this savearea as a vector
1228 mr. r12,r12 ; See if we were disowned while away. Very, very small chance of it...
b36670ce
A
1229 li r7,0 ; Clear
1230 beq-- vsbackout ; If disowned, just toss savearea...
9bccf70c 1231 lwz r4,facAct(r12) ; Get the activation associated with live context
9bccf70c
A
1232 lwz r8,VMXsave(r12) ; Get the current top vector savearea
1233 stw r4,SAVact(r3) ; Indicate the right activation for this context
1234 lwz r9,VMXlevel(r12) ; Get our current level indicator again
1235 stw r3,VMXsave(r12) ; Set this as the most current floating point context
55e303ae 1236 stw r8,SAVprev+4(r3) ; And then chain this in front
9bccf70c
A
1237
1238 stw r9,SAVlevel(r3) ; Set level in savearea
55e303ae
A
1239 mfcr r12 ; save CRs across call to vr_store
1240 lwz r10,liveVRS(r6) ; Get the right VRSave register
1241
1242 bl vr_store ; store live VRs into savearea as required (uses r4-r11)
9bccf70c 1243
b36670ce 1244 mfsprg r6,1 ; Get the current activation
55e303ae 1245 mtcrf 255,r12 ; Restore the non-volatile CRs
b36670ce
A
1246 lwz r6,ACT_PER_PROC(r6) ; Get the per_proc block
1247 mtlr r2 ; Restore return address
1248 lwz r12,VMXowner(r6) ; Get back our context ID
1249
1250vsretlk: li r7,0 ; Get the unlock value
1251 eieio ; Make sure that these updates make it out
1252 stw r7,VMXsync(r12) ; Unlock it
55e303ae
A
1253
1254vsret: mtmsr r0 ; Put interrupts on if they were and vector off
1c79356b
A
1255 isync
1256
1257 blr
1258
b36670ce
A
1259vsclrlive: li r7,0 ; Clear
1260 stw r7,VMXowner(r6) ; Show no live context here
1261 b vsretlk ; Go unlock and leave...
1262
1c79356b
A
1263/*
1264 * vec_switch()
1265 *
1266 * Entered to handle the vector unavailable exception and
1267 * switch vector context
1268 *
1269 * This code is run with virtual address mode on and interrupts off.
1270 *
1271 * Upon exit, the code returns to the users context with the vector
1272 * facility turned on.
1273 *
1274 * ENTRY: VM switched ON
1275 * Interrupts OFF
1276 * State is saved in savearea pointed to by R4.
1277 * All other registers are free.
1278 *
1279 */
1280
9bccf70c
A
1281 .align 5
1282 .globl EXT(vec_switch)
1283
1284LEXT(vec_switch)
1c79356b
A
1285
1286#if DEBUG
1c79356b
A
1287 lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter
1288 ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter
1289 lwz r1,0(r3)
1290 addi r1,r1,1
1291 stw r1,0(r3)
1c79356b
A
1292#endif /* DEBUG */
1293
91447636
A
1294 mfsprg r17,1 ; Get the current activation
1295 lwz r26,ACT_PER_PROC(r17) ; Get the per_proc block
55e303ae 1296 mfmsr r19 ; Get the current MSR
1c79356b 1297
9bccf70c 1298 mr r25,r4 ; Save the entry savearea
9bccf70c 1299 oris r19,r19,hi16(MASK(MSR_VEC)) ; Enable the vector feature
55e303ae 1300 lwz r22,VMXowner(r26) ; Get the thread that owns the vector
9bccf70c
A
1301
1302 mtmsr r19 ; Enable vector instructions
1c79356b
A
1303 isync
1304
9bccf70c
A
1305 lwz r27,ACT_MACT_PCB(r17) ; Get the current level
1306 lwz r29,curctx(r17) ; Grab the current context anchor of the current thread
0b4e3aa0 1307
9bccf70c
A
1308; R22 has the "old" context anchor
1309; R29 has the "new" context anchor
0b4e3aa0 1310
1c79356b 1311#if FPVECDBG
9bccf70c
A
1312 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1313 li r2,0x5F01 ; (TEST/DEBUG)
1314 mr r3,r22 ; (TEST/DEBUG)
1315 mr r5,r29 ; (TEST/DEBUG)
b36670ce 1316 lwz r6,liveVRS(r26) ; (TEST/DEBUG)
9bccf70c
A
1317 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1318 sc ; (TEST/DEBUG)
1c79356b
A
1319#endif
1320
9bccf70c 1321 lhz r16,PP_CPU_NUMBER(r26) ; Get the current CPU number
1c79356b 1322
b36670ce
A
1323 mr. r22,r22 ; See if there is any live vector status
1324 la r15,VMXsync(r22) ; Point to the sync word
1c79356b 1325
b36670ce 1326 beq-- vswnosave ; No live context, so nothing to save...
1c79356b 1327
9bccf70c 1328 lwz r18,VMXcpu(r22) ; Get the last CPU we ran on
b36670ce
A
1329 cmplw cr2,r22,r29 ; Are both old and new the same context?
1330 lwz r30,VMXsave(r22) ; Get the top savearea
9bccf70c 1331 cmplwi cr1,r30,0 ; Anything saved yet?
9bccf70c 1332 lwz r31,VMXlevel(r22) ; Get the context level
b36670ce 1333 cmplw r18,r16 ; Make sure we are on the right processor
1c79356b 1334
9bccf70c
A
1335 lwz r10,liveVRS(r26) ; Get the right VRSave register
1336
b36670ce 1337 bne-- vswnosave ; No, not on the same processor...
9bccf70c 1338
1c79356b 1339;
9bccf70c
A
1340; Check to see if the live context has already been saved.
1341; Also check to see if all we are here just to re-enable the MSR
1342; and handle specially if so.
1c79356b 1343;
9bccf70c
A
1344
1345 cmplw r31,r27 ; See if the current and active levels are the same
b36670ce
A
1346 crand cr0_eq,cr2_eq,cr0_eq ; Remember if both the levels and contexts are the same
1347
1348 beq-- vswthesame ; New and old are the same, just go enable...
1349
1350;
1351; Make sure that the live context block is not mucked with while
1352; we are trying to save it on out
1353;
1354
1355 lis r11,ha16(EXT(LockTimeOut)) ; Get the high part
1356 mftb r3 ; Get the time now
1357 lwz r11,lo16(EXT(LockTimeOut))(r11) ; Get the timeout value
1358 b vswsync0a ; Jump to the lock...
1359
1360 .align 5
1c79356b 1361
b36670ce
A
1362vswsync0: li r19,lgKillResv ; Get killing field
1363 stwcx. r19,0,r19 ; Kill reservation
1364
1365vswsync0a: lwz r19,0(r15) ; Sniff the lock
1366 mftb r18 ; Is it time yet?
1367 cmplwi cr1,r19,0 ; Is it locked?
1368 sub r18,r18,r3 ; How long have we been spinning?
1369 cmplw r18,r11 ; Has it been too long?
1370 bgt-- vswtimeout0 ; Way too long, panic...
1371 bne-- cr1,vswsync0a ; Yea, still locked so sniff harder...
1372
1373vswsync1: lwarx r19,0,r15 ; Get the sync word
1374 li r0,1 ; Get the lock
1375 mr. r19,r19 ; Is it unlocked?
1376 bne-- vswsync0
1377 stwcx. r0,0,r15 ; Store lock and test reservation
1378 bne-- vswsync1 ; Try again if lost reservation...
1379
1380 isync ; Toss speculation
1381
1382;
1383; Note that now that we have the lock, we need to check if anything changed.
1384; Also note that the possible changes are limited. The context owner can
1385; never change to a different thread or level although it can be invalidated.
1386; A new context can not be pushed on top of us, but it can be popped. The
1387; cpu indicator will always change if another processor mucked with any
1388; contexts.
1389;
1390; It should be very rare that any of the context stuff changes across the lock.
1391;
9bccf70c 1392
b36670ce
A
1393 lwz r0,VMXowner(r26) ; Get the thread that owns the vectors again
1394 lwz r11,VMXsave(r22) ; Get the top savearea again
1395 lwz r18,VMXcpu(r22) ; Get the last CPU we ran on again
1396 sub r0,r0,r22 ; Non-zero if we lost ownership, 0 if not
1397 xor r11,r11,r30 ; Non-zero if saved context changed, 0 if not
1398 xor r18,r18,r16 ; Non-zero if cpu changed, 0 if not
1399 cmplwi cr1,r30,0 ; Is anything saved?
1400 or r0,r0,r11 ; Zero only if both owner and context are unchanged
1401 or. r0,r0,r18 ; Zero only if nothing has changed
9bccf70c 1402 cmplwi cr2,r10,0 ; Check VRSave to see if we really need to save anything...
b36670ce
A
1403 li r8,0 ; Clear
1404
1405 bne-- vswnosavelk ; Something has changed, so this is not ours to save...
1406 beq-- cr1,vswmstsave ; There is no context saved yet...
1c79356b 1407
9bccf70c 1408 lwz r11,SAVlevel(r30) ; Get the level of top saved context
1c79356b 1409
9bccf70c
A
1410 cmplw r31,r11 ; Are live and saved the same?
1411
1c79356b 1412#if FPVECDBG
9bccf70c
A
1413 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1414 li r2,0x5F02 ; (TEST/DEBUG)
1415 mr r3,r30 ; (TEST/DEBUG)
1416 mr r5,r31 ; (TEST/DEBUG)
1417 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1418 sc ; (TEST/DEBUG)
1c79356b 1419#endif
9bccf70c 1420
b36670ce
A
1421 beq++ vswnosavelk ; Same level, already saved...
1422 bne-- cr2,vswnosavelk ; Live context saved and VRSave not 0, no save and keep context...
1c79356b 1423
55e303ae 1424 lwz r4,SAVprev+4(r30) ; Pick up the previous area
9bccf70c
A
1425 li r5,0 ; Assume this is the only one (which should be the ususal case)
1426 mr. r4,r4 ; Was this the only one?
1427 stw r4,VMXsave(r22) ; Dequeue this savearea
b36670ce 1428 beq++ vswonlyone ; This was the only one...
9bccf70c
A
1429 lwz r5,SAVlevel(r4) ; Get the level associated with previous save
1430
b36670ce 1431vswonlyone: stw r5,VMXlevel(r22) ; Save the level
9bccf70c 1432 stw r8,VMXowner(r26) ; Clear owner
b36670ce 1433
9bccf70c
A
1434 mr r3,r30 ; Copy the savearea we are tossing
1435 bl EXT(save_ret) ; Toss the savearea
b36670ce 1436 b vswnosavelk ; Go load up the context...
9bccf70c
A
1437
1438 .align 5
1c79356b 1439
b36670ce
A
1440vswmstsave: stw r8,VMXowner(r26) ; Clear owner
1441 beq-- cr2,vswnosavelk ; The VRSave was 0, so there is nothing to save...
9bccf70c
A
1442
1443 bl EXT(save_get) ; Go get a savearea
1444
b36670ce 1445 lwz r12,facAct(r22) ; Get the activation associated with the context
55e303ae 1446 stw r3,VMXsave(r22) ; Set this as the latest context savearea for the thread
55e303ae 1447 stw r30,SAVprev+4(r3) ; Point us to the old context
9bccf70c
A
1448 stw r31,SAVlevel(r3) ; Tag our level
1449 li r7,SAVvector ; Get the vector ID
1450 stw r12,SAVact(r3) ; Make sure we point to the right guy
1451 stb r7,SAVflags+2(r3) ; Set that we have a vector save area
1c79356b 1452
1c79356b 1453#if FPVECDBG
9bccf70c
A
1454 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1455 li r2,0x5F03 ; (TEST/DEBUG)
1456 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1457 sc ; (TEST/DEBUG)
1c79356b
A
1458#endif
1459
9bccf70c 1460 lwz r10,liveVRS(r26) ; Get the right VRSave register
55e303ae 1461 bl vr_store ; store VRs into savearea according to vrsave (uses r4-r11)
1c79356b 1462
9bccf70c
A
1463;
1464; The context is all saved now and the facility is free.
1465;
b36670ce 1466; Check if we need to fill the registers with junk, because this level has
9bccf70c
A
1467; never used them before and some thieving bastard could hack the old values
1468; of some thread! Just imagine what would happen if they could! Why, nothing
1469; would be safe! My God! It is terrifying!
1470;
1471; Also, along the way, thanks to Ian Ollmann, we generate the 0x7FFFDEAD (QNaNbarbarian)
1472; constant that we may need to fill unused vector registers.
1473;
b36670ce
A
1474; Make sure that the live context block is not mucked with while
1475; we are trying to load it up
1476;
1c79356b 1477
b36670ce
A
1478vswnosavelk:
1479 li r7,0 ; Get the unlock value
1480 eieio ; Make sure that these updates make it out
1481 stw r7,VMXsync(r22) ; Unlock the old context
1482
1483vswnosave: la r15,VMXsync(r29) ; Point to the sync word
1484 lis r11,ha16(EXT(LockTimeOut)) ; Get the high part
1485 mftb r3 ; Get the time now
1486 lwz r11,lo16(EXT(LockTimeOut))(r11) ; Get the timeout value
1487 b vswnsync0a ; Jump to the lock...
1488
1489 .align 5
1490
1491vswnsync0: li r19,lgKillResv ; Get killing field
1492 stwcx. r19,0,r19 ; Kill reservation
0b4e3aa0 1493
b36670ce
A
1494vswnsync0a: lwz r19,0(r15) ; Sniff the lock
1495 mftb r18 ; Is it time yet?
1496 cmplwi cr1,r19,0 ; Is it locked?
1497 sub r18,r18,r3 ; How long have we been spinning?
1498 cmplw r18,r11 ; Has it been too long?
1499 bgt-- vswtimeout1 ; Way too long, panic...
1500 bne-- cr1,vswnsync0a ; Yea, still locked so sniff harder...
0b4e3aa0 1501
b36670ce
A
1502vswnsync1: lwarx r19,0,r15 ; Get the sync word
1503 li r0,1 ; Get the lock
1504 mr. r19,r19 ; Is it unlocked?
1505 bne-- vswnsync0 ; Unfortunately, it is locked...
1506 stwcx. r0,0,r15 ; Store lock and test reservation
1507 bne-- vswnsync1 ; Try again if lost reservation...
1508
1509 isync ; Toss speculation
0b4e3aa0 1510
b36670ce 1511 vspltisb v31,-10 ; Get 0xF6F6F6F6
9bccf70c
A
1512 lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one
1513 vspltisb v30,5 ; Get 0x05050505
1514 lwz r19,VMXcpu(r29) ; Get the last CPU we ran on
1515 vspltish v29,4 ; Get 0x00040004
1516 lwz r14,VMXsave(r29) ; Point to the top of the "new" context stack
1517 vrlb v31,v31,v30 ; Get 0xDEDEDEDE
1518
1519 stw r16,VMXcpu(r29) ; Claim context for us
1520 eieio
1c79356b
A
1521
1522#if FPVECDBG
9bccf70c
A
1523 lwz r13,VMXlevel(r29) ; (TEST/DEBUG)
1524 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1525 li r2,0x5F04 ; (TEST/DEBUG)
1526 mr r1,r15 ; (TEST/DEBUG)
1527 mr r3,r14 ; (TEST/DEBUG)
1528 mr r5,r13 ; (TEST/DEBUG)
1529 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1530 sc ; (TEST/DEBUG)
1c79356b 1531#endif
9bccf70c 1532
91447636 1533 lis r18,hi16(EXT(PerProcTable)) ; Set base PerProcTable
9bccf70c 1534 vspltisb v28,-2 ; Get 0xFEFEFEFE
91447636 1535 mulli r19,r19,ppeSize ; Find offset to the owner per_proc_entry
9bccf70c 1536 vsubuhm v31,v31,v29 ; Get 0xDEDADEDA
91447636 1537 ori r18,r18,lo16(EXT(PerProcTable)) ; Set base PerProcTable
9bccf70c
A
1538 vpkpx v30,v28,v3 ; Get 0x7FFF7FFF
1539 li r16,VMXowner ; Displacement to vector owner
91447636
A
1540 add r19,r18,r19 ; Point to the owner per_proc_entry
1541 lwz r19,ppe_vaddr(r19) ; Point to the owner per_proc
9bccf70c 1542 vrlb v31,v31,v29 ; Get 0xDEADDEAD
9bccf70c 1543
b36670ce 1544vswinvothr: lwarx r18,r16,r19 ; Get the owner
55e303ae
A
1545
1546 sub r0,r18,r29 ; Subtract one from the other
1547 sub r11,r29,r18 ; Subtract the other from the one
1548 or r11,r11,r0 ; Combine them
1549 srawi r11,r11,31 ; Get a 0 if equal or -1 of not
1550 and r18,r18,r11 ; Make 0 if same, unchanged if not
1551 stwcx. r18,r16,r19 ; Try to invalidate it
b36670ce 1552 bne-- vswinvothr ; Try again if there was a collision...
9bccf70c 1553
55e303ae 1554 cmplwi cr1,r14,0 ; Do we possibly have some context to load?
9bccf70c
A
1555 vmrghh v31,v30,v31 ; Get 0x7FFFDEAD. V31 keeps this value until the bitter end
1556 stw r15,VMXlevel(r29) ; Set the "new" active level
1557 eieio
1558 stw r29,VMXowner(r26) ; Mark us as having the live context
1c79356b 1559
55e303ae 1560 beq-- cr1,ProtectTheAmericanWay ; Nothing to restore, first time use...
9bccf70c 1561
55e303ae 1562 lwz r3,SAVprev+4(r14) ; Get the previous context
9bccf70c
A
1563 lwz r0,SAVlevel(r14) ; Get the level of first facility savearea
1564 cmplw r0,r15 ; Top level correct to load?
55e303ae 1565 bne-- ProtectTheAmericanWay ; No, go initialize...
1c79356b 1566
9bccf70c
A
1567 stw r3,VMXsave(r29) ; Pop the context (we will toss the savearea later)
1568
1c79356b 1569#if FPVECDBG
9bccf70c
A
1570 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1571 li r2,0x5F05 ; (TEST/DEBUG)
1572 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1573 sc ; (TEST/DEBUG)
1c79356b
A
1574#endif
1575
de355530 1576 lwz r10,savevrvalid(r14) ; Get the valid VRs in the savearea
55e303ae 1577 lwz r22,savevrsave(r25) ; Get the most current VRSAVE
9bccf70c 1578 and r10,r10,r22 ; Figure out just what registers need to be loaded
55e303ae
A
1579 mr r3,r14 ; r3 <- ptr to savearea with VRs
1580 bl vr_load ; load VRs from save area based on vrsave in r10
1581
1582 bl EXT(save_ret) ; Toss the save area after loading VRs
b36670ce
A
1583
1584vrenablelk: li r7,0 ; Get the unlock value
1585 eieio ; Make sure that these updates make it out
1586 stw r7,VMXsync(r29) ; Unlock the new context
de355530 1587
55e303ae 1588vrenable: lwz r8,savesrr1+4(r25) ; Get the msr of the interrupted guy
9bccf70c 1589 oris r8,r8,hi16(MASK(MSR_VEC)) ; Enable the vector facility
d7e50217
A
1590 lwz r10,ACT_MACT_SPF(r17) ; Get the act special flags
1591 lwz r11,spcFlags(r26) ; Get per_proc spec flags cause not in sync with act
1c79356b 1592 oris r10,r10,hi16(vectorUsed|vectorCng) ; Set that we used vectors
d7e50217 1593 oris r11,r11,hi16(vectorUsed|vectorCng) ; Set that we used vectors
9bccf70c 1594 rlwinm. r0,r8,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are doing this for user state
55e303ae
A
1595 stw r8,savesrr1+4(r25) ; Set the msr of the interrupted guy
1596 mr r3,r25 ; Pass virtual address of the savearea
b4c24cb9 1597 beq- vrnuser ; We are not user state...
9bccf70c 1598 stw r10,ACT_MACT_SPF(r17) ; Set the activation copy
d7e50217 1599 stw r11,spcFlags(r26) ; Set per_proc copy
1c79356b
A
1600
1601vrnuser:
1602#if FPVECDBG
9bccf70c
A
1603 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1604 li r2,0x5F07 ; (TEST/DEBUG)
1605 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1606 sc ; (TEST/DEBUG)
1c79356b 1607#endif
9bccf70c 1608 b EXT(exception_exit) ; Exit to the fray...
1c79356b
A
1609
1610/*
1611 * Initialize the registers to some bogus value
1c79356b
A
1612 */
1613
1614ProtectTheAmericanWay:
1615
1616#if FPVECDBG
9bccf70c
A
1617 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1618 li r2,0x5F06 ; (TEST/DEBUG)
1619 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1620 sc ; (TEST/DEBUG)
1c79356b 1621#endif
9bccf70c
A
1622
1623 vor v0,v31,v31 ; Copy into the next register
1624 vor v1,v31,v31 ; Copy into the next register
1625 vor v2,v31,v31 ; Copy into the next register
1626 vor v3,v31,v31 ; Copy into the next register
1627 vor v4,v31,v31 ; Copy into the next register
1628 vor v5,v31,v31 ; Copy into the next register
1629 vor v6,v31,v31 ; Copy into the next register
1630 vor v7,v31,v31 ; Copy into the next register
1631 vor v8,v31,v31 ; Copy into the next register
1632 vor v9,v31,v31 ; Copy into the next register
1633 vor v10,v31,v31 ; Copy into the next register
1634 vor v11,v31,v31 ; Copy into the next register
1635 vor v12,v31,v31 ; Copy into the next register
1636 vor v13,v31,v31 ; Copy into the next register
1637 vor v14,v31,v31 ; Copy into the next register
1638 vor v15,v31,v31 ; Copy into the next register
1639 vor v16,v31,v31 ; Copy into the next register
1640 vor v17,v31,v31 ; Copy into the next register
1641 vor v18,v31,v31 ; Copy into the next register
1642 vor v19,v31,v31 ; Copy into the next register
1643 vor v20,v31,v31 ; Copy into the next register
1644 vor v21,v31,v31 ; Copy into the next register
1645 vor v22,v31,v31 ; Copy into the next register
1646 vor v23,v31,v31 ; Copy into the next register
1647 vor v24,v31,v31 ; Copy into the next register
1648 vor v25,v31,v31 ; Copy into the next register
1649 vor v26,v31,v31 ; Copy into the next register
1650 vor v27,v31,v31 ; Copy into the next register
1651 vor v28,v31,v31 ; Copy into the next register
1652 vor v29,v31,v31 ; Copy into the next register
1653 vor v30,v31,v31 ; Copy into the next register
b36670ce 1654 b vrenablelk ; Finish setting it all up...
9bccf70c
A
1655
1656
1657
1658;
1659; We get here when we are switching to the same context at the same level and the context
1660; is still live. Essentially, all we are doing is turning on the faility. It may have
1661; gotten turned off due to doing a context save for the current level or a context switch
1662; back to the live guy.
1663;
1664
1665 .align 5
1666
b36670ce 1667vswthesame:
9bccf70c
A
1668
1669#if FPVECDBG
1670 lis r0,hi16(CutTrace) ; (TEST/DEBUG)
1671 li r2,0x5F0A ; (TEST/DEBUG)
1672 oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG)
1673 sc ; (TEST/DEBUG)
1674#endif
1675 beq- cr1,vrenable ; Not saved yet, nothing to pop, go enable and exit...
1676
1677 lwz r11,SAVlevel(r30) ; Get the level of top saved context
55e303ae 1678 lwz r14,SAVprev+4(r30) ; Get the previous savearea
9bccf70c
A
1679
1680 cmplw r11,r31 ; Are live and saved the same?
1681
1682 bne+ vrenable ; Level not the same, nothing to pop, go enable and exit...
1683
1684 mr r3,r30 ; Get the old savearea (we popped it before)
55e303ae 1685 stw r11,VMXsave(r22) ; Pop the vector stack
9bccf70c
A
1686 bl EXT(save_ret) ; Toss it
1687 b vrenable ; Go enable and exit...
1688
1689
1690;
1691; This function invalidates any live vector context for the passed in facility_context.
1692; This is intended to be called just before act_machine_sv_free tosses saveareas.
1c79356b 1693;
1c79356b 1694
9bccf70c
A
1695 .align 5
1696 .globl EXT(toss_live_vec)
1c79356b 1697
9bccf70c
A
1698LEXT(toss_live_vec)
1699
55e303ae 1700 lis r0,hi16(MASK(MSR_VEC)) ; Get VEC
9bccf70c 1701 mfmsr r9 ; Get the MSR
55e303ae
A
1702 ori r0,r0,lo16(MASK(MSR_FP)) ; Add in FP
1703 rlwinm. r8,r9,0,MSR_VEC_BIT,MSR_VEC_BIT ; Are vectors on right now?
1704 andc r9,r9,r0 ; Force off VEC and FP
1705 ori r0,r0,lo16(MASK(MSR_EE)) ; Turn off EE
1706 andc r0,r9,r0 ; Turn off EE now
9bccf70c
A
1707 mtmsr r0 ; No interruptions
1708 isync
1709 beq+ tlvnotours ; Vector off, can not be live here...
1c79356b 1710
91447636
A
1711 mfsprg r8,1 ; Get the current activation
1712 lwz r8,ACT_PER_PROC(r8) ; Get the per_proc block
9bccf70c
A
1713
1714;
1715; Note that at this point, since vecs are on, we are the owner
1716; of live state on this processor
1717;
1718
1719 lwz r6,VMXowner(r8) ; Get the thread that owns the vector
1720 li r0,0 ; Clear this just in case we need it
1721 cmplw r6,r3 ; Are we tossing our own context?
1722 bne- tlvnotours ; Nope...
1723
1724 vspltish v1,1 ; Turn on the non-Java bit and saturate
1725 vspltisw v0,1 ; Turn on the saturate bit
1726 vxor v1,v1,v0 ; Turn off saturate
1727 mtspr vrsave,r0 ; Clear VRSAVE
1728 mtvscr v1 ; Set the non-java, no saturate status
1729
1730tlvnotours: lwz r11,VMXcpu(r3) ; Get the cpu on which we last loaded context
91447636
A
1731 lis r12,hi16(EXT(PerProcTable)) ; Set base PerProcTable
1732 mulli r11,r11,ppeSize ; Find offset to the owner per_proc_entry
1733 ori r12,r12,lo16(EXT(PerProcTable)) ; Set base PerProcTable
9bccf70c 1734 li r10,VMXowner ; Displacement to vector owner
91447636
A
1735 add r11,r12,r11 ; Point to the owner per_proc_entry
1736 lwz r11,ppe_vaddr(r11) ; Point to the owner per_proc
9bccf70c
A
1737 li r0,0 ; Set a 0 to invalidate context
1738
1739tlvinvothr: lwarx r12,r10,r11 ; Get the owner
9bccf70c 1740
55e303ae
A
1741 sub r0,r12,r3 ; Subtract one from the other
1742 sub r8,r3,r12 ; Subtract the other from the one
1743 or r8,r8,r0 ; Combine them
1744 srawi r8,r8,31 ; Get a 0 if equal or -1 of not
1745 and r12,r12,r8 ; Make 0 if same, unchanged if not
1746 stwcx. r12,r10,r11 ; Try to invalidate it
1747 bne-- tlvinvothr ; Try again if there was a collision...
1748
1749 mtmsr r9 ; Restore interruptions
9bccf70c
A
1750 isync ; Could be turning off vectors here
1751 blr ; Leave....
1752
1753#if 0
1754;
1755; This function invalidates any live vector context for the passed in facility_context
1756; if the level is current. It also tosses the corresponding savearea if there is one.
1757; This function is primarily used whenever we detect a VRSave that is all zeros.
1758;
1759
1760 .align 5
1761 .globl EXT(vec_trash)
1762
1763LEXT(vec_trash)
1764
1765 lwz r12,facAct(r3) ; Get the activation
1766 lwz r11,VMXlevel(r3) ; Get the context level
1767 lwz r10,ACT_MACT_PCB(r12) ; Grab the current level for the thread
1768 lwz r9,VMXsave(r3) ; Get the savearea, if any
1769 cmplw r10,r11 ; Are we at the right level?
1770 cmplwi cr1,r9,0 ; Remember if there is a savearea
1771 bnelr+ ; No, we do nothing...
1772
1773 lwz r11,VMXcpu(r3) ; Get the cpu on which we last loaded context
91447636
A
1774 lis r12,hi16(EXT(PerProcTable)) ; Set base PerProcTable
1775 mulli r11,r11,ppeSize ; Find offset to the owner per_proc_entry
1776 ori r12,r12,lo16(EXT(PerProcTable)) ; Set base PerProcTable
9bccf70c 1777 li r10,VMXowner ; Displacement to vector owner
91447636
A
1778 add r11,r12,r11 ; Point to the owner per_proc_entry
1779 lwz r11,ppe_vaddr(r11) ; Point to the owner per_proc
9bccf70c
A
1780
1781vtinvothr: lwarx r12,r10,r11 ; Get the owner
9bccf70c 1782
55e303ae
A
1783 sub r0,r12,r3 ; Subtract one from the other
1784 sub r8,r3,r12 ; Subtract the other from the one
1785 or r8,r8,r0 ; Combine them
1786 srawi r8,r8,31 ; Get a 0 if equal or -1 of not
1787 and r12,r12,r8 ; Make 0 if same, unchanged if not
1788 stwcx. r12,r10,r11 ; Try to invalidate it
1789 bne-- vtinvothr ; Try again if there was a collision...
1790
1791
1792 beqlr++ cr1 ; Leave if there is no savearea
9bccf70c
A
1793 lwz r8,SAVlevel(r9) ; Get the level of the savearea
1794 cmplw r8,r11 ; Savearea for the current level?
55e303ae 1795 bnelr++ ; No, nothing to release...
9bccf70c 1796
55e303ae 1797 lwz r8,SAVprev+4(r9) ; Pick up the previous area
9bccf70c 1798 mr. r8,r8 ; Is there a previous?
55e303ae 1799 beq-- vtnoprev ; Nope...
9bccf70c
A
1800 lwz r7,SAVlevel(r8) ; Get the level associated with save
1801
1802vtnoprev: stw r8,VMXsave(r3) ; Dequeue this savearea
1803 stw r7,VMXlevel(r3) ; Pop the level
1804
1805 mr r3,r9 ; Get the savearea to release
1806 b EXT(save_ret) ; Go and toss the save area (note, we will return from there)...
1807#endif
1808
1809;
1810; Just some test code to force vector and/or floating point in the kernel
1811;
1812
1813 .align 5
1814 .globl EXT(fctx_test)
1c79356b 1815
9bccf70c
A
1816LEXT(fctx_test)
1817
55e303ae 1818 mfsprg r3,1 ; Get the current thread
9bccf70c
A
1819 mr. r3,r3 ; Are we actually up and running?
1820 beqlr- ; No...
1821
1822 fmr f0,f0 ; Use floating point
1823 mftb r4 ; Get time base for a random number
1824 li r5,1 ; Get a potential vrsave to use
1825 andi. r4,r4,0x3F ; Get a number from 0 - 63
1826 slw r5,r5,r4 ; Choose a register to save (should be 0 half the time)
1827 mtspr vrsave,r5 ; Set VRSave
1828 vor v0,v0,v0 ; Use vectors
1829 blr
55e303ae
A
1830
1831
1832// *******************
1833// * f p _ s t o r e *
1834// *******************
1835//
1836// Store FPRs into a save area. Called by fpu_save and fpu_switch.
1837//
1838// When called:
1839// floating pt is enabled
1840// r3 = ptr to save area
1841//
1842// We destroy:
1843// r11.
1844
1845fp_store:
1846 mfsprg r11,2 ; get feature flags
1847 mtcrf 0x02,r11 ; put cache line size bits in cr6
1848 la r11,savefp0(r3) ; point to 1st line
1849 dcbz128 0,r11 ; establish 1st line no matter what linesize is
1850 bt-- pf32Byteb,fp_st32 ; skip if a 32-byte machine
1851
1852// Store the FPRs on a 128-byte machine.
1853
1854 stfd f0,savefp0(r3)
1855 stfd f1,savefp1(r3)
1856 la r11,savefp16(r3) ; Point to the 2nd cache line
1857 stfd f2,savefp2(r3)
1858 stfd f3,savefp3(r3)
1859 dcbz128 0,r11 ; establish 2nd line
1860 stfd f4,savefp4(r3)
1861 stfd f5,savefp5(r3)
1862 stfd f6,savefp6(r3)
1863 stfd f7,savefp7(r3)
1864 stfd f8,savefp8(r3)
1865 stfd f9,savefp9(r3)
1866 stfd f10,savefp10(r3)
1867 stfd f11,savefp11(r3)
1868 stfd f12,savefp12(r3)
1869 stfd f13,savefp13(r3)
1870 stfd f14,savefp14(r3)
1871 stfd f15,savefp15(r3)
1872 stfd f16,savefp16(r3)
1873 stfd f17,savefp17(r3)
1874 stfd f18,savefp18(r3)
1875 stfd f19,savefp19(r3)
1876 stfd f20,savefp20(r3)
1877 stfd f21,savefp21(r3)
1878 stfd f22,savefp22(r3)
1879 stfd f23,savefp23(r3)
1880 stfd f24,savefp24(r3)
1881 stfd f25,savefp25(r3)
1882 stfd f26,savefp26(r3)
1883 stfd f27,savefp27(r3)
1884 stfd f28,savefp28(r3)
1885 stfd f29,savefp29(r3)
1886 stfd f30,savefp30(r3)
1887 stfd f31,savefp31(r3)
1888 blr
1889
1890// Store FPRs on a 32-byte machine.
1891
1892fp_st32:
1893 la r11,savefp4(r3) ; Point to the 2nd line
1894 stfd f0,savefp0(r3)
1895 dcbz 0,r11 ; Allocate cache
1896 stfd f1,savefp1(r3)
1897 stfd f2,savefp2(r3)
1898 la r11,savefp8(r3) ; Point to the 3rd line
1899 stfd f3,savefp3(r3)
1900 dcbz 0,r11 ; Allocate cache
1901 stfd f4,savefp4(r3)
1902 stfd f5,savefp5(r3)
1903 stfd f6,savefp6(r3)
1904 la r11,savefp12(r3) ; Point to the 4th line
1905 stfd f7,savefp7(r3)
1906 dcbz 0,r11 ; Allocate cache
1907 stfd f8,savefp8(r3)
1908 stfd f9,savefp9(r3)
1909 stfd f10,savefp10(r3)
1910 la r11,savefp16(r3) ; Point to the 5th line
1911 stfd f11,savefp11(r3)
1912 dcbz 0,r11 ; Allocate cache
1913 stfd f12,savefp12(r3)
1914 stfd f13,savefp13(r3)
1915 stfd f14,savefp14(r3)
1916 la r11,savefp20(r3) ; Point to the 6th line
1917 stfd f15,savefp15(r3)
1918 dcbz 0,r11 ; Allocate cache
1919 stfd f16,savefp16(r3)
1920 stfd f17,savefp17(r3)
1921 stfd f18,savefp18(r3)
1922 la r11,savefp24(r3) ; Point to the 7th line
1923 stfd f19,savefp19(r3)
1924 dcbz 0,r11 ; Allocate cache
1925 stfd f20,savefp20(r3)
1926
1927 stfd f21,savefp21(r3)
1928 stfd f22,savefp22(r3)
1929 la r11,savefp28(r3) ; Point to the 8th line
1930 stfd f23,savefp23(r3)
1931 dcbz 0,r11 ; allocate it
1932 stfd f24,savefp24(r3)
1933 stfd f25,savefp25(r3)
1934 stfd f26,savefp26(r3)
1935 stfd f27,savefp27(r3)
1936
1937 stfd f28,savefp28(r3)
1938 stfd f29,savefp29(r3)
1939 stfd f30,savefp30(r3)
1940 stfd f31,savefp31(r3)
1941 blr
1942
1943
1944// *******************
1945// * v r _ s t o r e *
1946// *******************
1947//
1948// Store VRs into savearea, according to bits set in passed vrsave bitfield. This routine is used
1949// both by vec_save and vec_switch. In order to minimize conditional branches and touching in
1950// unnecessary cache blocks, we either save all or none of the VRs in a block. We have separate paths
1951// for each cache block size.
1952//
1953// When called:
1954// interrupts are off, vectors are enabled
1955// r3 = ptr to save area
1956// r10 = vrsave (not 0)
1957//
1958// We destroy:
1959// r4 - r11, all CRs.
1960
1961vr_store:
1962 mfsprg r9,2 ; get feature flags
1963 stw r10,savevrvalid(r3) ; Save the validity information in savearea
1964 slwi r8,r10,1 ; Shift over 1
1965 mtcrf 0x02,r9 ; put cache line size bits in cr6 where we can test
1966 or r8,r10,r8 ; r8 <- even bits show which pairs are in use
1967 bt-- pf32Byteb,vr_st32 ; skip if 32-byte cacheline processor
1968
1969
1970; Save vectors on a 128-byte linesize processor. We save all or none of the 8 registers in each of
1971; the four cache lines. This minimizes mispredicted branches yet handles cache lines optimally.
1972
1973 slwi r7,r8,2 ; shift groups-of-2 over by 2
1974 li r4,16 ; load offsets for X-form stores
1975 or r8,r7,r8 ; show if any in group of 4 are in use
1976 li r5,32
1977 slwi r7,r8,4 ; shift groups-of-4 over by 4
1978 li r6,48
1979 or r11,r7,r8 ; show if any in group of 8 are in use
1980 li r7,64
1981 mtcrf 0x80,r11 ; set CRs one at a time (faster)
1982 li r8,80
1983 mtcrf 0x20,r11
1984 li r9,96
1985 mtcrf 0x08,r11
1986 li r10,112
1987 mtcrf 0x02,r11
1988
1989 bf 0,vr_st64b ; skip if none of vr0-vr7 are in use
1990 la r11,savevr0(r3) ; get address of this group of registers in save area
1991 dcbz128 0,r11 ; zero the line
1992 stvxl v0,0,r11 ; save 8 VRs in the line
1993 stvxl v1,r4,r11
1994 stvxl v2,r5,r11
1995 stvxl v3,r6,r11
1996 stvxl v4,r7,r11
1997 stvxl v5,r8,r11
1998 stvxl v6,r9,r11
1999 stvxl v7,r10,r11
2000
2001vr_st64b:
2002 bf 8,vr_st64c ; skip if none of vr8-vr15 are in use
2003 la r11,savevr8(r3) ; get address of this group of registers in save area
2004 dcbz128 0,r11 ; zero the line
2005 stvxl v8,0,r11 ; save 8 VRs in the line
2006 stvxl v9,r4,r11
2007 stvxl v10,r5,r11
2008 stvxl v11,r6,r11
2009 stvxl v12,r7,r11
2010 stvxl v13,r8,r11
2011 stvxl v14,r9,r11
2012 stvxl v15,r10,r11
2013
2014vr_st64c:
2015 bf 16,vr_st64d ; skip if none of vr16-vr23 are in use
2016 la r11,savevr16(r3) ; get address of this group of registers in save area
2017 dcbz128 0,r11 ; zero the line
2018 stvxl v16,0,r11 ; save 8 VRs in the line
2019 stvxl v17,r4,r11
2020 stvxl v18,r5,r11
2021 stvxl v19,r6,r11
2022 stvxl v20,r7,r11
2023 stvxl v21,r8,r11
2024 stvxl v22,r9,r11
2025 stvxl v23,r10,r11
2026
2027vr_st64d:
2028 bflr 24 ; done if none of vr24-vr31 are in use
2029 la r11,savevr24(r3) ; get address of this group of registers in save area
2030 dcbz128 0,r11 ; zero the line
2031 stvxl v24,0,r11 ; save 8 VRs in the line
2032 stvxl v25,r4,r11
2033 stvxl v26,r5,r11
2034 stvxl v27,r6,r11
2035 stvxl v28,r7,r11
2036 stvxl v29,r8,r11
2037 stvxl v30,r9,r11
2038 stvxl v31,r10,r11
2039 blr
2040
2041; Save vectors on a 32-byte linesize processor. We save in 16 groups of 2: we either save both
2042; or neither in each group. This cuts down on conditional branches.
2043; r8 = bitmask with bit n set (for even n) if either of that pair of VRs is in use
2044; r3 = savearea
2045
2046vr_st32:
2047 mtcrf 0xFF,r8 ; set CR bits so we can branch on them
2048 li r4,16 ; load offset for X-form stores
2049
2050 bf 0,vr_st32b ; skip if neither VR in this pair is in use
2051 la r11,savevr0(r3) ; get address of this group of registers in save area
2052 dcba 0,r11 ; establish the line wo reading it
2053 stvxl v0,0,r11 ; save the two VRs in the line
2054 stvxl v1,r4,r11
2055
2056vr_st32b:
2057 bf 2,vr_st32c ; skip if neither VR in this pair is in use
2058 la r11,savevr2(r3) ; get address of this group of registers in save area
2059 dcba 0,r11 ; establish the line wo reading it
2060 stvxl v2,0,r11 ; save the two VRs in the line
2061 stvxl v3,r4,r11
2062
2063vr_st32c:
2064 bf 4,vr_st32d ; skip if neither VR in this pair is in use
2065 la r11,savevr4(r3) ; get address of this group of registers in save area
2066 dcba 0,r11 ; establish the line wo reading it
2067 stvxl v4,0,r11 ; save the two VRs in the line
2068 stvxl v5,r4,r11
2069
2070vr_st32d:
2071 bf 6,vr_st32e ; skip if neither VR in this pair is in use
2072 la r11,savevr6(r3) ; get address of this group of registers in save area
2073 dcba 0,r11 ; establish the line wo reading it
2074 stvxl v6,0,r11 ; save the two VRs in the line
2075 stvxl v7,r4,r11
2076
2077vr_st32e:
2078 bf 8,vr_st32f ; skip if neither VR in this pair is in use
2079 la r11,savevr8(r3) ; get address of this group of registers in save area
2080 dcba 0,r11 ; establish the line wo reading it
2081 stvxl v8,0,r11 ; save the two VRs in the line
2082 stvxl v9,r4,r11
2083
2084vr_st32f:
2085 bf 10,vr_st32g ; skip if neither VR in this pair is in use
2086 la r11,savevr10(r3) ; get address of this group of registers in save area
2087 dcba 0,r11 ; establish the line wo reading it
2088 stvxl v10,0,r11 ; save the two VRs in the line
2089 stvxl v11,r4,r11
2090
2091vr_st32g:
2092 bf 12,vr_st32h ; skip if neither VR in this pair is in use
2093 la r11,savevr12(r3) ; get address of this group of registers in save area
2094 dcba 0,r11 ; establish the line wo reading it
2095 stvxl v12,0,r11 ; save the two VRs in the line
2096 stvxl v13,r4,r11
2097
2098vr_st32h:
2099 bf 14,vr_st32i ; skip if neither VR in this pair is in use
2100 la r11,savevr14(r3) ; get address of this group of registers in save area
2101 dcba 0,r11 ; establish the line wo reading it
2102 stvxl v14,0,r11 ; save the two VRs in the line
2103 stvxl v15,r4,r11
2104
2105vr_st32i:
2106 bf 16,vr_st32j ; skip if neither VR in this pair is in use
2107 la r11,savevr16(r3) ; get address of this group of registers in save area
2108 dcba 0,r11 ; establish the line wo reading it
2109 stvxl v16,0,r11 ; save the two VRs in the line
2110 stvxl v17,r4,r11
2111
2112vr_st32j:
2113 bf 18,vr_st32k ; skip if neither VR in this pair is in use
2114 la r11,savevr18(r3) ; get address of this group of registers in save area
2115 dcba 0,r11 ; establish the line wo reading it
2116 stvxl v18,0,r11 ; save the two VRs in the line
2117 stvxl v19,r4,r11
2118
2119vr_st32k:
2120 bf 20,vr_st32l ; skip if neither VR in this pair is in use
2121 la r11,savevr20(r3) ; get address of this group of registers in save area
2122 dcba 0,r11 ; establish the line wo reading it
2123 stvxl v20,0,r11 ; save the two VRs in the line
2124 stvxl v21,r4,r11
2125
2126vr_st32l:
2127 bf 22,vr_st32m ; skip if neither VR in this pair is in use
2128 la r11,savevr22(r3) ; get address of this group of registers in save area
2129 dcba 0,r11 ; establish the line wo reading it
2130 stvxl v22,0,r11 ; save the two VRs in the line
2131 stvxl v23,r4,r11
2132
2133vr_st32m:
2134 bf 24,vr_st32n ; skip if neither VR in this pair is in use
2135 la r11,savevr24(r3) ; get address of this group of registers in save area
2136 dcba 0,r11 ; establish the line wo reading it
2137 stvxl v24,0,r11 ; save the two VRs in the line
2138 stvxl v25,r4,r11
2139
2140vr_st32n:
2141 bf 26,vr_st32o ; skip if neither VR in this pair is in use
2142 la r11,savevr26(r3) ; get address of this group of registers in save area
2143 dcba 0,r11 ; establish the line wo reading it
2144 stvxl v26,0,r11 ; save the two VRs in the line
2145 stvxl v27,r4,r11
2146
2147vr_st32o:
2148 bf 28,vr_st32p ; skip if neither VR in this pair is in use
2149 la r11,savevr28(r3) ; get address of this group of registers in save area
2150 dcba 0,r11 ; establish the line wo reading it
2151 stvxl v28,0,r11 ; save the two VRs in the line
2152 stvxl v29,r4,r11
2153
2154vr_st32p:
2155 bflr 30 ; done if neither VR in this pair is in use
2156 la r11,savevr30(r3) ; get address of this group of registers in save area
2157 dcba 0,r11 ; establish the line wo reading it
2158 stvxl v30,0,r11 ; save the two VRs in the line
2159 stvxl v31,r4,r11
2160 blr
2161
2162
2163// *****************
2164// * v r _ l o a d *
2165// *****************
2166//
2167// Load live VRs from a savearea, according to bits set in a passed vector. This is the reverse
2168// of "vr_store". Like it, we avoid touching unnecessary cache blocks and minimize conditional
2169// branches by loading all VRs from a cache line, if we have to load any. If we don't load the VRs
2170// in a cache line, we bug them. Note that this behavior is slightly different from earlier kernels,
2171// which would bug all VRs that aren't live.
2172//
2173// When called:
2174// interrupts are off, vectors are enabled
2175// r3 = ptr to save area
2176// r10 = vector of live regs to load (ie, savevrsave & savevrvalid, may be 0)
2177// v31 = bugbug constant (0x7FFFDEAD7FFFDEAD7FFFDEAD7FFFDEAD)
2178//
2179// We destroy:
2180// r4 - r11, all CRs.
2181
2182vr_load:
2183 mfsprg r9,2 ; get feature flags
2184 li r6,1 ; assuming 32-byte, get (#VRs)-1 in a cacheline
2185 mtcrf 0x02,r9 ; set cache line size bits in cr6
2186 lis r7,0xC000 ; assuming 32-byte, set bits 0-1
2187 bt-- pf32Byteb,vr_ld0 ; skip if 32-bit processor
2188 li r6,7 ; 128-byte machines have 8 VRs in a cacheline
2189 lis r7,0xFF00 ; so set bits 0-7
2190
2191// Loop touching in cache blocks we will load from.
2192// r3 = savearea ptr
2193// r5 = we light bits for the VRs we will be loading
2194// r6 = 1 if 32-byte, 7 if 128-byte
2195// r7 = 0xC0000000 if 32-byte, 0xFF000000 if 128-byte
2196// r10 = live VR bits
2197// v31 = bugbug constant
2198
2199vr_ld0:
2200 li r5,0 ; initialize set of VRs to load
2201 la r11,savevr0(r3) ; get address of register file
2202 b vr_ld2 ; enter loop in middle
2203
2204 .align 5
2205vr_ld1: ; loop over each cache line we will load
2206 dcbt r4,r11 ; start prefetch of the line
2207 andc r10,r10,r9 ; turn off the bits in this line
2208 or r5,r5,r9 ; we will load all these
2209vr_ld2: ; initial entry pt
2210 cntlzw r4,r10 ; get offset to next live VR
2211 andc r4,r4,r6 ; cacheline align it
2212 srw. r9,r7,r4 ; position bits for VRs in that cache line
2213 slwi r4,r4,4 ; get byte offset within register file to that line
2214 bne vr_ld1 ; loop if more bits in r10
2215
2216 bf-- pf128Byteb,vr_ld32 ; skip if not 128-byte lines
2217
2218// Handle a processor with 128-byte cache lines. Four groups of 8 VRs.
2219// r3 = savearea ptr
2220// r5 = 1st bit in each cacheline is 1 iff any reg in that line must be loaded
2221// r11 = addr(savevr0)
2222// v31 = bugbug constant
2223
2224 mtcrf 0x80,r5 ; set up bits for conditional branches
2225 li r4,16 ; load offsets for X-form stores
2226 li r6,48
2227 mtcrf 0x20,r5 ; load CRs ona at a time, which is faster
2228 li r7,64
2229 li r8,80
2230 mtcrf 0x08,r5
2231 li r9,96
2232 li r10,112
2233 mtcrf 0x02,r5
2234 li r5,32
2235
2236 bt 0,vr_ld128a ; skip if this line must be loaded
2237 vor v0,v31,v31 ; no VR must be loaded, so bug them all
2238 vor v1,v31,v31
2239 vor v2,v31,v31
2240 vor v3,v31,v31
2241 vor v4,v31,v31
2242 vor v5,v31,v31
2243 vor v6,v31,v31
2244 vor v7,v31,v31
2245 b vr_ld128b
2246vr_ld128a: ; must load from this line
2247 lvxl v0,0,r11
2248 lvxl v1,r4,r11
2249 lvxl v2,r5,r11
2250 lvxl v3,r6,r11
2251 lvxl v4,r7,r11
2252 lvxl v5,r8,r11
2253 lvxl v6,r9,r11
2254 lvxl v7,r10,r11
2255
2256vr_ld128b: ; here to handle next cache line
2257 la r11,savevr8(r3) ; load offset to it
2258 bt 8,vr_ld128c ; skip if this line must be loaded
2259 vor v8,v31,v31 ; no VR must be loaded, so bug them all
2260 vor v9,v31,v31
2261 vor v10,v31,v31
2262 vor v11,v31,v31
2263 vor v12,v31,v31
2264 vor v13,v31,v31
2265 vor v14,v31,v31
2266 vor v15,v31,v31
2267 b vr_ld128d
2268vr_ld128c: ; must load from this line
2269 lvxl v8,0,r11
2270 lvxl v9,r4,r11
2271 lvxl v10,r5,r11
2272 lvxl v11,r6,r11
2273 lvxl v12,r7,r11
2274 lvxl v13,r8,r11
2275 lvxl v14,r9,r11
2276 lvxl v15,r10,r11
2277
2278vr_ld128d: ; here to handle next cache line
2279 la r11,savevr16(r3) ; load offset to it
2280 bt 16,vr_ld128e ; skip if this line must be loaded
2281 vor v16,v31,v31 ; no VR must be loaded, so bug them all
2282 vor v17,v31,v31
2283 vor v18,v31,v31
2284 vor v19,v31,v31
2285 vor v20,v31,v31
2286 vor v21,v31,v31
2287 vor v22,v31,v31
2288 vor v23,v31,v31
2289 b vr_ld128f
2290vr_ld128e: ; must load from this line
2291 lvxl v16,0,r11
2292 lvxl v17,r4,r11
2293 lvxl v18,r5,r11
2294 lvxl v19,r6,r11
2295 lvxl v20,r7,r11
2296 lvxl v21,r8,r11
2297 lvxl v22,r9,r11
2298 lvxl v23,r10,r11
2299
2300vr_ld128f: ; here to handle next cache line
2301 la r11,savevr24(r3) ; load offset to it
2302 bt 24,vr_ld128g ; skip if this line must be loaded
2303 vor v24,v31,v31 ; no VR must be loaded, so bug them all
2304 vor v25,v31,v31
2305 vor v26,v31,v31
2306 vor v27,v31,v31
2307 vor v28,v31,v31
2308 vor v29,v31,v31
2309 vor v30,v31,v31
2310 blr
2311vr_ld128g: ; must load from this line
2312 lvxl v24,0,r11
2313 lvxl v25,r4,r11
2314 lvxl v26,r5,r11
2315 lvxl v27,r6,r11
2316 lvxl v28,r7,r11
2317 lvxl v29,r8,r11
2318 lvxl v30,r9,r11
2319 lvxl v31,r10,r11
2320 blr
2321
2322// Handle a processor with 32-byte cache lines. Sixteen groups of two VRs.
2323// r5 = 1st bit in each cacheline is 1 iff any reg in that line must be loaded
2324// r11 = addr(savevr0)
2325
2326vr_ld32:
2327 mtcrf 0xFF,r5 ; set up bits for conditional branches
2328 li r4,16 ; load offset for X-form stores
2329
2330 bt 0,vr_ld32load0 ; skip if we must load this line
2331 vor v0,v31,v31 ; neither VR is live, so bug them both
2332 vor v1,v31,v31
2333 b vr_ld32test2
2334vr_ld32load0: ; must load VRs in this line
2335 lvxl v0,0,r11
2336 lvxl v1,r4,r11
2337
2338vr_ld32test2: ; here to handle next cache line
2339 la r11,savevr2(r3) ; get offset to next cache line
2340 bt 2,vr_ld32load2 ; skip if we must load this line
2341 vor v2,v31,v31 ; neither VR is live, so bug them both
2342 vor v3,v31,v31
2343 b vr_ld32test4
2344vr_ld32load2: ; must load VRs in this line
2345 lvxl v2,0,r11
2346 lvxl v3,r4,r11
2347
2348vr_ld32test4: ; here to handle next cache line
2349 la r11,savevr4(r3) ; get offset to next cache line
2350 bt 4,vr_ld32load4 ; skip if we must load this line
2351 vor v4,v31,v31 ; neither VR is live, so bug them both
2352 vor v5,v31,v31
2353 b vr_ld32test6
2354vr_ld32load4: ; must load VRs in this line
2355 lvxl v4,0,r11
2356 lvxl v5,r4,r11
2357
2358vr_ld32test6: ; here to handle next cache line
2359 la r11,savevr6(r3) ; get offset to next cache line
2360 bt 6,vr_ld32load6 ; skip if we must load this line
2361 vor v6,v31,v31 ; neither VR is live, so bug them both
2362 vor v7,v31,v31
2363 b vr_ld32test8
2364vr_ld32load6: ; must load VRs in this line
2365 lvxl v6,0,r11
2366 lvxl v7,r4,r11
2367
2368vr_ld32test8: ; here to handle next cache line
2369 la r11,savevr8(r3) ; get offset to next cache line
2370 bt 8,vr_ld32load8 ; skip if we must load this line
2371 vor v8,v31,v31 ; neither VR is live, so bug them both
2372 vor v9,v31,v31
2373 b vr_ld32test10
2374vr_ld32load8: ; must load VRs in this line
2375 lvxl v8,0,r11
2376 lvxl v9,r4,r11
2377
2378vr_ld32test10: ; here to handle next cache line
2379 la r11,savevr10(r3) ; get offset to next cache line
2380 bt 10,vr_ld32load10 ; skip if we must load this line
2381 vor v10,v31,v31 ; neither VR is live, so bug them both
2382 vor v11,v31,v31
2383 b vr_ld32test12
2384vr_ld32load10: ; must load VRs in this line
2385 lvxl v10,0,r11
2386 lvxl v11,r4,r11
2387
2388vr_ld32test12: ; here to handle next cache line
2389 la r11,savevr12(r3) ; get offset to next cache line
2390 bt 12,vr_ld32load12 ; skip if we must load this line
2391 vor v12,v31,v31 ; neither VR is live, so bug them both
2392 vor v13,v31,v31
2393 b vr_ld32test14
2394vr_ld32load12: ; must load VRs in this line
2395 lvxl v12,0,r11
2396 lvxl v13,r4,r11
2397
2398vr_ld32test14: ; here to handle next cache line
2399 la r11,savevr14(r3) ; get offset to next cache line
2400 bt 14,vr_ld32load14 ; skip if we must load this line
2401 vor v14,v31,v31 ; neither VR is live, so bug them both
2402 vor v15,v31,v31
2403 b vr_ld32test16
2404vr_ld32load14: ; must load VRs in this line
2405 lvxl v14,0,r11
2406 lvxl v15,r4,r11
2407
2408vr_ld32test16: ; here to handle next cache line
2409 la r11,savevr16(r3) ; get offset to next cache line
2410 bt 16,vr_ld32load16 ; skip if we must load this line
2411 vor v16,v31,v31 ; neither VR is live, so bug them both
2412 vor v17,v31,v31
2413 b vr_ld32test18
2414vr_ld32load16: ; must load VRs in this line
2415 lvxl v16,0,r11
2416 lvxl v17,r4,r11
2417
2418vr_ld32test18: ; here to handle next cache line
2419 la r11,savevr18(r3) ; get offset to next cache line
2420 bt 18,vr_ld32load18 ; skip if we must load this line
2421 vor v18,v31,v31 ; neither VR is live, so bug them both
2422 vor v19,v31,v31
2423 b vr_ld32test20
2424vr_ld32load18: ; must load VRs in this line
2425 lvxl v18,0,r11
2426 lvxl v19,r4,r11
2427
2428vr_ld32test20: ; here to handle next cache line
2429 la r11,savevr20(r3) ; get offset to next cache line
2430 bt 20,vr_ld32load20 ; skip if we must load this line
2431 vor v20,v31,v31 ; neither VR is live, so bug them both
2432 vor v21,v31,v31
2433 b vr_ld32test22
2434vr_ld32load20: ; must load VRs in this line
2435 lvxl v20,0,r11
2436 lvxl v21,r4,r11
2437
2438vr_ld32test22: ; here to handle next cache line
2439 la r11,savevr22(r3) ; get offset to next cache line
2440 bt 22,vr_ld32load22 ; skip if we must load this line
2441 vor v22,v31,v31 ; neither VR is live, so bug them both
2442 vor v23,v31,v31
2443 b vr_ld32test24
2444vr_ld32load22: ; must load VRs in this line
2445 lvxl v22,0,r11
2446 lvxl v23,r4,r11
2447
2448vr_ld32test24: ; here to handle next cache line
2449 la r11,savevr24(r3) ; get offset to next cache line
2450 bt 24,vr_ld32load24 ; skip if we must load this line
2451 vor v24,v31,v31 ; neither VR is live, so bug them both
2452 vor v25,v31,v31
2453 b vr_ld32test26
2454vr_ld32load24: ; must load VRs in this line
2455 lvxl v24,0,r11
2456 lvxl v25,r4,r11
2457
2458vr_ld32test26: ; here to handle next cache line
2459 la r11,savevr26(r3) ; get offset to next cache line
2460 bt 26,vr_ld32load26 ; skip if we must load this line
2461 vor v26,v31,v31 ; neither VR is live, so bug them both
2462 vor v27,v31,v31
2463 b vr_ld32test28
2464vr_ld32load26: ; must load VRs in this line
2465 lvxl v26,0,r11
2466 lvxl v27,r4,r11
2467
2468vr_ld32test28: ; here to handle next cache line
2469 la r11,savevr28(r3) ; get offset to next cache line
2470 bt 28,vr_ld32load28 ; skip if we must load this line
2471 vor v28,v31,v31 ; neither VR is live, so bug them both
2472 vor v29,v31,v31
2473 b vr_ld32test30
2474vr_ld32load28: ; must load VRs in this line
2475 lvxl v28,0,r11
2476 lvxl v29,r4,r11
2477
2478vr_ld32test30: ; here to handle next cache line
2479 la r11,savevr30(r3) ; get offset to next cache line
2480 bt 30,vr_ld32load30 ; skip if we must load this line
2481 vor v30,v31,v31 ; neither VR is live, so bug them both
2482 blr
2483vr_ld32load30: ; must load VRs in this line
2484 lvxl v30,0,r11
2485 lvxl v31,r4,r11
2486 blr