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