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