]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/cswtch.s
8a4d0ac657c9bb3303a45e937edabb044790193b
[apple/xnu.git] / osfmk / ppc / cswtch.s
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25
26 #include <ppc/asm.h>
27 #include <ppc/proc_reg.h>
28 #include <cpus.h>
29 #include <assym.s>
30 #include <debug.h>
31 #include <mach/ppc/vm_param.h>
32 #include <ppc/exception.h>
33
34 #define FPVECDBG 0
35 #define GDDBG 0
36
37 .text
38
39 /*
40 * void load_context(thread_t thread)
41 *
42 * Load the context for the first kernel thread, and go.
43 *
44 * NOTE - if DEBUG is set, the former routine is a piece
45 * of C capable of printing out debug info before calling the latter,
46 * otherwise both entry points are identical.
47 */
48
49 ENTRY2(load_context, Load_context, TAG_NO_FRAME_USED)
50
51 /*
52 * Since this is the first thread, we came in on the interrupt
53 * stack. The first thread never returns, so there is no need to
54 * worry about saving its frame, hence we can reset the istackptr
55 * back to the saved_state structure at it's top
56 */
57
58
59 /*
60 * get new thread pointer and set it into the active_threads pointer
61 *
62 */
63
64 mfsprg r6,0
65 lwz r0,PP_INTSTACK_TOP_SS(r6)
66 lwz r11,PP_CPU_DATA(r6)
67 stw r0,PP_ISTACKPTR(r6)
68 stw r3,CPU_ACTIVE_THREAD(r11)
69
70 /* Find the new stack and store it in active_stacks */
71
72 lwz r12,PP_ACTIVE_STACKS(r6)
73 lwz r1,THREAD_KERNEL_STACK(r3)
74 lwz r9,THREAD_TOP_ACT(r3) /* Point to the active activation */
75 stw r1,0(r12)
76 li r0,0 /* Clear a register */
77 lwz r8,ACT_MACT_PCB(r9) /* Get the savearea used */
78 lwz r10,SAVflags(r8) /* Get the savearea flags */
79 rlwinm r7,r8,0,0,19 /* Switch to savearea base */
80 lwz r11,SAVprev(r8) /* Get the previous savearea */
81 mfmsr r5 /* Since we are passing control, get our MSR values */
82 lwz r1,saver1(r8) /* Load new stack pointer */
83 rlwinm r10,r10,0,1,31 /* Remove the attached flag */
84 stw r0,saver3(r8) /* Make sure we pass in a 0 for the continuation */
85 lwz r7,SACvrswap(r7) /* Get the translation from virtual to real */
86 stw r0,FM_BACKPTR(r1) /* zero backptr */
87 stw r5,savesrr1(r8) /* Pass our MSR to the new guy */
88 stw r10,SAVflags(r8) /* Pass back the flags */
89 xor r3,r7,r8 /* Get the physical address of the new context save area */
90 stw r11,ACT_MACT_PCB(r9) /* Unstack our savearea */
91 b EXT(exception_exit) /* Go end it all... */
92
93 /* struct thread_shuttle *Switch_context(struct thread_shuttle *old,
94 * void (*cont)(void),
95 * struct thread_shuttle *new)
96 *
97 * Switch from one thread to another. If a continuation is supplied, then
98 * we do not need to save callee save registers.
99 *
100 */
101
102 /* void Call_continuation( void (*continuation)(void), vm_offset_t stack_ptr)
103 */
104
105 ENTRY(Call_continuation, TAG_NO_FRAME_USED)
106 mtlr r3
107 mr r1, r4 /* Load new stack pointer */
108 blr /* Jump to the continuation */
109
110 /*
111 * Get the old kernel stack, and store into the thread structure.
112 * See if a continuation is supplied, and skip state save if so.
113 * NB. Continuations are no longer used, so this test is omitted,
114 * as should the second argument, but it is in generic code.
115 * We always save state. This does not hurt even if continuations
116 * are put back in.
117 */
118
119 /* Context switches are double jumps. We pass the following to the
120 * context switch firmware call:
121 *
122 * R3 = switchee's savearea
123 * R4 = old thread
124 * R5 = new SRR0
125 * R6 = new SRR1
126 *
127 * savesrr0 is set to go to switch_in
128 * savesrr1 is set to uninterruptible with translation on
129 */
130
131
132 ENTRY(Switch_context, TAG_NO_FRAME_USED)
133
134 mfsprg r6,0 /* Get the per_proc block */
135 lwz r12,PP_ACTIVE_STACKS(r6)
136 #if DEBUG
137 lwz r11,PP_ISTACKPTR(r6) ; (DEBUG/TRACE) make sure we are not
138 mr. r11,r11 ; (DEBUG/TRACE) on the interrupt
139 bne+ notonintstack ; (DEBUG/TRACE) stack
140 BREAKPOINT_TRAP
141 notonintstack:
142 #endif
143 stw r4,THREAD_CONTINUATION(r3)
144 cmpwi cr1,r4,0 /* used waaaay down below */
145 lwz r7,0(r12)
146 /*
147 * Make the new thread the current thread.
148 */
149
150 lwz r11,PP_CPU_DATA(r6)
151 stw r7,THREAD_KERNEL_STACK(r3)
152 stw r5, CPU_ACTIVE_THREAD(r11)
153
154 lwz r11,THREAD_KERNEL_STACK(r5)
155
156 lwz r5,THREAD_TOP_ACT(r5)
157 lwz r10,PP_ACTIVE_STACKS(r6)
158 lwz r7,CTHREAD_SELF(r5) ; Pick up the user assist word
159 lwz r8,ACT_MACT_PCB(r5) ; Get the PCB for the new guy
160
161 stw r11,0(r10) ; Save the kernel stack address
162 stw r7,UAW(r6) ; Save the assist word for the "ultra fast path"
163
164 lwz r11,ACT_MACT_BTE(r5) ; Get BlueBox Task Environment
165
166 lwz r7,ACT_MACT_SPF(r5) ; Get the special flags
167
168 lwz r10,ACT_KLOADED(r5)
169 stw r11,ppbbTaskEnv(r6) ; Save the bb task env
170 li r0,0
171 cmpwi cr0,r10,0
172 lwz r10,PP_ACTIVE_KLOADED(r6)
173 stw r7,spcFlags(r6) ; Set per_proc copy of the special flags
174 beq cr0,.L_sw_ctx_not_kld
175
176 stw r5,0(r10)
177 b .L_sw_ctx_cont
178
179 .L_sw_ctx_not_kld:
180 stw r0,0(r10) /* act_kloaded = 0 */
181
182 .L_sw_ctx_cont:
183 lis r10,hi16(EXT(trcWork)) ; Get top of trace mask
184 rlwinm r7,r8,0,0,19 /* Switch to savearea base */
185 ori r10,r10,lo16(EXT(trcWork)) ; Get bottom of mask
186 lwz r11,SAVprev(r8) /* Get the previous of the switchee's savearea */
187 lwz r10,traceMask(r10) ; Get the enabled traces
188 lis r0,hi16(CutTrace) ; Trace FW call
189 mr. r10,r10 ; Any tracing going on?
190 ori r0,r0,lo16(CutTrace) ; Trace FW call
191 beq+ cswNoTrc ; No trace today, dude...
192 mr r10,r3 ; Save across trace
193 lwz r2,THREAD_TOP_ACT(r3) ; Trace old activation
194 mr r3,r11 ; Trace prev savearea
195 sc ; Cut trace entry of context switch
196 mr r3,r10 ; Restore
197
198 cswNoTrc: mfmsr r6 /* Get the MSR because the switched to thread should inherit it */
199 lwz r7,SACvrswap(r7) /* Get the translation from virtual to real */
200 lis r0,hi16(SwitchContextCall) /* Top part of switch context */
201 lis r9,hi16(EXT(switch_in)) /* Get top of switch in routine */
202 stw r11,ACT_MACT_PCB(r5) /* Dequeue the savearea we're switching to */
203
204 rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 /* Turn off the FP */
205 ori r9,r9,lo16(EXT(switch_in)) /* Bottom half of switch in */
206 lwz r5,savesrr0(r8) /* Set up the new SRR0 */
207 rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 /* Turn off the vector */
208 mr r4,r3 /* Save our old thread to pass back */
209 stw r9,savesrr0(r8) /* Make us jump to the switch in routine */
210 li r10,MSR_SUPERVISOR_INT_OFF /* Get the switcher's MSR */
211 lwz r9,SAVflags(r8) /* Get the flags */
212 stw r10,savesrr1(r8) /* Set up for switch in */
213 rlwinm r9,r9,0,15,13 /* Reset the syscall flag */
214 ori r0,r0,lo16(SwitchContextCall) /* Bottom part of switch context */
215 rlwinm r9,r9,0,1,31 /* Clear the attached flag */
216 xor r3,r7,r8 /* Get the physical address of the new context save area */
217 stw r9,SAVflags(r8) /* Set the flags */
218 /* if blocking on continuation avoid saving state */
219 bne cr1,1f
220 sc /* Switch to the new context */
221
222 /* We come back here in the new thread context
223 * R4 was set to hold the old thread pointer, but switch_in will put it into
224 * R3 where it belongs.
225 */
226 blr /* Jump into the new thread */
227
228 1: stw r5,savesrr0(r8) /* go to real pc */
229 stw r4,saver3(r8) /* must pass back old thread */
230 b EXT(exception_exit) /* blocking on continuation, avoid state save */
231
232
233
234 /*
235 * All switched to threads come here first to clean up the old thread.
236 * We need to do the following contortions because we need to keep
237 * the LR clean. And because we need to manipulate the savearea chain
238 * with translation on. If we could, this should be done in lowmem_vectors
239 * before translation is turned on. But we can't, dang it!
240 *
241 * R3 = switcher's savearea
242 * saver4 = old thread in switcher's save
243 * saver5 = new SRR0 in switcher's save
244 * saver6 = new SRR1 in switcher's save
245
246
247 */
248
249 ENTRY(switch_in, TAG_NO_FRAME_USED)
250
251 lwz r4,saver4(r3) /* Get the old thread */
252 li r8,MSR_VM_OFF /* Set to everything off */
253 lwz r9,THREAD_TOP_ACT(r4) /* Get the switched from ACT */
254 lwz r5,saver5(r3) /* Get the srr0 value */
255 lwz r10,ACT_MACT_PCB(r9) /* Get the top PCB on the old thread */
256 lwz r6,saver6(r3) /* Get the srr1 value */
257
258 stw r3,ACT_MACT_PCB(r9) /* Put the new one on top */
259 stw r10,SAVprev(r3) /* Chain on the old one */
260
261 mr r3,r4 /* Pass back the old thread */
262
263 mtsrr0 r5 /* Set return point */
264 mtsrr1 r6 /* Set return MSR */
265 rfi /* Jam... */
266 .long 0
267 .long 0
268 .long 0
269 .long 0
270 .long 0
271 .long 0
272 .long 0
273 .long 0
274
275
276
277 /*
278 * void fpu_save(thread_act_t act)
279 *
280 * To do the floating point and VMX, we keep three thread pointers: one
281 * to the current thread, one to the thread that has the floating point context
282 * loaded into the FPU registers, and one for the VMX owner.
283 *
284 * Each of these threads has three PCB pointers. The normal PCB, the FPU pcb,
285 * and the VMX pcb. There is also a bit for each in the savearea flags.
286 * When we take an exception, or need to use the FPU/VMX in the kernel, we call
287 * this routine. It checks to see if there is an owner thread for the facility.
288 * If so, it saves the facility's state information in the normal PCB. Then, it
289 * turns on the appropriate flag in the savearea to indicate that the state is
290 * in that particular savearea. Also, the thread pointer for the owner in
291 * the per_processor block is cleared. Note that we don't have to worry about the
292 * PCB pointers in the thread because whenever the state is loaded, the associated
293 * savearea is released and the pointer cleared. This is done so that the facility
294 * context always migrates to the normal savearea/PCB. This always insures that
295 * no more than 2 saveareas are used for a thread.
296 *
297 * When the context is loaded into the facility, the associated PCB is released if
298 * its usage flags indicate that it is empty. (Note that return from exception and
299 * context switch honor these flags and won't release a savearea if there is unrestored
300 * facility context.) The per_processor is set to point to the facility owner's
301 * thread and the associated PCB pointer within the thread is cleared because
302 * the PCB has been released.
303 *
304 * Part of loading a context is to release the savearea. If the savearea contains
305 * other context, the savearea cannot be released. So, what we're left with is
306 * that there will be no normal context savearea, but one for the as-not-yet
307 * restored facility savearea. Again, when that context is reloaded, the PCB
308 * is released, and when it is again stored, it goes into the "normal" savearea.
309 *
310 * So, what do we do when there is no general context, and we have some FPU/VMX
311 * state to save? Heck if I know, but it happens when we switch threads when
312 * we shortcut system calls. The question is: does the target thread carry the
313 * FPU/VMX context with it or not? Actually, it don't matter, not one little bit.
314 * If we are asked to save it, we gotta. It's a really lousy way to do it, but
315 * short of starting over with FPUs, it's what's what. Therefore, we'll
316 * allocate an FPU context save and attach it.
317 *
318 * Actually, it's not quite that simple: since we aren't in
319 * in interrupt handler context (that's only in fpu_switch) we can't use
320 * quickfret to merge FPU into general context. So, if there is an FPU
321 * savearea, we need to use that. So what we do is: if there is FPU context
322 * use that. If there is a general context, then use that. If neither,
323 * allocate a savearea and make that the FPU context.
324 *
325 * The next thing we have to do is to allow the kernel to use both the
326 * floating point and Altivec. It is not recommended, but there may be a
327 * good reason to do so. So, what we need to do is to treat each of the
328 * three types of context the same, by keeping a LIFO chain of states.
329 * We do have a problem with that in that there can be multiple levels of
330 * kernel context. For example, we are using floating point and we take a
331 * page fault, and somehow start using the FPU, and take another page fault,
332 * etc.
333 *
334 * Anyway, we will hope that we only reasonably use floating point and vectors in
335 * the kernel. And try to pack the context in as few saveareas as possible.
336 *
337 * The way we keep these "levels" of floating point or vector context straight is
338 * to remember the top of the normal savearea chain when we activate the
339 * facility when it is first used. Then, when we save that context, this value
340 * is saved in its level field.
341 *
342 * What the level concept gives us is a way to distinguish between multiple
343 * independent contexts under the same thread activation. Any time we take
344 * any kind of interruption (trap, system call, I/O interruption), we are,
345 * in effect, running with a different context even though we are in the
346 * same thread. The top savearea address is used only as a marker. It does not
347 * point to any context associated with the float or vector context. For example,
348 * the top savearea pointer will always be 0 for the user context, because there
349 * it it always last on the list.
350 *
351 * As normal context is unstacked, the first facility context is checked and
352 * if there is a match, the facility savearea is released. This is because we
353 * are returning to a level before the facility saved there was used. In effect,
354 * this allows us to unwind the facility context saveareas at different rates.
355 *
356 * In conjunction with the current activation, these markers are also used to
357 * determine the state of the facility enablement. Whenever the facility context is
358 * "live," i.e., loaded in the hardware registers and belonging to the currently
359 * running context, the facility is enabled before dispatch.
360 *
361 * There is nothing special about using floating point or vector facilities,
362 * no preliminary saving, enabling, or disabling. You just use them. The only exception
363 * is during context switching on an SMP system. In this case, the context must
364 * be saved as there is no guarantee that the thread will resume on the same
365 * processor. This is not a good thing, not at all.
366 *
367 * Whenever we switch out a thread with a dirty context, we always need to save it
368 * because it can wake up on a different processor. However, once the context has
369 * been saved, we don't need to save it again until it gets dirty, nor do we need
370 * to reload it unless someone else's context has been loaded. To handle this
371 * optimization, we need 3 things. We need to know what processor the saved context
372 * was last loaded on, whether the loaded context could be dirty, and if we've already
373 * saved it.
374 *
375 * Whenever the facility is enabled, the processor ID is saved in the activation. This
376 * will show which processor has dirty data. When a context switch occurs, the facility
377 * contexts are saved, but are still remembered as live. The next time we need to
378 * context switch, we first check if the state is live, and if not, do no state
379 * saving. Then we check if the state has already been save and if not, save it.
380 * The facility is always disabled on a context switch. On a UP, this save function
381 * does not occur.
382 *
383 * Whenever a facility unavailable interruption occurs, the current state is saved
384 * if it is live and unsaved. However, if the live state is the same as the new
385 * one to be loaded, the processor ID is checked and if it is the current processor
386 * the state does not need to be loaded or saved. The facility is simply enabled.
387 *
388 * Once allocated, facility saveareas are not released until a return is made to a
389 * previous level. Once a facility has been enabled, there is no way to tell if
390 * it will ever be used again, but it is likely. Therefore, discarding a savearea
391 * when its context is made live is extra overhead. So, we don't do it, but we
392 * do mark the savearea contents as invalid.
393 *
394 */
395
396 /*
397 ; The following is the actual way it is implemented. It doesn't quite match
398 ; the above text. I need to go and fix that.
399 ;
400 ; Context download (operates on owner's data):
401 ;
402 ; 0) enable facility
403 ; 1) if no owner exit to context restore
404 ; 2) if context processor != current processor exit to context restore
405 ; 3) if current activation == owner activation:
406 ; 1) if curr level == active level:
407 ; 1) if top facility savearea exists:
408 ; invalidate savearea by setting level to 1
409 ; 2) enable facility for user
410 ; 3) exit
411 ;
412 ; 2) else go to 5
413 ;
414 ; 4) if curr level == active level:
415 ; 1) if top facility savearea exists:
416 ; 1) if top save level == active level exit to context restore
417 ;
418 ; 5) allocate savearea
419 ; 1) if there is a facility save and it is invalid, select it, and break
420 ; 2) scan normal list for free facility area, select if found, and break
421 ; 3) scan other facility for free save: select, if found, and break
422 ; 4) allocate a new save area
423 ;
424 ; 6) save context
425 ; 7) mark facility save with curr level
426 ; 8) if reusing cached savearea (case #1) exit to context restore
427 ; 9) set facility save backchain to facility top savearea
428 ; 10) set facility top to savearea
429 ; 11) exit to context restore
430 ;
431 ;
432 ; Context restore/upload (operates on current activation's data):
433 ;
434 ; 1) set current to activation
435 ; 2) set active level to current level
436 ; 3) set context processor to current processor
437 ; 4) if no facility savearea or top save level != curr level
438 ; initialize facility registers to empty value
439 ; 5) else
440 ; 1) load registers from savearea
441 ; 2) invalidate save area by setting level to 1
442 ;
443 ; 6) enable facility for user
444 ; 7) exit to interrupt return
445 ;
446 ;
447 ; Context save (operates on specified activation's data):
448
449 ; 1) if no owner exit
450 ; 2) if owner != specified activation exit
451 ; 3) if context processor != current processor
452 ; 1) clear owner
453 ; 2) exit
454 ;
455 ; 4) if facility top savearea level exists and == active level exit
456 ; 5) if curr level != active level exit
457 ; 6) allocate savearea
458 ; 1) if there is a facility save and it is invalid, select it, and break
459 ; 2) scan normal list for free facility area, select if found, and break
460 ; 3) scan other facility for free save: select, if found, and break
461 ; 4) allocate a new save area
462 ; 7) save context
463 ; 8) mark facility savearea with curr level
464 ; 9) if reusing cached savearea (case #1) exit
465 ; 10) set facility save backchain to facility top savearea
466 ; 11) set facility top to savearea
467 ; 12) exit
468 ;
469 ;
470 ; Exception exit (hw_exceptions):
471 ;
472 ; 1) disable return facility
473 ; 2) if returning savearea != active level
474 ; 1) if owner != current activation exit
475 ; 2) if context processor != current processor:
476 ; 1) clear owner
477 ; 2) exit
478 ;
479 ; 3) if new level != active level exit
480 ; 4) enable return facility
481 ; 5) exit
482 ;
483 ; 3) if no facility savearea exit
484 ; 4) if top save level == active or top is invalid
485 ; 1) dequeue top facility savearea
486 ; 2) set active level to new top savearea's level
487 ; 3) release savearea
488 ; 4) if owner == current activation clear owner
489 ; 5) exit
490 ;
491 ;
492 ;
493 ;
494 ; if (owner == activation) && (curr level == active level)
495 ; && (activation processor == current processor) ::= context live
496 */
497
498 ENTRY(fpu_save, TAG_NO_FRAME_USED)
499
500 mfmsr r0 ; Get the MSR
501 rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off floating point forever
502 rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; But do interrupts only for now
503 ori r2,r2,MASK(MSR_FP) ; Enable the floating point feature for now also
504 mtmsr r2 ; Set the MSR
505 isync
506
507 mfsprg r6,0 ; Get the per_processor block
508 lwz r12,PP_FPU_THREAD(r6) ; Get the thread that owns the FPU
509 #if FPVECDBG
510 mr r7,r0 ; (TEST/DEBUG)
511 li r4,0 ; (TEST/DEBUG)
512 mr r10,r3 ; (TEST/DEBUG)
513 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
514 mr. r3,r12 ; (TEST/DEBUG)
515 li r2,0x6F00 ; (TEST/DEBUG)
516 li r5,0 ; (TEST/DEBUG)
517 beq- noowneryet ; (TEST/DEBUG)
518 lwz r4,ACT_MACT_FPUlvl(r12) ; (TEST/DEBUG)
519 lwz r5,ACT_MACT_FPU(r12) ; (TEST/DEBUG)
520
521 noowneryet: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
522 sc ; (TEST/DEBUG)
523 mr r0,r7 ; (TEST/DEBUG)
524 mr r3,r10 ; (TEST/DEBUG)
525 #endif
526 mflr r2 ; Save the return address
527 lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number
528
529 mr. r12,r12 ; Anyone own the FPU?
530 cmplw cr1,r3,r12 ; Is the specified thread the owner?
531
532 beq- fsretnr ; Nobody owns the FPU, no save required...
533
534 li r4,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word
535 bne- cr1,fsretnr ; Facility belongs to some other activation...
536
537 fsvSpin2: lwarx r9,r4,r12 ; Get and reserve the last used CPU
538 mr. r9,r9 ; Is it changing now?
539 oris r3,r9,hi16(fvChk) ; Set the "changing" flag
540 blt- fsvSpin2 ; Spin if changing
541 stwcx. r3,r4,r12 ; Lock it up
542 bne- fsvSpin2 ; Someone is messing right now
543
544 isync ; Make sure we see everything
545
546 cmplw cr1,r9,r11 ; Was the context for this processor?
547 li r3,0 ; Assume we need a fix-me-up
548 beq- cr1,fsgoodcpu ; Facility last used on this processor...
549 stw r3,PP_FPU_THREAD(r6) ; Clear owner because it was really on the other processor
550 b fsret ; Bail now with no save...
551
552 fsgoodcpu: lwz r3,ACT_MACT_FPU(r12) ; Get the current FPU savearea for the thread
553 lwz r9,ACT_MACT_FPUlvl(r12) ; Get our current level indicator
554
555 cmplwi cr1,r3,0 ; Have we ever saved this facility context?
556 beq- cr1,fsneedone ; Never saved it, so we need an area...
557
558 lwz r8,SAVlvlfp(r3) ; Get the level this savearea is for
559 cmplwi r8,1 ; See if it is a spare
560 cmplw cr1,r9,r8 ; Correct level?
561 beq+ fsusespare ; We have a spare to use...
562 beq- cr1,fsret ; The current level is already saved, bail out...
563
564 fsneedone: li r3,0 ; Tell the routine to allocate an area if none found
565 bl fpsrchsave ; Find a free savearea
566
567 mfsprg r6,0 ; Get back per_processor block
568 oris r7,r7,hi16(SAVfpuvalid) ; Set the allocated bit
569 lwz r12,PP_FPU_THREAD(r6) ; Get back our thread
570 mtlr r2 ; Restore return
571 lwz r8,ACT_MACT_FPU(r12) ; Get the current top floating point savearea
572 lwz r9,ACT_MACT_FPUlvl(r12) ; Get our current level indicator again
573 stw r3,ACT_MACT_FPU(r12) ; Set this as the latest FPU savearea for the thread
574 stw r8,SAVprefp(r3) ; And then chain this in front
575 stw r7,SAVflags(r3) ; Set the validity flags
576 stw r12,SAVact(r3) ; Make sure we point to the right guy
577
578 fsusespare: stw r9,SAVlvlfp(r3) ; And set the level this savearea is for
579
580 ;
581 ; Save the current FPU state into the PCB of the thread that owns it.
582 ;
583
584 la r11,savefp0(r3) ; Point to the 1st line
585 dcbz 0,r11 ; Allocate the first savearea line
586
587 la r11,savefp4(r3) /* Point to the 2nd line */
588 stfd f0,savefp0(r3)
589 dcbz 0,r11 /* allocate it */
590 stfd f1,savefp1(r3)
591 stfd f2,savefp2(r3)
592 la r11,savefp8(r3) /* Point to the 3rd line */
593 stfd f3,savefp3(r3)
594 dcbz 0,r11 /* allocate it */
595 stfd f4,savefp4(r3)
596 stfd f5,savefp5(r3)
597 stfd f6,savefp6(r3)
598 la r11,savefp12(r3) /* Point to the 4th line */
599 stfd f7,savefp7(r3)
600 dcbz 0,r11 /* allocate it */
601 stfd f8,savefp8(r3)
602 stfd f9,savefp9(r3)
603 stfd f10,savefp10(r3)
604 la r11,savefp16(r3) /* Point to the 5th line */
605 stfd f11,savefp11(r3)
606 dcbz 0,r11 /* allocate it */
607 stfd f12,savefp12(r3)
608 stfd f13,savefp13(r3)
609 stfd f14,savefp14(r3)
610 la r11,savefp20(r3) /* Point to the 6th line */
611 stfd f15,savefp15(r3)
612 stfd f16,savefp16(r3)
613 stfd f17,savefp17(r3)
614 stfd f18,savefp18(r3)
615 la r11,savefp24(r3) /* Point to the 7th line */
616 stfd f19,savefp19(r3)
617 dcbz 0,r11 /* allocate it */
618 stfd f20,savefp20(r3)
619 lwz r10,liveFPSCR(r6) ; Get the previously saved FPSCR
620 stfd f21,savefp21(r3)
621 stfd f22,savefp22(r3)
622 li r9,0 ; Just clear this out
623 la r11,savefp28(r3) /* Point to the 8th line */
624 stfd f23,savefp23(r3)
625 dcbz 0,r11 /* allocate it */
626 stfd f24,savefp24(r3)
627 stfd f25,savefp25(r3)
628 stfd f26,savefp26(r3)
629 stfd f27,savefp27(r3)
630 stfd f28,savefp28(r3)
631
632 ; Note that we just save the FPSCR here for ease. It is really already saved
633 ; in the "normal" context area of the savearea.
634
635 stw r9,savefpscrpad(r3) ; Save the FPSCR pad
636 stw r10,savefpscr(r3) ; Save the FPSCR
637
638 stfd f29,savefp29(r3)
639 stfd f30,savefp30(r3)
640 stfd f31,savefp31(r3)
641 lfd f0,savefp0(r3) ; We need to restore F0 because we used it
642 ; to get the FPSCR
643
644 #if 0
645 la r9,savefp0(r3) ; (TEST/DEBUG)
646 la r10,savefp31(r3) ; (TEST/DEBUG)
647
648 chkkillmedead:
649 lha r8,0(r9) ; (TEST/DEBUG)
650 addi r9,r9,8 ; (TEST/DEBUG)
651 cmpwi r8,-8 ; (TEST/DEBUG)
652 cmplw cr1,r9,r10 ; (TEST/DEBUG)
653 bne+ dontkillmedead ; (TEST/DEBUG)
654 BREAKPOINT_TRAP ; (TEST/DEBUG)
655
656 dontkillmedead: ; (TEST/DEBUG)
657 ble+ cr1,chkkillmedead ; (TEST/DEBUG)
658 #endif
659
660 fsret: lwz r4,ACT_MACT_FPUcpu(r12) ; Get back the owner CPU
661 rlwinm r4,r4,0,fvChkb+1,31 ; Clear lock
662 sync
663 stw r4,ACT_MACT_FPUcpu(r12) ; Unlock the context
664
665 fsretnr: mtmsr r0 ; Put interrupts on if they were and floating point off
666 isync
667
668 blr
669
670 /*
671 * fpu_switch()
672 *
673 * Entered to handle the floating-point unavailable exception and
674 * switch fpu context
675 *
676 * This code is run in virtual address mode on with interrupts off.
677 *
678 * Upon exit, the code returns to the users context with the floating
679 * point facility turned on.
680 *
681 * ENTRY: VM switched ON
682 * Interrupts OFF
683 * State is saved in savearea pointed to by R4.
684 * All other registers are free.
685 *
686 */
687
688 ENTRY(fpu_switch, TAG_NO_FRAME_USED)
689 #if DEBUG
690 #if GDDBG
691 mr r7,r4 ; Save input parameter
692 lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter
693 ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter
694 lwz r1,0(r3)
695 lis r5,hi16(EXT(GratefulDeb)) ; Point to top of display
696 ori r5,r5,lo16(EXT(GratefulDeb)) ; Put in bottom part
697 addi r1,r1,1
698 mtlr r5 ; Set link register
699 stw r1,0(r3)
700 mr r4,r1
701 li r3,0
702 blrl ; Display count
703 mr r4,r7 ; Restore the parameter
704 #else
705 lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter
706 ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter
707 lwz r1,0(r3)
708 addi r1,r1,1
709 stw r1,0(r3)
710 #endif
711 #endif /* DEBUG */
712
713 mfsprg r6,0 ; Get the per_processor block
714 mfmsr r19 ; Get the current MSR
715
716 lwz r10,PP_CPU_DATA(r6) ; Get the CPU data pointer
717 lwz r12,PP_FPU_THREAD(r6) ; Get the thread that owns the FPU
718 lwz r10,CPU_ACTIVE_THREAD(r10) ; Get the pointer to the active thread
719 ori r19,r19,lo16(MASK(MSR_FP)) ; Enable the floating point feature
720 lwz r17,THREAD_TOP_ACT(r10) ; Now get the activation that is running
721
722 ; R12 has the "old" activation
723 ; R17 has the "new" activation
724
725 #if FPVECDBG
726 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
727 li r2,0x7F01 ; (TEST/DEBUG)
728 mr r3,r12 ; (TEST/DEBUG)
729 mr r5,r17 ; (TEST/DEBUG)
730 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
731 sc ; (TEST/DEBUG)
732 #endif
733 mr. r12,r12 ; See if there is any live FP status
734
735 lhz r18,PP_CPU_NUMBER(r6) ; Get the current CPU, we will need it later
736
737 mtmsr r19 ; Enable floating point instructions
738 isync
739
740 beq- fsnosave ; No live context, so nothing to save...
741
742 li r20,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word
743
744 fsSpin1: lwarx r19,r20,r12 ; Get and reserve the last used CPU
745 mr. r19,r19 ; Is it changing now?
746 oris r21,r19,hi16(fvChk) ; Set the "changing" flag
747 blt- fsSpin1 ; Spin if changing
748 stwcx. r21,r20,r12 ; Lock it up
749 bne- fsSpin1 ; Someone is messing right now
750
751 isync ; Make sure we see everything
752
753 lwz r15,ACT_MACT_PCB(r12) ; Get the current level of the "old" one
754 cmplw r18,r19 ; Check the CPU that the old context is live on
755 lwz r14,ACT_MACT_FPU(r12) ; Point to the top of the old context stack
756 bne- fsnosaverel ; Context is not live if used on a different CPU...
757 lwz r13,ACT_MACT_FPUlvl(r12) ; Get the "old" active level
758
759 ;
760 ; First, check to see if all we are doing is enabling because the
761 ; "new" context is live.
762 ;
763 #if FPVECDBG
764 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
765 li r2,0x7F02 ; (TEST/DEBUG)
766 mr r1,r15 ; (TEST/DEBUG)
767 mr r3,r13 ; (TEST/DEBUG)
768 mr r5,r14 ; (TEST/DEBUG)
769 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
770 sc ; (TEST/DEBUG)
771 #endif
772
773 cmplw cr1,r12,r17 ; Are the "old" activation and the "new" the same?
774 cmplwi cr2,r14,0 ; Is there any saved context on the "old" activation?
775 bne+ cr1,fsmstsave ; The activations are different so "old" context must be saved...
776
777 ;
778 ; Here we know that both the "old" and "new" activations are the same. We will
779 ; check the current level and active levels. If they are the same, the context is
780 ; already live, so all we do is turn on the facility and invalidate the top
781 ; savearea.
782 ;
783 ; If the current level, the active level, and the top savearea level are the
784 ; same, then the context was saved as part of a thread context switch and neither
785 ; needs saving or restoration.
786 ;
787 ; In all other cases, the context must be saved unless we are just re-enabling
788 ; floating point.
789 ;
790
791 cmplw r13,r15 ; Are the levels the same?
792 cmplwi cr2,r14,0 ; Is there any saved context?
793 bne- fsmstsave ; Levels are different, we need to save...
794
795 beq- cr2,fsenableret ; No saved context at all, enable and go...
796
797 lwz r20,SAVlvlfp(r14) ; Get the level of the top savearea
798
799 #if FPVECDBG
800 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
801 li r2,0x7F03 ; (TEST/DEBUG)
802 mr r3,r15 ; (TEST/DEBUG)
803 mr r5,r20 ; (TEST/DEBUG)
804 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
805 sc ; (TEST/DEBUG)
806 #endif
807 cmplw r15,r20 ; Is the top level the same as the current?
808 li r0,1 ; Get the invalid flag
809 bne- fsenableret ; Not the same, just enable and go...
810
811 stw r0,SAVlvlfp(r14) ; Invalidate that top savearea
812 fsenableret:
813 sync ; Make sure everything is saved
814 stw r19,ACT_MACT_FPUcpu(r12) ; Say we are not using the context anymore
815
816 b fsenable ; Then enable and go...
817
818 ;
819 ; We need to save the "old" context here. The LIFO queueing scheme works
820 ; out for all cases because if both the "new" and "old" activations are the
821 ; same, there can not be any saved state to load. the "new" level is
822 ; truely new.
823 ;
824 ; When we save the context, we either use a new savearea, or the free
825 ; one that is cached at the head of the list.
826
827 fsmstsave: beq- cr2,fsgetsave ; There is no possible cached save area
828
829 lwz r5,SAVlvlfp(r14) ; Get the level of first facility savearea
830 #if FPVECDBG
831 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
832 li r2,0x7F04 ; (TEST/DEBUG)
833 mr r3,r15 ; (TEST/DEBUG)
834 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
835 sc ; (TEST/DEBUG)
836 #endif
837 mr r3,r14 ; Assume we are invalid
838 cmplwi r5,1 ; Is it invalid?
839 cmplw cr1,r5,r13 ; Is the SA level the active one?
840 beq+ fsusecache ; Invalid, just use it...
841 beq- cr1,fsnosaverel ; The SA level is active, it is already saved...
842
843 fsgetsave: mr r3,r4 ; Use the interrupt save as the context savearea if none cached
844 #if FPVECDBG
845 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
846 li r2,0x7F05 ; (TEST/DEBUG)
847 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
848 sc ; (TEST/DEBUG)
849 #endif
850
851 bl fpsrchsave ; Find a free savearea
852
853 stw r3,ACT_MACT_FPU(r12) ; Set this as the latest context savearea for the thread
854 mfsprg r6,0 ; Get back per_processor block
855 stw r14,SAVprefp(r3) ; And then chain this in front
856 oris r7,r7,hi16(SAVfpuvalid) ; Set the allocated bit
857 stw r12,SAVact(r3) ; Make sure we point to the right guy
858 stw r7,SAVflags(r3) ; Set the allocation flags
859
860 fsusecache: la r11,savefp0(r3) ; Point to the 1st line in area
861 stw r13,SAVlvlfp(r3) ; Set this context level
862 #if FPVECDBG
863 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
864 li r2,0x7F06 ; (TEST/DEBUG)
865 mr r5,r13 ; (TEST/DEBUG)
866 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
867 sc ; (TEST/DEBUG)
868 #endif
869
870 ;
871 ; Now we will actually save the old context
872 ;
873
874 dcbz 0,r11 ; Allocate the output area
875
876 la r11,savefp4(r3) ; Point to the 2nd line
877 stfd f0,savefp0(r3)
878 dcbz 0,r11 ; Allocate cache
879 stfd f1,savefp1(r3)
880 stfd f2,savefp2(r3)
881 la r11,savefp8(r3) ; Point to the 3rd line
882 stfd f3,savefp3(r3)
883 dcbz 0,r11 ; Allocate cache
884 stfd f4,savefp4(r3)
885 stfd f5,savefp5(r3)
886 stfd f6,savefp6(r3)
887 la r11,savefp12(r3) ; Point to the 4th line
888 stfd f7,savefp7(r3)
889 dcbz 0,r11 ; Allocate cache
890 stfd f8,savefp8(r3)
891 stfd f9,savefp9(r3)
892 stfd f10,savefp10(r3)
893 la r11,savefp16(r3) ; Point to the 5th line
894 stfd f11,savefp11(r3)
895 dcbz 0,r11 ; Allocate cache
896 stfd f12,savefp12(r3)
897 stfd f13,savefp13(r3)
898 stfd f14,savefp14(r3)
899 la r11,savefp20(r3) ; Point to the 6th line
900 stfd f15,savefp15(r3)
901 dcbz 0,r11 ; Allocate cache
902 stfd f16,savefp16(r3)
903 stfd f17,savefp17(r3)
904 stfd f18,savefp18(r3)
905 la r11,savefp24(r3) ; Point to the 7th line
906 stfd f19,savefp19(r3)
907 dcbz 0,r11 ; Allocate cache
908 stfd f20,savefp20(r3)
909
910 li r14,0 ; Clear this for now
911 lwz r15,liveFPSCR(r6) ; Get the previously saved FPSCR
912
913 stfd f21,savefp21(r3)
914 stfd f22,savefp22(r3)
915 la r11,savefp28(r3) ; Point to the 8th line
916 stfd f23,savefp23(r3)
917 dcbz 0,r11 ; allocate it
918 stfd f24,savefp24(r3)
919 stfd f25,savefp25(r3)
920 stfd f26,savefp26(r3)
921 la r11,savefpscrpad(r3) ; Point to the 9th line
922 stfd f27,savefp27(r3)
923 dcbz 0,r11 ; allocate it
924 stfd f28,savefp28(r3)
925 stfd f29,savefp29(r3)
926 stfd f30,savefp30(r3)
927 stfd f31,savefp31(r3)
928
929 ; Note that we just save the FPSCR here for ease. It is really already saved
930 ; in the "normal" context area of the savearea.
931
932 stw r14,savefpscrpad(r3) ; Save the FPSCR pad
933 stw r15,savefpscr(r3) ; Save the FPSCR
934
935 ;
936 ; The context is all saved now and the facility is free.
937 ;
938 ; Now check out the "new" and see if we need to load up his context.
939 ; If we do (and this should be the normal case), do it and then invalidate the
940 ; savearea. (This will keep it cached for quick access next time around.)
941 ;
942 ; If we do not (remember, we already took care of the case where we just enable
943 ; the FPU), we need to fill the registers with junk, because this level has
944 ; never used them before and some thieving bastard could hack the old values
945 ; of some thread! Just imagine what would happen if they could! Why, nothing
946 ; would be safe! My God! It is terrifying!
947 ;
948
949
950 fsnosaverel:
951 sync ; Make sure everything is saved
952 stw r19,ACT_MACT_FPUcpu(r12) ; Say we are not using the context anymore
953
954 fsnosave:
955 li r20,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word
956
957 fsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU
958 mr. r19,r19 ; Is it changing now?
959 oris r21,r19,hi16(fvChk) ; Set the "changing" flag
960 blt- fsSpin2 ; Spin if changing
961 stwcx. r21,r20,r17 ; Lock it up
962 bne- fsSpin2 ; Someone is messing right now
963
964 isync ; Make sure we see everything
965
966 lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one
967 lwz r14,ACT_MACT_FPU(r17) ; Point to the top of the "new" context stack
968 lwz r13,ACT_MACT_FPUlvl(r17) ; Get the "new" active level
969 #if FPVECDBG
970 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
971 li r2,0x7F07 ; (TEST/DEBUG)
972 mr r1,r15 ; (TEST/DEBUG)
973 mr r3,r14 ; (TEST/DEBUG)
974 mr r5,r13 ; (TEST/DEBUG)
975 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
976 sc ; (TEST/DEBUG)
977 #endif
978
979 cmplwi cr1,r14,0 ; Do we possibly have some context to load?
980 stw r15,ACT_MACT_FPUlvl(r17) ; Set the "new" active level
981 la r11,savefp0(r14) ; Point to first line to bring in
982 stw r17,PP_FPU_THREAD(r6) ; Store current thread address in fpu_thread to claim fpu for thread
983
984 beq+ cr1,MakeSureThatNoTerroristsCanHurtUsByGod ; No "new" context to load...
985 lwz r0,SAVlvlfp(r14) ; Get the level of first facility savearea
986 cmplw r0,r15 ; Top level correct to load?
987 bne- MakeSureThatNoTerroristsCanHurtUsByGod ; No, go initialize...
988
989 #if FPVECDBG
990 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
991 li r2,0x7F08 ; (TEST/DEBUG)
992 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
993 sc ; (TEST/DEBUG)
994 #endif
995
996 dcbt 0,r11 ; Touch line in
997 li r0,1 ; Get the level invalid indication
998
999 la r11,savefp4(r14) ; Point to next line
1000 dcbt 0,r11 ; Touch line in
1001 lfd f0, savefp0(r14)
1002 lfd f1,savefp1(r14)
1003 stw r0,SAVlvlfp(r14) ; Mark the savearea invalid because we are activating again
1004 lfd f2,savefp2(r14)
1005 la r11,savefp8(r14) ; Point to next line
1006 lfd f3,savefp3(r14)
1007 dcbt 0,r11 ; Touch line in
1008 lfd f4,savefp4(r14)
1009 lfd f5,savefp5(r14)
1010 lfd f6,savefp6(r14)
1011 la r11,savefp12(r14) ; Point to next line
1012 lfd f7,savefp7(r14)
1013 dcbt 0,r11 ; Touch line in
1014 lfd f8,savefp8(r14)
1015 lfd f9,savefp9(r14)
1016 lfd f10,savefp10(r14)
1017 la r11,savefp16(r14) ; Point to next line
1018 lfd f11,savefp11(r14)
1019 dcbt 0,r11 ; Touch line in
1020 lfd f12,savefp12(r14)
1021 lfd f13,savefp13(r14)
1022 lfd f14,savefp14(r14)
1023 la r11,savefp20(r14) ; Point to next line
1024 lfd f15,savefp15(r14)
1025 dcbt 0,r11 ; Touch line in
1026 lfd f16,savefp16(r14)
1027 lfd f17,savefp17(r14)
1028 lfd f18,savefp18(r14)
1029 la r11,savefp24(r14) ; Point to next line
1030 lfd f19,savefp19(r14)
1031 dcbt 0,r11 ; Touch line in
1032 lfd f20,savefp20(r14)
1033 lfd f21,savefp21(r14)
1034 la r11,savefp28(r14) ; Point to next line
1035 lfd f22,savefp22(r14)
1036 lfd f23,savefp23(r14)
1037 dcbt 0,r11 ; Touch line in
1038 lfd f24,savefp24(r14)
1039 lfd f25,savefp25(r14)
1040 lfd f26,savefp26(r14)
1041 lfd f27,savefp27(r14)
1042 lfd f28,savefp28(r14)
1043 lfd f29,savefp29(r14)
1044 lfd f30,savefp30(r14)
1045 lfd f31,savefp31(r14)
1046
1047 fsenablexx: sync ; Make sure all is saved
1048 stw r18,ACT_MACT_FPUcpu(r17) ; Set the active CPU and release
1049
1050 fsenable: lwz r9,SAVflags(r4) /* Get the flags of the current savearea */
1051 lwz r8,savesrr1(r4) ; Get the msr of the interrupted guy
1052 rlwinm r5,r4,0,0,19 /* Get the page address of the savearea */
1053 ori r8,r8,MASK(MSR_FP) ; Enable the floating point feature
1054 lwz r10,ACT_MACT_SPF(r17) ; Get the special flags
1055 lis r7,hi16(SAVattach) /* Get the attached flag */
1056 lwz r5,SACvrswap(r5) /* Get Virtual to Real translation */
1057 oris r10,r10,hi16(floatUsed|floatCng) ; Set that we used floating point
1058 mr. r15,r15 ; See if we are doing this for user state
1059 stw r8,savesrr1(r4) ; Set the msr of the interrupted guy
1060 andc r9,r9,r7 /* Clear the attached bit */
1061 xor r3,r4,r5 /* Get the real address of the savearea */
1062 bne- fsnuser ; We are not user state...
1063 stw r10,ACT_MACT_SPF(r17) ; Set the activation copy
1064 stw r10,spcFlags(r6) ; Set per_proc copy
1065
1066 fsnuser:
1067 #if FPVECDBG
1068 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1069 li r2,0x7F0A ; (TEST/DEBUG)
1070 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1071 sc ; (TEST/DEBUG)
1072 #endif
1073 stw r9,SAVflags(r4) /* Set the flags of the current savearea */
1074
1075 b EXT(exception_exit) /* Exit from the fray... */
1076
1077 /*
1078 * Initialize the registers to some bogus value
1079 */
1080
1081 MakeSureThatNoTerroristsCanHurtUsByGod:
1082
1083 #if 0
1084 lwz r10,savesrr1(r4) ; (TEST/DEBUG)
1085 rlwinm. r10,r10,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG)
1086 beq- nxxxxxx ; (TEST/DEBUG)
1087 lwz r10,ACT_MACT_SPF(r17) ; (TEST/DEBUG)
1088 rlwinm. r10,r10,0,1,1 ; (TEST/DEBUG)
1089 beq+ nxxxxxx
1090 BREAKPOINT_TRAP ; (TEST/DEBUG)
1091 nxxxxxx:
1092 #endif
1093
1094 #if FPVECDBG
1095 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1096 li r2,0x7F09 ; (TEST/DEBUG)
1097 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1098 sc ; (TEST/DEBUG)
1099 #endif
1100 lis r5,hi16(EXT(FloatInit)) /* Get top secret floating point init value address */
1101 ori r5,r5,lo16(EXT(FloatInit)) /* Slam bottom */
1102 lfd f0,0(r5) /* Initialize FP0 */
1103 fmr f1,f0 ; Do them all
1104 fmr f2,f0
1105 fmr f3,f0
1106 fmr f4,f0
1107 fmr f5,f0
1108 fmr f6,f0
1109 fmr f7,f0
1110 fmr f8,f0
1111 fmr f9,f0
1112 fmr f10,f0
1113 fmr f11,f0
1114 fmr f12,f0
1115 fmr f13,f0
1116 fmr f14,f0
1117 fmr f15,f0
1118 fmr f16,f0
1119 fmr f17,f0
1120 fsub f31,f31,f31 ; Get set to initialize the FPSCR
1121 fmr f18,f0
1122 fmr f19,f0
1123 fmr f20,f0
1124 mtfsf 0xff,f31 ; Clear all FPSCR exception eanbles
1125 fmr f21,f0
1126 fmr f22,f0
1127 fmr f23,f0
1128 fmr f24,f0
1129 fmr f25,f0
1130 fmr f26,f0
1131 fmr f27,f0
1132 fmr f28,f0
1133 fmr f29,f0
1134 fmr f30,f0
1135 fmr f31,f0
1136 b fsenablexx ; Finish setting it all up...
1137
1138 ;
1139 ; Finds an unused floating point area in the activation pointed
1140 ; to by R12s saved contexts. If none are found (unlikely but possible)
1141 ; and R3 is 0, a new area is allocated. If R3 is non-zero, it contains
1142 ; a pointer to an floating point savearea that is free.
1143 ;
1144 fpsrchsave:
1145 lwz r6,ACT_MACT_PCB(r12) ; Get the first "normal" savearea
1146
1147 fpsrnorm: mr. r5,r6 ; Is there another?
1148 beq- fpsrvect ; No, search the vector saveareas...
1149 lwz r7,SAVflags(r5) ; Get the flags for this guy
1150 lwz r6,SAVprev(r5) ; Get the previous savearea, just in case
1151 andis. r8,r7,hi16(SAVfpuvalid) ; Have we found an empty FPU save in normal?
1152 beq+ fpsrgot ; We found one...
1153 b fpsrnorm ; Search again...
1154
1155 fpsrvect: lwz r6,ACT_MACT_VMX(r12) ; Get the first "vector" savearea
1156
1157 fpsrvectx: mr. r5,r6 ; Is there another?
1158 beq- fpsrget ; No, try to allocate one...
1159 lwz r7,SAVflags(r5) ; Get the flags for this guy
1160 lwz r6,SAVprevec(r5) ; Get the previous savearea, just in case
1161 andis. r8,r7,hi16(SAVfpuvalid) ; Have we found an empty FPU save in vector?
1162 bne- fpsrvectx ; Search again...
1163
1164 fpsrgot: mr r3,r5 ; Get the savearea into the right register
1165 blr ; Return...
1166
1167 fpsrget: mr. r5,r3 ; Do we allocate or use existing?
1168 beq+ fpsrallo ; Allocate one...
1169
1170 lwz r7,SAVflags(r3) ; Get the passed in area flags
1171 blr ; Return...
1172 ;
1173 ; NOTE: save_get will return directly and set R7 to 0...
1174 ;
1175 fpsrallo: b EXT(save_get) ; Get a fresh savearea
1176
1177 /*
1178 * Altivec stuff is here. The techniques used are pretty identical to
1179 * the floating point. Except that we will honor the VRSAVE register
1180 * settings when loading and restoring registers.
1181 *
1182 * There are two indications of saved VRs: the VRSAVE register and the vrvalid
1183 * mask. VRSAVE is set by the vector user and represents the VRs that they
1184 * say that they are using. The vrvalid mask indicates which vector registers
1185 * are saved in the savearea. Whenever context is saved, it is saved according
1186 * to the VRSAVE register. It is loaded based on VRSAVE anded with
1187 * vrvalid (all other registers are splatted with 0s). This is done because we
1188 * don't want to load any registers we don't have a copy of, we want to set them
1189 * to zero instead.
1190 *
1191 */
1192
1193 ENTRY(vec_save, TAG_NO_FRAME_USED)
1194
1195 mfmsr r0 ; Get the MSR
1196 rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off vector forever
1197 rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; But do interrupts only for now
1198 oris r2,r2,hi16(MASK(MSR_VEC)) ; Enable the vector facility for now also
1199 mtmsr r2 ; Set the MSR
1200 isync
1201
1202 mfsprg r6,0 ; Get the per_processor block
1203 lwz r12,PP_VMX_THREAD(r6) ; Get the thread that owns the vector
1204 #if FPVECDBG
1205 mr r7,r0 ; (TEST/DEBUG)
1206 li r4,0 ; (TEST/DEBUG)
1207 mr r10,r3 ; (TEST/DEBUG)
1208 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1209 mr. r3,r12 ; (TEST/DEBUG)
1210 li r2,0x5F00 ; (TEST/DEBUG)
1211 li r5,0 ; (TEST/DEBUG)
1212 beq- noowneryeu ; (TEST/DEBUG)
1213 lwz r4,ACT_MACT_VMXlvl(r12) ; (TEST/DEBUG)
1214 lwz r5,ACT_MACT_VMX(r12) ; (TEST/DEBUG)
1215
1216 noowneryeu: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1217 sc ; (TEST/DEBUG)
1218 mr r0,r7 ; (TEST/DEBUG)
1219 mr r3,r10 ; (TEST/DEBUG)
1220 #endif
1221 mflr r2 ; Save the return address
1222 lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number
1223
1224 mr. r12,r12 ; Anyone own the vector?
1225 cmplw cr1,r3,r12 ; Is the specified thread the owner?
1226
1227 beq- vsretnr ; Nobody owns the vector, no save required...
1228
1229 li r4,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word
1230 bne- cr1,vsretnr ; Facility belongs to some other activation...
1231
1232 vsvSpin2: lwarx r9,r4,r12 ; Get and reserve the last used CPU
1233 mr. r9,r9 ; Is it changing now?
1234 oris r3,r9,hi16(fvChk) ; Set the "changing" flag
1235 blt- vsvSpin2 ; Spin if changing
1236 stwcx. r3,r4,r12 ; Lock it up
1237 bne- vsvSpin2 ; Someone is messing right now
1238
1239 isync ; Make sure we see everything
1240
1241 cmplw cr1,r9,r11 ; Was the context for this processor?
1242 li r3,0 ; Assume we need a fix-me-up
1243 beq- cr1,vsgoodcpu ; Facility last used on this processor...
1244 stw r3,PP_VMX_THREAD(r6) ; Clear owner because it was really on the other processor
1245 b vsret ; Bail now with no save...
1246
1247 vsgoodcpu: lwz r3,ACT_MACT_VMX(r12) ; Get the current vector savearea for the thread
1248 lwz r9,ACT_MACT_VMXlvl(r12) ; Get our current level indicator
1249
1250 cmplwi cr1,r3,0 ; Have we ever saved this facility context?
1251 beq- cr1,vsneedone ; Never saved it, so we need an area...
1252
1253 lwz r8,SAVlvlvec(r3) ; Get the level this savearea is for
1254 cmplwi r8,1 ; See if this is a spare
1255 cmplw cr1,r9,r8 ; Correct level?
1256 beq+ vsusespare ; It is still live...
1257 beq- cr1,vsret ; The current level is already saved, bail out...
1258
1259 vsneedone: li r3,0 ; Tell the routine to allocate an area if none found
1260 bl vsrchsave ; Find a free savearea
1261
1262 mfsprg r6,0 ; Get back per_processor block
1263 oris r7,r7,hi16(SAVvmxvalid) ; Set the allocated bit
1264 lwz r12,PP_VMX_THREAD(r6) ; Get back our thread
1265 mtlr r2 ; Restore return
1266 lwz r8,ACT_MACT_VMX(r12) ; Get the current top vector savearea
1267 lwz r9,ACT_MACT_VMXlvl(r12) ; Get our current level indicator again
1268 stw r3,ACT_MACT_VMX(r12) ; Set this as the latest vector savearea for the thread
1269 stw r8,SAVprevec(r3) ; And then chain this in front
1270 stw r7,SAVflags(r3) ; Set the allocation flags
1271 stw r12,SAVact(r3) ; Make sure we point to the right guy
1272
1273 vsusespare: stw r9,SAVlvlvec(r3) ; And set the level this savearea is for
1274 mfcr r2 ; Save non-volatile CRs
1275 lwz r10,liveVRS(r6) ; Get the right VRSave register
1276 lis r9,0x5555 ; Mask with odd bits set
1277 rlwinm r11,r10,1,0,31 ; Shift over 1
1278 ori r9,r9,0x5555 ; Finish mask
1279 or r4,r10,r11 ; After this, even bits show which lines to zap
1280
1281 andc r11,r4,r9 ; Clear out odd bits
1282
1283 la r6,savevr0(r3) ; Point to line 0
1284 rlwinm r4,r11,15,0,15 ; Move line 8-15 flags to high order odd bits
1285 la r9,savevrvalid(r3) ; Point to the saved register mask field
1286 or r4,r11,r4 ; Set the odd bits
1287 ; (bit 0 is line 0, bit 1 is line 8,
1288 ; bit 2 is line 1, bit 3 is line 9, etc.
1289 dcba br0,r9 ; Allocate the cache for it
1290 rlwimi r4,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31
1291 la r7,savevr2(r3) ; Point to line 1
1292 mtcrf 255,r4 ; Load up the CRs
1293 stw r10,savevrvalid(r3) ; Save the validity information
1294 mr r8,r6 ; Start registers off
1295 ;
1296 ; Save the current vector state
1297 ;
1298
1299 bf 0,snol0 ; No line 0 to do...
1300 dcba br0,r6 ; Allocate cache line 0
1301
1302 snol0:
1303 la r6,savevr4(r3) ; Point to line 2
1304 bf 2,snol1 ; No line 1 to do...
1305 dcba br0,r7 ; Allocate cache line 1
1306
1307 snol1:
1308 la r7,savevr6(r3) ; Point to line 3
1309 bf 4,snol2 ; No line 2 to do...
1310 dcba br0,r6 ; Allocate cache line 2
1311
1312 snol2:
1313 li r11,16 ; Get offset for odd registers
1314 bf 16,snovr0 ; Do not save VR0...
1315 stvxl v0,br0,r8 ; Save VR0
1316
1317 snovr0:
1318 la r9,savevr2(r3) ; Point to V2/V3 pair
1319 bf 17,snovr1 ; Do not save VR1...
1320 stvxl v1,r11,r8 ; Save VR1
1321
1322 snovr1:
1323 la r6,savevr8(r3) ; Point to line 4
1324 bf 6,snol3 ; No line 3 to do...
1325 dcba br0,r7 ; Allocate cache line 3
1326
1327 snol3:
1328 la r8,savevr4(r3) ; Point to V4/V5 pair
1329 bf 18,snovr2 ; Do not save VR2...
1330 stvxl v2,br0,r9 ; Save VR2
1331
1332 snovr2:
1333 bf 19,snovr3 ; Do not save VR3...
1334 stvxl v3,r11,r9 ; Save VR3
1335
1336 snovr3:
1337 ;
1338 ; Note: CR4 is now free
1339 ;
1340 la r7,savevr10(r3) ; Point to line 5
1341 bf 8,snol4 ; No line 4 to do...
1342 dcba br0,r6 ; Allocate cache line 4
1343
1344 snol4:
1345 la r9,savevr6(r3) ; Point to R6/R7 pair
1346 bf 20,snovr4 ; Do not save VR4...
1347 stvxl v4,br0,r8 ; Save VR4
1348
1349 snovr4:
1350 bf 21,snovr5 ; Do not save VR5...
1351 stvxl v5,r11,r8 ; Save VR5
1352
1353 snovr5:
1354 mtcrf 0x08,r10 ; Set CRs for registers 16-19
1355 la r6,savevr12(r3) ; Point to line 6
1356 bf 10,snol5 ; No line 5 to do...
1357 dcba br0,r7 ; Allocate cache line 5
1358
1359 snol5:
1360 la r8,savevr8(r3) ; Point to V8/V9 pair
1361 bf 22,snovr6 ; Do not save VR6...
1362 stvxl v6,br0,r9 ; Save VR6
1363
1364 snovr6:
1365 bf 23,snovr7 ; Do not save VR7...
1366 stvxl v7,r11,r9 ; Save VR7
1367
1368 snovr7:
1369 ;
1370 ; Note: CR5 is now free
1371 ;
1372 la r7,savevr14(r3) ; Point to line 7
1373 bf 12,snol6 ; No line 6 to do...
1374 dcba br0,r6 ; Allocate cache line 6
1375
1376 snol6:
1377 la r9,savevr10(r3) ; Point to V10/V11 pair
1378 bf 24,snovr8 ; Do not save VR8...
1379 stvxl v8,br0,r8 ; Save VR8
1380
1381 snovr8:
1382 bf 25,snovr9 ; Do not save VR9...
1383 stvxl v9,r11,r8 ; Save VR9
1384
1385 snovr9:
1386 mtcrf 0x04,r10 ; Set CRs for registers 20-23
1387 la r6,savevr16(r3) ; Point to line 8
1388 bf 14,snol7 ; No line 7 to do...
1389 dcba br0,r7 ; Allocate cache line 7
1390
1391 snol7:
1392 la r8,savevr12(r3) ; Point to V12/V13 pair
1393 bf 26,snovr10 ; Do not save VR10...
1394 stvxl v10,br0,r9 ; Save VR10
1395
1396 snovr10:
1397 bf 27,snovr11 ; Do not save VR11...
1398 stvxl v11,r11,r9 ; Save VR11
1399
1400 snovr11:
1401
1402 ;
1403 ; Note: CR6 is now free
1404 ;
1405 la r7,savevr18(r3) ; Point to line 9
1406 bf 1,snol8 ; No line 8 to do...
1407 dcba br0,r6 ; Allocate cache line 8
1408
1409 snol8:
1410 la r9,savevr14(r3) ; Point to V14/V15 pair
1411 bf 28,snovr12 ; Do not save VR12...
1412 stvxl v12,br0,r8 ; Save VR12
1413
1414 snovr12:
1415 bf 29,snovr13 ; Do not save VR13...
1416 stvxl v13,r11,r8 ; Save VR13
1417
1418 snovr13:
1419 mtcrf 0x02,r10 ; Set CRs for registers 24-27
1420 la r6,savevr20(r3) ; Point to line 10
1421 bf 3,snol9 ; No line 9 to do...
1422 dcba br0,r7 ; Allocate cache line 9
1423
1424 snol9:
1425 la r8,savevr16(r3) ; Point to V16/V17 pair
1426 bf 30,snovr14 ; Do not save VR14...
1427 stvxl v14,br0,r9 ; Save VR14
1428
1429 snovr14:
1430 bf 31,snovr15 ; Do not save VR15...
1431 stvxl v15,r11,r9 ; Save VR15
1432
1433 snovr15:
1434 ;
1435 ; Note: CR7 is now free
1436 ;
1437 la r7,savevr22(r3) ; Point to line 11
1438 bf 5,snol10 ; No line 10 to do...
1439 dcba br0,r6 ; Allocate cache line 10
1440
1441 snol10:
1442 la r9,savevr18(r3) ; Point to V18/V19 pair
1443 bf 16,snovr16 ; Do not save VR16...
1444 stvxl v16,br0,r8 ; Save VR16
1445
1446 snovr16:
1447 bf 17,snovr17 ; Do not save VR17...
1448 stvxl v17,r11,r8 ; Save VR17
1449
1450 snovr17:
1451 mtcrf 0x01,r10 ; Set CRs for registers 28-31
1452 ;
1453 ; Note: All registers have been or are accounted for in CRs
1454 ;
1455 la r6,savevr24(r3) ; Point to line 12
1456 bf 7,snol11 ; No line 11 to do...
1457 dcba br0,r7 ; Allocate cache line 11
1458
1459 snol11:
1460 la r8,savevr20(r3) ; Point to V20/V21 pair
1461 bf 18,snovr18 ; Do not save VR18...
1462 stvxl v18,br0,r9 ; Save VR18
1463
1464 snovr18:
1465 bf 19,snovr19 ; Do not save VR19...
1466 stvxl v19,r11,r9 ; Save VR19
1467
1468 snovr19:
1469 la r7,savevr26(r3) ; Point to line 13
1470 bf 9,snol12 ; No line 12 to do...
1471 dcba br0,r6 ; Allocate cache line 12
1472
1473 snol12:
1474 la r9,savevr22(r3) ; Point to V22/V23 pair
1475 bf 20,snovr20 ; Do not save VR20...
1476 stvxl v20,br0,r8 ; Save VR20
1477
1478 snovr20:
1479 bf 21,snovr21 ; Do not save VR21...
1480 stvxl v21,r11,r8 ; Save VR21
1481
1482 snovr21:
1483 la r6,savevr28(r3) ; Point to line 14
1484 bf 11,snol13 ; No line 13 to do...
1485 dcba br0,r7 ; Allocate cache line 13
1486
1487 snol13:
1488 la r8,savevr24(r3) ; Point to V24/V25 pair
1489 bf 22,snovr22 ; Do not save VR22...
1490 stvxl v22,br0,r9 ; Save VR22
1491
1492 snovr22:
1493 bf 23,snovr23 ; Do not save VR23...
1494 stvxl v23,r11,r9 ; Save VR23
1495
1496 snovr23:
1497 la r7,savevr30(r3) ; Point to line 15
1498 bf 13,snol14 ; No line 14 to do...
1499 dcba br0,r6 ; Allocate cache line 14
1500
1501 snol14:
1502 la r9,savevr26(r3) ; Point to V26/V27 pair
1503 bf 24,snovr24 ; Do not save VR24...
1504 stvxl v24,br0,r8 ; Save VR24
1505
1506 snovr24:
1507 bf 25,snovr25 ; Do not save VR25...
1508 stvxl v25,r11,r8 ; Save VR25
1509
1510 snovr25:
1511 bf 15,snol15 ; No line 15 to do...
1512 dcba br0,r7 ; Allocate cache line 15
1513
1514 snol15:
1515 ;
1516 ; Note: All cache lines allocated now
1517 ;
1518 la r8,savevr28(r3) ; Point to V28/V29 pair
1519 bf 26,snovr26 ; Do not save VR26...
1520 stvxl v26,br0,r9 ; Save VR26
1521
1522 snovr26:
1523 bf 27,snovr27 ; Do not save VR27...
1524 stvxl v27,r11,r9 ; Save VR27
1525
1526 snovr27:
1527 la r7,savevr30(r3) ; Point to V30/V31 pair
1528 bf 28,snovr28 ; Do not save VR28...
1529 stvxl v28,br0,r8 ; Save VR28
1530
1531 snovr28:
1532 bf 29,snovr29 ; Do not save VR29...
1533 stvxl v29,r11,r8 ; Save VR29
1534
1535 snovr29:
1536 mfvscr v27 ; Get the VSCR
1537 la r8,savevscr(r3) ; Point to the VSCR save area
1538 bf 30,snovr30 ; Do not save VR30...
1539 stvxl v30,br0,r7 ; Save VR30
1540
1541 snovr30:
1542 dcba br0,r8 ; Allocate VSCR savearea
1543 bf 31,snovr31 ; Do not save VR31...
1544 stvxl v31,r11,r7 ; Save VR31
1545
1546 snovr31:
1547 add r11,r11,r9 ; Point to V27s saved value
1548 stvxl v27,br0,r8 ; Save the VSCR
1549 bt 27,v27ok ; V27 has been saved and is marked as wanted
1550
1551 lis r11,hi16(EXT(QNaNbarbarian)) ; V27 is not wanted, so get empty value
1552 ori r11,r11,lo16(EXT(QNaNbarbarian))
1553
1554 v27ok: mtcrf 255,r2 ; Restore all non-volatile CRs
1555 lvxl v27,br0,r11 ; Restore or load empty value into V27 because we used it
1556
1557 ;
1558 ; Save the current vector state into the savearea of the thread that owns it.
1559 ;
1560
1561 vsret: lwz r4,ACT_MACT_VMXcpu(r12) ; Get back the owner CPU
1562 rlwinm r4,r4,0,fvChkb+1,31 ; Clear lock
1563 sync
1564 stw r4,ACT_MACT_VMXcpu(r12) ; Unlock the context
1565
1566 vsretnr: mtmsr r0 ; Put interrupts on if they were and vector off
1567 isync
1568
1569 blr
1570
1571 /*
1572 * vec_switch()
1573 *
1574 * Entered to handle the vector unavailable exception and
1575 * switch vector context
1576 *
1577 * This code is run with virtual address mode on and interrupts off.
1578 *
1579 * Upon exit, the code returns to the users context with the vector
1580 * facility turned on.
1581 *
1582 * ENTRY: VM switched ON
1583 * Interrupts OFF
1584 * State is saved in savearea pointed to by R4.
1585 * All other registers are free.
1586 *
1587 */
1588
1589 ENTRY(vec_switch, TAG_NO_FRAME_USED)
1590
1591 #if DEBUG
1592 #if GDDBG
1593 mr r7,r4 ; Save input parameter
1594 lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter
1595 ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter
1596 lwz r1,0(r3)
1597 lis r5,hi16(EXT(GratefulDeb)) ; Point to top of display
1598 ori r5,r5,lo16(EXT(GratefulDeb)) ; Put in bottom part
1599 addi r1,r1,1
1600 mtlr r5 ; Set link register
1601 stw r1,0(r3)
1602 mr r4,r1
1603 lis r3,1
1604 blrl ; Display count
1605 mr r4,r7 ; Restore the parameter
1606 #else
1607 lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter
1608 ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter
1609 lwz r1,0(r3)
1610 addi r1,r1,1
1611 stw r1,0(r3)
1612 #endif
1613 #endif /* DEBUG */
1614
1615 mfsprg r6,0 /* Get the per_processor block */
1616 mfmsr r19 /* Get the current MSR */
1617
1618 lwz r10,PP_CPU_DATA(r6) /* Get the CPU data pointer */
1619 lwz r12,PP_VMX_THREAD(r6) /* Get the thread that owns the vector */
1620 lwz r10,CPU_ACTIVE_THREAD(r10) /* Get the pointer to the active thread */
1621 oris r19,r19,hi16(MASK(MSR_VEC)) /* Enable the vector feature */
1622 lwz r17,THREAD_TOP_ACT(r10) /* Now get the activation that is running */
1623
1624 ; R12 has the "old" activation
1625 ; R17 has the "new" activation
1626
1627 #if FPVECDBG
1628 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1629 li r2,0x5F01 ; (TEST/DEBUG)
1630 mr r3,r12 ; (TEST/DEBUG)
1631 mr r5,r17 ; (TEST/DEBUG)
1632 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1633 sc ; (TEST/DEBUG)
1634 #if GDDBG
1635 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
1636 mr r18,r4 ; Save this
1637 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
1638 mr r4,r2 ; Set value
1639 mtlr r3 ; Set link register
1640 li r3,1 ; Display address
1641 blrl ; Display it
1642 mr r4,r18 ; Restore it
1643 mfsprg r6,0 ; Get the per_processor block back
1644 #endif
1645 #endif
1646 mr. r12,r12 ; See if there is any live vector status
1647
1648 lhz r18,PP_CPU_NUMBER(r6) ; Get our CPU number
1649
1650 mtmsr r19 /* Set vector available */
1651 isync
1652
1653 beq- vsnosave ; No live context, so nothing to save...
1654
1655 li r20,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word
1656
1657 vsSpin1: lwarx r19,r20,r12 ; Get and reserve the last used CPU
1658 mr. r19,r19 ; Is it changing now?
1659 oris r21,r19,hi16(fvChk) ; Set the "changing" flag
1660 blt- vsSpin1 ; Spin if changing
1661 stwcx. r21,r20,r12 ; Lock it up
1662 bne- vsSpin1 ; Someone is messing right now
1663
1664 isync ; Make sure we see everything
1665
1666 lwz r15,ACT_MACT_PCB(r12) ; Get the current level of the "old" one
1667 cmplw r18,r19 ; Check the CPU that the old context is live on
1668 lwz r14,ACT_MACT_VMX(r12) ; Point to the top of the old context stack
1669 bne- vsnosaverel ; Context is not live if used on a different CPU...
1670 lwz r13,ACT_MACT_VMXlvl(r12) ; Get the "old" active level
1671
1672 ;
1673 ; First, check to see if all we are doing is enabling because the
1674 ; "new" context is live.
1675 ;
1676 #if FPVECDBG
1677 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1678 li r2,0x5F02 ; (TEST/DEBUG)
1679 mr r1,r15 ; (TEST/DEBUG)
1680 mr r3,r13 ; (TEST/DEBUG)
1681 mr r5,r14 ; (TEST/DEBUG)
1682 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1683 sc ; (TEST/DEBUG)
1684 #if GDDBG
1685 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
1686 mr r8,r4 ; Save this
1687 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
1688 mr r4,r2 ; Set value
1689 mtlr r3 ; Set link register
1690 li r3,1 ; Display address
1691 blrl ; Display it
1692 mr r4,r8 ; Restore it
1693 #endif
1694 #endif
1695
1696 cmplw cr1,r12,r17 ; Is the "old" activation and the "new" the same?
1697 cmplwi cr2,r14,0 ; Is there any saved context on the "old" activation?
1698 bne+ cr1,vsmstsave ; The activations are different so "old" context must be saved...
1699
1700 ;
1701 ; Here we know that both the "old" and "new" activations are the same. We will
1702 ; check the current level and active levels. If they are the same, the context is
1703 ; already live, so all we do is turn on the facility and invalidate the top
1704 ; savearea.
1705 ;
1706 ; If the current level, the active level, and the top savearea level are the
1707 ; same, then the context was saved as part of a thread context switch and neither
1708 ; needs saving or restoration.
1709 ;
1710 ; In all other cases, the context must be saved unless we are just re-enabling
1711 ; vector.
1712 ;
1713
1714 cmplw r13,r15 ; Are the levels the same?
1715 cmplwi cr2,r14,0 ; Is there any saved context?
1716 bne- vsmstsave ; Levels are different, we need to save...
1717
1718 beq- cr2,vrenableret ; No saved context at all, enable and go...
1719
1720 lwz r20,SAVlvlvec(r14) ; Get the level of the top savearea
1721
1722 #if FPVECDBG
1723 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1724 li r2,0x5F03 ; (TEST/DEBUG)
1725 mr r3,r15 ; (TEST/DEBUG)
1726 mr r5,r20 ; (TEST/DEBUG)
1727 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1728 sc ; (TEST/DEBUG)
1729 #if GDDBG
1730 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
1731 mr r8,r4 ; Save this
1732 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
1733 mr r4,r2 ; Set value
1734 mtlr r3 ; Set link register
1735 li r3,1 ; Display address
1736 blrl ; Display it
1737 mr r4,r8 ; Restore it
1738 #endif
1739 #endif
1740 cmplw r15,r20 ; Is the top level the same as the current?
1741 li r0,1 ; Get the invalid flag
1742 bne- vrenableret ; Not the same, just enable and go...
1743
1744 stw r0,SAVlvlvec(r14) ; Invalidate that top savearea
1745
1746 vrenableret:
1747 sync ; Make sure everything is saved
1748 stw r19,ACT_MACT_VMXcpu(r12) ; Say we are not using the context anymore
1749 b vrenable ; Then enable and go...
1750
1751 ;
1752 ; We need to save the "old" context here. The LIFO queueing scheme works
1753 ; out for all cases because if both the "new" and "old" activations are the
1754 ; same, there can not be any saved state to load. the "new" level is
1755 ; truely new.
1756 ;
1757 ; When we save the context, we either use a new savearea, or the free
1758 ; one that is cached at the head of the list.
1759
1760 vsmstsave: beq- cr2,vsgetsave ; There is no possible cached save area
1761
1762 lwz r5,SAVlvlvec(r14) ; Get the level of first facility savearea
1763 #if FPVECDBG
1764 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1765 li r2,0x5F04 ; (TEST/DEBUG)
1766 mr r3,r15 ; (TEST/DEBUG)
1767 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1768 sc ; (TEST/DEBUG)
1769 #if GDDBG
1770 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
1771 mr r8,r4 ; Save this
1772 mr r7,r5 ; Save this
1773 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
1774 mr r4,r2 ; Set value
1775 mtlr r3 ; Set link register
1776 li r3,1 ; Display address
1777 blrl ; Display it
1778 mr r4,r8 ; Restore it
1779 mr r5,r7 ; Restore it
1780 #endif
1781 #endif
1782 mr r3,r14 ; Assume we are invalid
1783 cmplwi r5,1 ; Is it invalid?
1784 cmplw cr1,r5,r13 ; Is the SA level the active one?
1785 beq+ vsusecache ; Invalid, just use it...
1786 beq- cr1,vsnosaverel ; The SA level is active, it is already saved...
1787
1788 vsgetsave: mr r3,r4 ; Use the interrupt save as the context savearea if none cached
1789 #if FPVECDBG
1790 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1791 li r2,0x5F05 ; (TEST/DEBUG)
1792 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1793 sc ; (TEST/DEBUG)
1794 #if GDDBG
1795 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
1796 mr r8,r4 ; Save this
1797 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
1798 mr r4,r2 ; Set value
1799 mtlr r3 ; Set link register
1800 li r3,1 ; Display address
1801 blrl ; Display it
1802 mr r4,r8 ; Restore it
1803 mr r3,r8 ; This too
1804 #endif
1805 #endif
1806
1807 bl vsrchsave ; Find a free savearea
1808
1809 stw r3,ACT_MACT_VMX(r12) ; Set this as the latest context savearea for the thread
1810 mfsprg r6,0 ; Get back per_processor block
1811 stw r14,SAVprevec(r3) ; And then chain this in front
1812 oris r7,r7,hi16(SAVvmxvalid) ; Set the allocated bit
1813 stw r12,SAVact(r3) ; Make sure we point to the right guy
1814 stw r7,SAVflags(r3) ; Set the allocation flags
1815
1816 vsusecache: la r11,savevr0(r3) ; Point to the 1st line in area
1817 stw r13,SAVlvlvec(r3) ; Set this context level
1818 #if FPVECDBG
1819 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
1820 li r2,0x5F06 ; (TEST/DEBUG)
1821 mr r5,r13 ; (TEST/DEBUG)
1822 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
1823 sc ; (TEST/DEBUG)
1824 #if GDDBG
1825 mr r10,r3
1826 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
1827 mr r8,r4 ; Save this
1828 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
1829 mr r4,r2 ; Set value
1830 mtlr r3 ; Set link register
1831 li r3,1 ; Display address
1832 blrl ; Display it
1833 mr r4,r8 ; Restore it
1834 mr r3,r10
1835 mfsprg r6,0 ; Get back per_processor block
1836 #endif
1837 #endif
1838
1839 vsgotsave:
1840 lwz r10,liveVRS(r6) ; Get the right VRSave register
1841 lis r9,0x5555 ; Mask with odd bits set
1842 rlwinm r11,r10,1,0,31 ; Shift over 1
1843 ori r9,r9,0x5555 ; Finish mask
1844 or r21,r10,r11 ; After this, even bits show which lines to zap
1845
1846 stw r13,SAVlvlvec(r3) ; Set the savearea level
1847 andc r13,r21,r9 ; Clear out odd bits
1848
1849 la r20,savevr0(r3) ; Point to line 0
1850 rlwinm r24,r13,15,0,15 ; Move line 8-15 flags to high order odd bits
1851 la r23,savevrvalid(r3) ; Point to the saved register mask field
1852 or r24,r13,r24 ; Set the odd bits
1853 ; (bit 0 is line 0, bit 1 is line 8,
1854 ; bit 2 is line 1, bit 3 is line 9, etc.
1855 dcba br0,r23 ; Allocate the cache for it
1856 rlwimi r24,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31
1857 la r21,savevr2(r3) ; Point to line 1
1858 mtcrf 255,r24 ; Load up the CRs
1859 stw r10,savevrvalid(r3) ; Save the validity information
1860 mr r22,r20 ; Start registers off
1861 ;
1862 ; Save the current vector state
1863 ;
1864
1865 bf 0,nol0 ; No line 0 to do...
1866 dcba br0,r20 ; Allocate cache line 0
1867
1868 nol0:
1869 la r20,savevr4(r3) ; Point to line 2
1870 bf 2,nol1 ; No line 1 to do...
1871 dcba br0,r21 ; Allocate cache line 1
1872
1873 nol1:
1874 la r21,savevr6(r3) ; Point to line 3
1875 bf 4,nol2 ; No line 2 to do...
1876 dcba br0,r20 ; Allocate cache line 2
1877
1878 nol2:
1879 li r30,16 ; Get offset for odd registers
1880 bf 16,novr0 ; Do not save VR0...
1881 stvxl v0,br0,r22 ; Save VR0
1882
1883 novr0:
1884 la r23,savevr2(r3) ; Point to V2/V3 pair
1885 bf 17,novr1 ; Do not save VR1...
1886 stvxl v1,r30,r22 ; Save VR1
1887
1888 novr1:
1889 la r20,savevr8(r3) ; Point to line 4
1890 bf 6,nol3 ; No line 3 to do...
1891 dcba br0,r21 ; Allocate cache line 3
1892
1893 nol3:
1894 la r22,savevr4(r3) ; Point to V4/V5 pair
1895 bf 18,novr2 ; Do not save VR2...
1896 stvxl v2,br0,r23 ; Save VR2
1897
1898 novr2:
1899 bf 19,novr3 ; Do not save VR3...
1900 stvxl v3,r30,r23 ; Save VR3
1901
1902 novr3:
1903 ;
1904 ; Note: CR4 is now free
1905 ;
1906 la r21,savevr10(r3) ; Point to line 5
1907 bf 8,nol4 ; No line 4 to do...
1908 dcba br0,r20 ; Allocate cache line 4
1909
1910 nol4:
1911 la r23,savevr6(r3) ; Point to R6/R7 pair
1912 bf 20,novr4 ; Do not save VR4...
1913 stvxl v4,br0,r22 ; Save VR4
1914
1915 novr4:
1916 bf 21,novr5 ; Do not save VR5...
1917 stvxl v5,r30,r22 ; Save VR5
1918
1919 novr5:
1920 mtcrf 0x08,r10 ; Set CRs for registers 16-19
1921 la r20,savevr12(r3) ; Point to line 6
1922 bf 10,nol5 ; No line 5 to do...
1923 dcba br0,r21 ; Allocate cache line 5
1924
1925 nol5:
1926 la r22,savevr8(r3) ; Point to V8/V9 pair
1927 bf 22,novr6 ; Do not save VR6...
1928 stvxl v6,br0,r23 ; Save VR6
1929
1930 novr6:
1931 bf 23,novr7 ; Do not save VR7...
1932 stvxl v7,r30,r23 ; Save VR7
1933
1934 novr7:
1935 ;
1936 ; Note: CR5 is now free
1937 ;
1938 la r21,savevr14(r3) ; Point to line 7
1939 bf 12,nol6 ; No line 6 to do...
1940 dcba br0,r20 ; Allocate cache line 6
1941
1942 nol6:
1943 la r23,savevr10(r3) ; Point to V10/V11 pair
1944 bf 24,novr8 ; Do not save VR8...
1945 stvxl v8,br0,r22 ; Save VR8
1946
1947 novr8:
1948 bf 25,novr9 ; Do not save VR9...
1949 stvxl v9,r30,r22 ; Save VR9
1950
1951 novr9:
1952 mtcrf 0x04,r10 ; Set CRs for registers 20-23
1953 la r20,savevr16(r3) ; Point to line 8
1954 bf 14,nol7 ; No line 7 to do...
1955 dcba br0,r21 ; Allocate cache line 7
1956
1957 nol7:
1958 la r22,savevr12(r3) ; Point to V12/V13 pair
1959 bf 26,novr10 ; Do not save VR10...
1960 stvxl v10,br0,r23 ; Save VR10
1961
1962 novr10:
1963 bf 27,novr11 ; Do not save VR11...
1964 stvxl v11,r30,r23 ; Save VR11
1965
1966 novr11:
1967
1968 ;
1969 ; Note: CR6 is now free
1970 ;
1971 la r21,savevr18(r3) ; Point to line 9
1972 bf 1,nol8 ; No line 8 to do...
1973 dcba br0,r20 ; Allocate cache line 8
1974
1975 nol8:
1976 la r23,savevr14(r3) ; Point to V14/V15 pair
1977 bf 28,novr12 ; Do not save VR12...
1978 stvxl v12,br0,r22 ; Save VR12
1979
1980 novr12:
1981 bf 29,novr13 ; Do not save VR13...
1982 stvxl v13,r30,r22 ; Save VR13
1983
1984 novr13:
1985 mtcrf 0x02,r10 ; Set CRs for registers 24-27
1986 la r20,savevr20(r3) ; Point to line 10
1987 bf 3,nol9 ; No line 9 to do...
1988 dcba br0,r21 ; Allocate cache line 9
1989
1990 nol9:
1991 la r22,savevr16(r3) ; Point to V16/V17 pair
1992 bf 30,novr14 ; Do not save VR14...
1993 stvxl v14,br0,r23 ; Save VR14
1994
1995 novr14:
1996 bf 31,novr15 ; Do not save VR15...
1997 stvxl v15,r30,r23 ; Save VR15
1998
1999 novr15:
2000 ;
2001 ; Note: CR7 is now free
2002 ;
2003 la r21,savevr22(r3) ; Point to line 11
2004 bf 5,nol10 ; No line 10 to do...
2005 dcba br0,r20 ; Allocate cache line 10
2006
2007 nol10:
2008 la r23,savevr18(r3) ; Point to V18/V19 pair
2009 bf 16,novr16 ; Do not save VR16...
2010 stvxl v16,br0,r22 ; Save VR16
2011
2012 novr16:
2013 bf 17,novr17 ; Do not save VR17...
2014 stvxl v17,r30,r22 ; Save VR17
2015
2016 novr17:
2017 mtcrf 0x01,r10 ; Set CRs for registers 28-31
2018 ;
2019 ; Note: All registers have been or are accounted for in CRs
2020 ;
2021 la r20,savevr24(r3) ; Point to line 12
2022 bf 7,nol11 ; No line 11 to do...
2023 dcba br0,r21 ; Allocate cache line 11
2024
2025 nol11:
2026 la r22,savevr20(r3) ; Point to V20/V21 pair
2027 bf 18,novr18 ; Do not save VR18...
2028 stvxl v18,br0,r23 ; Save VR18
2029
2030 novr18:
2031 bf 19,novr19 ; Do not save VR19...
2032 stvxl v19,r30,r23 ; Save VR19
2033
2034 novr19:
2035 la r21,savevr26(r3) ; Point to line 13
2036 bf 9,nol12 ; No line 12 to do...
2037 dcba br0,r20 ; Allocate cache line 12
2038
2039 nol12:
2040 la r23,savevr22(r3) ; Point to V22/V23 pair
2041 bf 20,novr20 ; Do not save VR20...
2042 stvxl v20,br0,r22 ; Save VR20
2043
2044 novr20:
2045 bf 21,novr21 ; Do not save VR21...
2046 stvxl v21,r30,r22 ; Save VR21
2047
2048 novr21:
2049 la r20,savevr28(r3) ; Point to line 14
2050 bf 11,nol13 ; No line 13 to do...
2051 dcba br0,r21 ; Allocate cache line 13
2052
2053 nol13:
2054 la r22,savevr24(r3) ; Point to V24/V25 pair
2055 bf 22,novr22 ; Do not save VR22...
2056 stvxl v22,br0,r23 ; Save VR22
2057
2058 novr22:
2059 bf 23,novr23 ; Do not save VR23...
2060 stvxl v23,r30,r23 ; Save VR23
2061
2062 novr23:
2063 la r21,savevr30(r3) ; Point to line 15
2064 bf 13,nol14 ; No line 14 to do...
2065 dcba br0,r20 ; Allocate cache line 14
2066
2067 nol14:
2068 la r23,savevr26(r3) ; Point to V26/V27 pair
2069 bf 24,novr24 ; Do not save VR24...
2070 stvxl v24,br0,r22 ; Save VR24
2071
2072 novr24:
2073 bf 25,novr25 ; Do not save VR25...
2074 stvxl v25,r30,r22 ; Save VR25
2075
2076 novr25:
2077 bf 15,nol15 ; No line 15 to do...
2078 dcba br0,r21 ; Allocate cache line 15
2079
2080 nol15:
2081 ;
2082 ; Note: All cache lines allocated now
2083 ;
2084 la r22,savevr28(r3) ; Point to V28/V29 pair
2085 bf 26,novr26 ; Do not save VR26...
2086 stvxl v26,br0,r23 ; Save VR26
2087
2088 novr26:
2089 bf 27,novr27 ; Do not save VR27...
2090 stvxl v27,r30,r23 ; Save VR27
2091
2092 novr27:
2093 la r23,savevr30(r3) ; Point to V30/V31 pair
2094 bf 28,novr28 ; Do not save VR28...
2095 stvxl v28,br0,r22 ; Save VR28
2096
2097 novr28:
2098 mfvscr v27 ; Get the VSCR
2099 bf 29,novr29 ; Do not save VR29...
2100 stvxl v29,r30,r22 ; Save VR29
2101
2102 novr29:
2103 la r22,savevscr(r3) ; Point to the VSCR save area
2104 bf 30,novr30 ; Do not save VR30...
2105 stvxl v30,br0,r23 ; Save VR30
2106
2107 novr30:
2108 dcba br0,r22 ; Allocate VSCR savearea
2109 bf 31,novr31 ; Do not save VR31...
2110 stvxl v31,r30,r23 ; Save VR31
2111
2112 novr31:
2113 stvxl v27,br0,r22 ; Save the VSCR
2114
2115
2116
2117 /*
2118 * Now check out the current thread and see if we need to load up his context.
2119 * If we do (and this should be the normal case), do it and then release the
2120 * savearea.
2121 *
2122 * If we don't (remember, we already took care of the case where we just enable
2123 * the vector), we need to fill the registers with garbage, because this thread has
2124 * never used them before and some thieving bastard could hack the old values
2125 * of some thread! Just imagine what would happen if they could! Why, nothing
2126 * would be safe! My Gosh! It's terrifying!
2127 */
2128
2129 vsnosaverel:
2130 sync ; Make sure everything is saved
2131 stw r19,ACT_MACT_VMXcpu(r12) ; Say we are not using the context anymore
2132
2133
2134 vsnosave:
2135 li r20,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word
2136
2137 vsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU
2138 mr. r19,r19 ; Is it changing now?
2139 oris r21,r19,hi16(fvChk) ; Set the "changing" flag
2140 blt- vsSpin2 ; Spin if changing
2141 stwcx. r21,r20,r17 ; Lock it up
2142 bne- vsSpin2 ; Someone is messing right now
2143
2144 isync ; Make sure we see everything
2145
2146 lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one
2147 lwz r14,ACT_MACT_VMX(r17) ; Point to the top of the "new" context stack
2148 lwz r13,ACT_MACT_VMXlvl(r17) ; Get the "new" active level
2149
2150 #if FPVECDBG
2151 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
2152 li r2,0x5F07 ; (TEST/DEBUG)
2153 mr r1,r15 ; (TEST/DEBUG)
2154 mr r3,r14 ; (TEST/DEBUG)
2155 mr r5,r13 ; (TEST/DEBUG)
2156 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
2157 sc ; (TEST/DEBUG)
2158 #endif
2159
2160 cmplwi cr1,r14,0 ; Do we possibly have some context to load?
2161 stw r15,ACT_MACT_VMXlvl(r17) ; Set the "new" active level
2162 la r23,savevscr(r14) ; Point to the VSCR
2163 la r20,savevr0(r14) ; Point to first line to bring in
2164 stw r17,PP_VMX_THREAD(r6) ; Store current thread address in vmx_thread to claim vector for thread
2165 beq- cr1,ProtectTheAmericanWay ; Nothing to restore, first time use...
2166 lwz r0,SAVlvlvec(r14) ; Get the level of first facility savearea
2167 cmplw r0,r15 ; Top level correct to load?
2168 bne- ProtectTheAmericanWay ; No, go initialize...
2169
2170 #if FPVECDBG
2171 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
2172 li r2,0x5F08 ; (TEST/DEBUG)
2173 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
2174 sc ; (TEST/DEBUG)
2175 #if GDDBG
2176 mr r8,r3
2177 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
2178 mr r22,r4 ; Save this
2179 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
2180 mr r4,r2 ; Set value
2181 mtlr r3 ; Set link register
2182 li r3,1 ; Display address
2183 blrl ; Display it
2184 mr r4,r22 ; Restore it
2185 mr r3,r8
2186 #endif
2187 #endif
2188
2189 li r0,1 ; Get the level invalid indication
2190 lwz r22,savevrsave(r4) ; Get the most current VRSAVE
2191 lwz r10,savevrvalid(r14) ; Get the valid VRs in the savearea
2192 lis r9,0x5555 ; Mask with odd bits set
2193 and r10,r10,r22 ; Figure out just what registers need to be loaded
2194 ori r9,r9,0x5555 ; Finish mask
2195 rlwinm r11,r10,1,0,31 ; Shift over 1
2196 stw r0,SAVlvlvec(r14) ; Mark the savearea invalid because we are activating again
2197 or r12,r10,r11 ; After this, even bits show which lines to touch
2198 dcbt br0,r23 ; Touch in the VSCR
2199 andc r13,r12,r9 ; Clear out odd bits
2200
2201 la r20,savevr0(r14) ; Point to line 0
2202 rlwinm r3,r13,15,0,15 ; Move line 8-15 flags to high order odd bits
2203 la r21,savevr2(r3) ; Point to line 1
2204 or r3,r13,r3 ; Set the odd bits
2205 ; (bit 0 is line 0, bit 1 is line 8,
2206 ; bit 2 is line 1, bit 3 is line 9, etc.
2207 lvxl v31,br0,r23 ; Get the VSCR
2208 rlwimi r3,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31
2209 mtvscr v31 ; Slam the VSCR value
2210 mtcrf 255,r3 ; Load up the CRs
2211 mr r22,r20 ; Start registers off
2212 ;
2213 ; Load the new vector state
2214 ;
2215
2216 bf 0,lnol0 ; No line 0 to do...
2217 dcbt br0,r20 ; Touch cache line 0
2218
2219 lnol0:
2220 la r20,savevr4(r14) ; Point to line 2
2221 bf 2,lnol1 ; No line 1 to do...
2222 dcbt br0,r21 ; Touch cache line 1
2223
2224 lnol1:
2225 la r21,savevr6(r14) ; Point to line 3
2226 bf 4,lnol2 ; No line 2 to do...
2227 dcbt br0,r20 ; Touch cache line 2
2228
2229 lnol2:
2230 li r30,16 ; Get offset for odd registers
2231 bf 16,lnovr0 ; Do not restore VR0...
2232 lvxl v0,br0,r22 ; Restore VR0
2233
2234 lnovr0:
2235 la r23,savevr2(r14) ; Point to V2/V3 pair
2236 bf 17,lnovr1 ; Do not restore VR1...
2237 lvxl v1,r30,r22 ; Restore VR1
2238
2239 lnovr1:
2240 la r20,savevr8(r14) ; Point to line 4
2241 bf 6,lnol3 ; No line 3 to do...
2242 dcbt br0,r21 ; Touch cache line 3
2243
2244 lnol3:
2245 la r22,savevr4(r14) ; Point to V4/V5 pair
2246 bf 18,lnovr2 ; Do not restore VR2...
2247 lvxl v2,br0,r23 ; Restore VR2
2248
2249 lnovr2:
2250 bf 19,lnovr3 ; Do not restore VR3...
2251 lvxl v3,r30,r23 ; Restore VR3
2252
2253 lnovr3:
2254 ;
2255 ; Note: CR4 is now free
2256 ;
2257 la r21,savevr10(r14) ; Point to line 5
2258 bf 8,lnol4 ; No line 4 to do...
2259 dcbt br0,r20 ; Touch cache line 4
2260
2261 lnol4:
2262 la r23,savevr6(r14) ; Point to R6/R7 pair
2263 bf 20,lnovr4 ; Do not restore VR4...
2264 lvxl v4,br0,r22 ; Restore VR4
2265
2266 lnovr4:
2267 bf 21,lnovr5 ; Do not restore VR5...
2268 lvxl v5,r30,r22 ; Restore VR5
2269
2270 lnovr5:
2271 mtcrf 0x08,r10 ; Set CRs for registers 16-19
2272 la r20,savevr12(r14) ; Point to line 6
2273 bf 10,lnol5 ; No line 5 to do...
2274 dcbt br0,r21 ; Touch cache line 5
2275
2276 lnol5:
2277 la r22,savevr8(r14) ; Point to V8/V9 pair
2278 bf 22,lnovr6 ; Do not restore VR6...
2279 lvxl v6,br0,r23 ; Restore VR6
2280
2281 lnovr6:
2282 bf 23,lnovr7 ; Do not restore VR7...
2283 lvxl v7,r30,r23 ; Restore VR7
2284
2285 lnovr7:
2286 ;
2287 ; Note: CR5 is now free
2288 ;
2289 la r21,savevr14(r14) ; Point to line 7
2290 bf 12,lnol6 ; No line 6 to do...
2291 dcbt br0,r20 ; Touch cache line 6
2292
2293 lnol6:
2294 la r23,savevr10(r14) ; Point to V10/V11 pair
2295 bf 24,lnovr8 ; Do not restore VR8...
2296 lvxl v8,br0,r22 ; Restore VR8
2297
2298 lnovr8:
2299 bf 25,lnovr9 ; Do not save VR9...
2300 lvxl v9,r30,r22 ; Restore VR9
2301
2302 lnovr9:
2303 mtcrf 0x04,r10 ; Set CRs for registers 20-23
2304 la r20,savevr16(r14) ; Point to line 8
2305 bf 14,lnol7 ; No line 7 to do...
2306 dcbt br0,r21 ; Touch cache line 7
2307
2308 lnol7:
2309 la r22,savevr12(r14) ; Point to V12/V13 pair
2310 bf 26,lnovr10 ; Do not restore VR10...
2311 lvxl v10,br0,r23 ; Restore VR10
2312
2313 lnovr10:
2314 bf 27,lnovr11 ; Do not restore VR11...
2315 lvxl v11,r30,r23 ; Restore VR11
2316
2317 lnovr11:
2318
2319 ;
2320 ; Note: CR6 is now free
2321 ;
2322 la r21,savevr18(r14) ; Point to line 9
2323 bf 1,lnol8 ; No line 8 to do...
2324 dcbt br0,r20 ; Touch cache line 8
2325
2326 lnol8:
2327 la r23,savevr14(r14) ; Point to V14/V15 pair
2328 bf 28,lnovr12 ; Do not restore VR12...
2329 lvxl v12,br0,r22 ; Restore VR12
2330
2331 lnovr12:
2332 bf 29,lnovr13 ; Do not restore VR13...
2333 lvxl v13,r30,r22 ; Restore VR13
2334
2335 lnovr13:
2336 mtcrf 0x02,r10 ; Set CRs for registers 24-27
2337 la r20,savevr20(r14) ; Point to line 10
2338 bf 3,lnol9 ; No line 9 to do...
2339 dcbt br0,r21 ; Touch cache line 9
2340
2341 lnol9:
2342 la r22,savevr16(r14) ; Point to V16/V17 pair
2343 bf 30,lnovr14 ; Do not restore VR14...
2344 lvxl v14,br0,r23 ; Restore VR14
2345
2346 lnovr14:
2347 bf 31,lnovr15 ; Do not restore VR15...
2348 lvxl v15,r30,r23 ; Restore VR15
2349
2350 lnovr15:
2351 ;
2352 ; Note: CR7 is now free
2353 ;
2354 la r21,savevr22(r14) ; Point to line 11
2355 bf 5,lnol10 ; No line 10 to do...
2356 dcbt br0,r20 ; Touch cache line 10
2357
2358 lnol10:
2359 la r23,savevr18(r14) ; Point to V18/V19 pair
2360 bf 16,lnovr16 ; Do not restore VR16...
2361 lvxl v16,br0,r22 ; Restore VR16
2362
2363 lnovr16:
2364 bf 17,lnovr17 ; Do not restore VR17...
2365 lvxl v17,r30,r22 ; Restore VR17
2366
2367 lnovr17:
2368 mtcrf 0x01,r10 ; Set CRs for registers 28-31
2369 ;
2370 ; Note: All registers have been or are accounted for in CRs
2371 ;
2372 la r20,savevr24(r14) ; Point to line 12
2373 bf 7,lnol11 ; No line 11 to do...
2374 dcbt br0,r21 ; Touch cache line 11
2375
2376 lnol11:
2377 la r22,savevr20(r14) ; Point to V20/V21 pair
2378 bf 18,lnovr18 ; Do not restore VR18...
2379 lvxl v18,br0,r23 ; Restore VR18
2380
2381 lnovr18:
2382 bf 19,lnovr19 ; Do not restore VR19...
2383 lvxl v19,r30,r23 ; Restore VR19
2384
2385 lnovr19:
2386 la r21,savevr26(r14) ; Point to line 13
2387 bf 9,lnol12 ; No line 12 to do...
2388 dcbt br0,r20 ; Touch cache line 12
2389
2390 lnol12:
2391 la r23,savevr22(r14) ; Point to V22/V23 pair
2392 bf 20,lnovr20 ; Do not restore VR20...
2393 lvxl v20,br0,r22 ; Restore VR20
2394
2395 lnovr20:
2396 bf 21,lnovr21 ; Do not restore VR21...
2397 lvxl v21,r30,r22 ; Restore VR21
2398
2399 lnovr21:
2400 la r20,savevr28(r14) ; Point to line 14
2401 bf 11,lnol13 ; No line 13 to do...
2402 dcbt br0,r21 ; Touch cache line 13
2403
2404 lnol13:
2405 la r22,savevr24(r14) ; Point to V24/V25 pair
2406 bf 22,lnovr22 ; Do not restore VR22...
2407 lvxl v22,br0,r23 ; Restore VR22
2408
2409 lnovr22:
2410 bf 23,lnovr23 ; Do not restore VR23...
2411 lvxl v23,r30,r23 ; Restore VR23
2412
2413 lnovr23:
2414 la r21,savevr30(r14) ; Point to line 15
2415 bf 13,lnol14 ; No line 14 to do...
2416 dcbt br0,r20 ; Touch cache line 14
2417
2418 lnol14:
2419 la r23,savevr26(r14) ; Point to V26/V27 pair
2420 bf 24,lnovr24 ; Do not restore VR24...
2421 lvxl v24,br0,r22 ; Restore VR24
2422
2423 lnovr24:
2424 bf 25,lnovr25 ; Do not restore VR25...
2425 lvxl v25,r30,r22 ; Restore VR25
2426
2427 lnovr25:
2428 bf 15,lnol15 ; No line 15 to do...
2429 dcbt br0,r21 ; Touch cache line 15
2430
2431 lnol15:
2432 ;
2433 ; Note: All needed cache lines have been touched now
2434 ;
2435 la r22,savevr28(r14) ; Point to V28/V29 pair
2436 bf 26,lnovr26 ; Do not restore VR26...
2437 lvxl v26,br0,r23 ; Restore VR26
2438
2439 lnovr26:
2440 bf 27,lnovr27 ; Do not restore VR27...
2441 lvxl v27,r30,r23 ; Restore VR27
2442
2443 lnovr27:
2444 la r23,savevr30(r14) ; Point to V30/V31 pair
2445 bf 28,lnovr28 ; Do not restore VR28...
2446 lvxl v28,br0,r22 ; Restore VR28
2447
2448 lnovr28:
2449 bf 29,lnovr29 ; Do not restore VR29...
2450 lvxl v29,r30,r22 ; Restore VR29
2451
2452 lnovr29:
2453 bf 30,lnovr30 ; Do not restore VR30...
2454 lvxl v30,br0,r23 ; Restore VR30
2455
2456 lnovr30:
2457 ;
2458 ; Everything is restored now except for VR31. We need it to get
2459 ; the QNaNBarbarian value to put into idle vector registers
2460 ;
2461
2462 lis r5,hi16(EXT(QNaNbarbarian)) ; Get address of empty value
2463 cmpwi r10,-1 ; Handle the quick case of all registers in use
2464 ori r5,r5,lo16(EXT(QNaNbarbarian)) ; Get low address of empty value
2465 beq- mstlvr31 ; Not likely, but all are in use...
2466 mtcrf 255,r10 ; Get mask of valid registers
2467 lvxl v31,br0,r5 ; Initialize VR31 to the empty value
2468
2469 bt 0,ni0 ; Register is ok already...
2470 vor v0,v31,v31 ; Copy into the next register
2471 ni0:
2472 bt 1,ni1 ; Register is ok already...
2473 vor v1,v31,v31 ; Copy into the next register
2474 ni1:
2475 bt 2,ni2 ; Register is ok already...
2476 vor v2,v31,v31 ; Copy into the next register
2477 ni2:
2478 bt 3,ni3 ; Register is ok already...
2479 vor v3,v31,v31 ; Copy into the next register
2480 ni3:
2481 bt 4,ni4 ; Register is ok already...
2482 vor v4,v31,v31 ; Copy into the next register
2483 ni4:
2484 bt 5,ni5 ; Register is ok already...
2485 vor v5,v31,v31 ; Copy into the next register
2486 ni5:
2487 bt 6,ni6 ; Register is ok already...
2488 vor v6,v31,v31 ; Copy into the next register
2489 ni6:
2490 bt 7,ni7 ; Register is ok already...
2491 vor v7,v31,v31 ; Copy into the next register
2492 ni7:
2493 bt 8,ni8 ; Register is ok already...
2494 vor v8,v31,v31 ; Copy into the next register
2495 ni8:
2496 bt 9,ni9 ; Register is ok already...
2497 vor v9,v31,v31 ; Copy into the next register
2498 ni9:
2499 bt 10,ni10 ; Register is ok already...
2500 vor v10,v31,v31 ; Copy into the next register
2501 ni10:
2502 bt 11,ni11 ; Register is ok already...
2503 vor v11,v31,v31 ; Copy into the next register
2504 ni11:
2505 bt 12,ni12 ; Register is ok already...
2506 vor v12,v31,v31 ; Copy into the next register
2507 ni12:
2508 bt 13,ni13 ; Register is ok already...
2509 vor v13,v31,v31 ; Copy into the next register
2510 ni13:
2511 bt 14,ni14 ; Register is ok already...
2512 vor v14,v31,v31 ; Copy into the next register
2513 ni14:
2514 bt 15,ni15 ; Register is ok already...
2515 vor v15,v31,v31 ; Copy into the next register
2516 ni15:
2517 bt 16,ni16 ; Register is ok already...
2518 vor v16,v31,v31 ; Copy into the next register
2519 ni16:
2520 bt 17,ni17 ; Register is ok already...
2521 vor v17,v31,v31 ; Copy into the next register
2522 ni17:
2523 bt 18,ni18 ; Register is ok already...
2524 vor v18,v31,v31 ; Copy into the next register
2525 ni18:
2526 bt 19,ni19 ; Register is ok already...
2527 vor v19,v31,v31 ; Copy into the next register
2528 ni19:
2529 bt 20,ni20 ; Register is ok already...
2530 vor v20,v31,v31 ; Copy into the next register
2531 ni20:
2532 bt 21,ni21 ; Register is ok already...
2533 vor v21,v31,v31 ; Copy into the next register
2534 ni21:
2535 bt 22,ni22 ; Register is ok already...
2536 vor v22,v31,v31 ; Copy into the next register
2537 ni22:
2538 bt 23,ni23 ; Register is ok already...
2539 vor v23,v31,v31 ; Copy into the next register
2540 ni23:
2541 bt 24,ni24 ; Register is ok already...
2542 vor v24,v31,v31 ; Copy into the next register
2543 ni24:
2544 bt 25,ni25 ; Register is ok already...
2545 vor v25,v31,v31 ; Copy into the next register
2546 ni25:
2547 bt 26,ni26 ; Register is ok already...
2548 vor v26,v31,v31 ; Copy into the next register
2549 ni26:
2550 bt 27,ni27 ; Register is ok already...
2551 vor v27,v31,v31 ; Copy into the next register
2552 ni27:
2553 bt 28,ni28 ; Register is ok already...
2554 vor v28,v31,v31 ; Copy into the next register
2555 ni28:
2556 bt 29,ni29 ; Register is ok already...
2557 vor v29,v31,v31 ; Copy into the next register
2558 ni29:
2559 bt 30,ni30 ; Register is ok already...
2560 vor v30,v31,v31 ; Copy into the next register
2561 ni30:
2562 bf 31,lnovr31 ; R31 is empty, no need to restore...
2563
2564 mstlvr31: lvxl v31,r30,r23 ; Restore VR31
2565
2566 lnovr31:
2567
2568 vrenablexx: sync ; Make sure all is saved
2569 stw r18,ACT_MACT_VMXcpu(r17) ; Set the active CPU and release
2570
2571 vrenable:
2572 lwz r9,SAVflags(r4) /* Get the flags of the current savearea */
2573 lwz r8,savesrr1(r4) ; Get the msr of the interrupted guy
2574 rlwinm r5,r4,0,0,19 /* Get the page address of the savearea */
2575 oris r8,r8,hi16(MASK(MSR_VEC)) ; Enable the vector facility
2576 lwz r10,ACT_MACT_SPF(r17) ; Get the special flags
2577 lis r7,hi16(SAVattach) /* Get the attached flag */
2578 lwz r5,SACvrswap(r5) /* Get Virtual to Real translation */
2579 oris r10,r10,hi16(vectorUsed|vectorCng) ; Set that we used vectors
2580 mr. r15,r15 ; See if we are doing this for user state
2581 stw r8,savesrr1(r4) ; Set the msr of the interrupted guy
2582 andc r9,r9,r7 /* Clear the attached bit */
2583 xor r3,r4,r5 /* Get the real address of the savearea */
2584 stw r9,SAVflags(r4) /* Set the flags of the current savearea */
2585 bne- vrnuser ; We are not user state...
2586 stw r10,ACT_MACT_SPF(r17) ; Set the activation copy
2587 stw r10,spcFlags(r6) ; Set per_proc copy
2588
2589 vrnuser:
2590 #if FPVECDBG
2591 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
2592 li r2,0x5F0A ; (TEST/DEBUG)
2593 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
2594 sc ; (TEST/DEBUG)
2595 #if GDDBG
2596 mr r8,r3 ; Save this
2597 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
2598 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
2599 mr r4,r2 ; Set value
2600 mtlr r3 ; Set link register
2601 li r3,1 ; Display address
2602 blrl ; Display it
2603 mr r3,r8 ; Restore it
2604 #endif
2605 #endif
2606 b EXT(exception_exit) /* Exit from the fray... */
2607
2608 /*
2609 * Initialize the registers to some bogus value
2610 * We make sure that non-Java mode is the default here
2611 */
2612
2613 ProtectTheAmericanWay:
2614
2615 #if 0
2616 lwz r10,savesrr1(r4) ; (TEST/DEBUG)
2617 rlwinm. r10,r10,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG)
2618 beq- nxxxxxx2 ; (TEST/DEBUG)
2619 lwz r10,ACT_MACT_SPF(r17) ; (TEST/DEBUG)
2620 rlwinm. r10,r10,0,2,2 ; (TEST/DEBUG)
2621 beq+ nxxxxxx2
2622 BREAKPOINT_TRAP ; (TEST/DEBUG)
2623 nxxxxxx2:
2624 #endif
2625 #if FPVECDBG
2626 lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG)
2627 li r2,0x5F09 ; (TEST/DEBUG)
2628 oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG)
2629 sc ; (TEST/DEBUG)
2630 #if GDDBG
2631 lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display
2632 mr r8,r4 ; Save this
2633 ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part
2634 mr r4,r2 ; Set value
2635 mtlr r3 ; Set link register
2636 li r3,1 ; Display address
2637 blrl ; Display it
2638 mr r4,r8 ; Restore it
2639 #endif
2640 #endif
2641 lis r5,hi16(EXT(QNaNbarbarian)) ; Get address of empty value
2642 vspltish v1,1 ; Turn on the non-Java bit and saturate
2643 ori r5,r5,lo16(EXT(QNaNbarbarian)) ; Get low address of empty value
2644 vspltisw v2,1 ; Turn on the saturate bit
2645 lvxl v0,br0,r5 ; Initialize VR0
2646 vxor v1,v1,v2 ; Turn off saturate
2647
2648 vor v2,v0,v0 ; Copy into the next register
2649 mtvscr v1 ; Clear the vector status register
2650 vor v3,v0,v0 ; Copy into the next register
2651 vor v1,v0,v0 ; Copy into the next register
2652 vor v4,v0,v0 ; Copy into the next register
2653 vor v5,v0,v0 ; Copy into the next register
2654 vor v6,v0,v0 ; Copy into the next register
2655 vor v7,v0,v0 ; Copy into the next register
2656 vor v8,v0,v0 ; Copy into the next register
2657 vor v9,v0,v0 ; Copy into the next register
2658 vor v10,v0,v0 ; Copy into the next register
2659 vor v11,v0,v0 ; Copy into the next register
2660 vor v12,v0,v0 ; Copy into the next register
2661 vor v13,v0,v0 ; Copy into the next register
2662 vor v14,v0,v0 ; Copy into the next register
2663 vor v15,v0,v0 ; Copy into the next register
2664 vor v16,v0,v0 ; Copy into the next register
2665 vor v17,v0,v0 ; Copy into the next register
2666 vor v18,v0,v0 ; Copy into the next register
2667 vor v19,v0,v0 ; Copy into the next register
2668 vor v20,v0,v0 ; Copy into the next register
2669 vor v21,v0,v0 ; Copy into the next register
2670 vor v22,v0,v0 ; Copy into the next register
2671 vor v23,v0,v0 ; Copy into the next register
2672 vor v24,v0,v0 ; Copy into the next register
2673 vor v25,v0,v0 ; Copy into the next register
2674 vor v26,v0,v0 ; Copy into the next register
2675 vor v27,v0,v0 ; Copy into the next register
2676 vor v28,v0,v0 ; Copy into the next register
2677 vor v29,v0,v0 ; Copy into the next register
2678 vor v30,v0,v0 ; Copy into the next register
2679 vor v31,v0,v0 ; Copy into the next register
2680 b vrenablexx ; Finish setting it all up...
2681
2682 ;
2683 ; Finds a unused vector area in the activation pointed
2684 ; to by R12s saved contexts. If none are found (unlikely but possible)
2685 ; and R3 is 0, a new area is allocated. If R3 is non-zero, it contains
2686 ; a pointer to a vector savearea that is free.
2687 ;
2688
2689 vsrchsave: lwz r6,ACT_MACT_PCB(r12) ; Get the first "normal" savearea
2690
2691 vsrnorm: mr. r5,r6 ; Is there another?
2692 beq- vsrvect ; No, search the floating point saveareas...
2693 lwz r7,SAVflags(r5) ; Get the flags for this guy
2694 lwz r6,SAVprev(r5) ; Get the previous savearea, just in case
2695 andis. r8,r7,hi16(SAVvmxvalid) ; Have we found an empty vector save in normal?
2696 beq+ vsrgot ; We found one...
2697 b vsrnorm ; Search again...
2698
2699 vsrvect: lwz r6,ACT_MACT_FPU(r12) ; Get the first "floating point" savearea
2700
2701 vsrvectx: mr. r5,r6 ; Is there another?
2702 beq- vsrget ; No, try to allocate one...
2703 lwz r7,SAVflags(r5) ; Get the flags for this guy
2704 lwz r6,SAVprefp(r5) ; Get the previous savearea, just in case
2705 andis. r8,r7,hi16(SAVvmxvalid) ; Have we found an empty vector save in float?
2706 bne- vsrvectx ; Search again...
2707
2708 vsrgot: mr r3,r5 ; Get the savearea into the right register
2709 blr ; Return...
2710
2711 vsrget: mr. r5,r3 ; Do we allocate or use existing?
2712 beq+ vsrallo ; Allocate one...
2713
2714 lwz r7,SAVflags(r3) ; Get the passed in area flags
2715 blr ; Return...
2716 ;
2717 ; NOTE: save_get will return directly and set R7 to 0...
2718 ;
2719 vsrallo: b EXT(save_get) ; Get a fresh savearea
2720
2721
2722 /*
2723 * void lfs(fpsp,fpdp)
2724 *
2725 * load the single precision float to the double
2726 *
2727 * This routine is used by the alignment handler.
2728 *
2729 */
2730 ENTRY(lfs, TAG_NO_FRAME_USED)
2731 lfs f1, 0(r3)
2732 stfd f1, 0(r4)
2733 blr
2734
2735 /*
2736 * fpsp stfs(fpdp,fpsp)
2737 *
2738 * store the double precision float to the single
2739 *
2740 * This routine is used by the alignment handler.
2741 *
2742 */
2743 ENTRY(stfs, TAG_NO_FRAME_USED)
2744 lfd f1, 0(r3)
2745 stfs f1, 0(r4)
2746 blr
2747