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