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