X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d52fe63fc81f7e44faaae711812a211a78434976..9bccf70c0258c7cac2dcb80011b2a964d884c552:/osfmk/ppc/cswtch.s diff --git a/osfmk/ppc/cswtch.s b/osfmk/ppc/cswtch.s index 8a4d0ac65..3cca411b2 100644 --- a/osfmk/ppc/cswtch.s +++ b/osfmk/ppc/cswtch.s @@ -30,6 +30,7 @@ #include #include #include +#include #define FPVECDBG 0 #define GDDBG 0 @@ -46,12 +47,19 @@ * otherwise both entry points are identical. */ -ENTRY2(load_context, Load_context, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(load_context) + +LEXT(load_context) + + .globl EXT(Load_context) + +LEXT(Load_context) /* * Since this is the first thread, we came in on the interrupt * stack. The first thread never returns, so there is no need to - * worry about saving its frame, hence we can reset the istackptr + e worry about saving its frame, hence we can reset the istackptr * back to the saved_state structure at it's top */ @@ -63,29 +71,26 @@ ENTRY2(load_context, Load_context, TAG_NO_FRAME_USED) mfsprg r6,0 lwz r0,PP_INTSTACK_TOP_SS(r6) - lwz r11,PP_CPU_DATA(r6) stw r0,PP_ISTACKPTR(r6) - stw r3,CPU_ACTIVE_THREAD(r11) + stw r3,PP_ACTIVE_THREAD(r6) /* Find the new stack and store it in active_stacks */ lwz r12,PP_ACTIVE_STACKS(r6) lwz r1,THREAD_KERNEL_STACK(r3) lwz r9,THREAD_TOP_ACT(r3) /* Point to the active activation */ + mtsprg 1,r9 stw r1,0(r12) li r0,0 /* Clear a register */ lwz r8,ACT_MACT_PCB(r9) /* Get the savearea used */ - lwz r10,SAVflags(r8) /* Get the savearea flags */ rlwinm r7,r8,0,0,19 /* Switch to savearea base */ lwz r11,SAVprev(r8) /* Get the previous savearea */ mfmsr r5 /* Since we are passing control, get our MSR values */ lwz r1,saver1(r8) /* Load new stack pointer */ - rlwinm r10,r10,0,1,31 /* Remove the attached flag */ stw r0,saver3(r8) /* Make sure we pass in a 0 for the continuation */ lwz r7,SACvrswap(r7) /* Get the translation from virtual to real */ stw r0,FM_BACKPTR(r1) /* zero backptr */ stw r5,savesrr1(r8) /* Pass our MSR to the new guy */ - stw r10,SAVflags(r8) /* Pass back the flags */ xor r3,r7,r8 /* Get the physical address of the new context save area */ stw r11,ACT_MACT_PCB(r9) /* Unstack our savearea */ b EXT(exception_exit) /* Go end it all... */ @@ -102,10 +107,14 @@ ENTRY2(load_context, Load_context, TAG_NO_FRAME_USED) /* void Call_continuation( void (*continuation)(void), vm_offset_t stack_ptr) */ -ENTRY(Call_continuation, TAG_NO_FRAME_USED) - mtlr r3 - mr r1, r4 /* Load new stack pointer */ - blr /* Jump to the continuation */ + .align 5 + .globl EXT(Call_continuation) + +LEXT(Call_continuation) + + mtlr r3 + mr r1, r4 /* Load new stack pointer */ + blr /* Jump to the continuation */ /* * Get the old kernel stack, and store into the thread structure. @@ -129,48 +138,59 @@ ENTRY(Call_continuation, TAG_NO_FRAME_USED) */ -ENTRY(Switch_context, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(Switch_context) - mfsprg r6,0 /* Get the per_proc block */ - lwz r12,PP_ACTIVE_STACKS(r6) +LEXT(Switch_context) + + mfsprg r12,0 ; Get the per_proc block + lwz r10,PP_ACTIVE_STACKS(r12) ; Get the pointer to the current stack #if DEBUG - lwz r11,PP_ISTACKPTR(r6) ; (DEBUG/TRACE) make sure we are not + lwz r11,PP_ISTACKPTR(r12) ; (DEBUG/TRACE) make sure we are not mr. r11,r11 ; (DEBUG/TRACE) on the interrupt bne+ notonintstack ; (DEBUG/TRACE) stack BREAKPOINT_TRAP notonintstack: #endif - stw r4,THREAD_CONTINUATION(r3) - cmpwi cr1,r4,0 /* used waaaay down below */ - lwz r7,0(r12) + stw r4,THREAD_CONTINUATION(r3) ; Set continuation into the thread + cmpwi cr1,r4,0 ; used waaaay down below + lwz r7,0(r10) ; Get the current stack /* * Make the new thread the current thread. */ - lwz r11,PP_CPU_DATA(r6) - stw r7,THREAD_KERNEL_STACK(r3) - stw r5, CPU_ACTIVE_THREAD(r11) + stw r7,THREAD_KERNEL_STACK(r3) ; Remember the current stack in the thread (do not need???) + stw r5, PP_ACTIVE_THREAD(r12) ; Make the new thread current - lwz r11,THREAD_KERNEL_STACK(r5) + lwz r11,THREAD_KERNEL_STACK(r5) ; Get the new stack pointer - lwz r5,THREAD_TOP_ACT(r5) - lwz r10,PP_ACTIVE_STACKS(r6) + lwz r5,THREAD_TOP_ACT(r5) ; Get the new activation + mtsprg 1,r5 lwz r7,CTHREAD_SELF(r5) ; Pick up the user assist word lwz r8,ACT_MACT_PCB(r5) ; Get the PCB for the new guy - - stw r11,0(r10) ; Save the kernel stack address - stw r7,UAW(r6) ; Save the assist word for the "ultra fast path" + +#if 0 + lwz r0,SAVflags(r8) ; (TEST/DEBUG) + rlwinm r0,r0,24,24,31 ; (TEST/DEBUG) + cmplwi r0,SAVempty ; (TEST/DEBUG) + bne+ nnnn ; (TEST/DEBUG) + b . ; (TEST/DEBUG) +nnnn: ; (TEST/DEBUG) +#endif + + stw r11,0(r10) ; Save the new kernel stack address + stw r7,UAW(r12) ; Save the assist word for the "ultra fast path" lwz r11,ACT_MACT_BTE(r5) ; Get BlueBox Task Environment lwz r7,ACT_MACT_SPF(r5) ; Get the special flags lwz r10,ACT_KLOADED(r5) - stw r11,ppbbTaskEnv(r6) ; Save the bb task env + stw r11,ppbbTaskEnv(r12) ; Save the bb task env li r0,0 cmpwi cr0,r10,0 - lwz r10,PP_ACTIVE_KLOADED(r6) - stw r7,spcFlags(r6) ; Set per_proc copy of the special flags + lwz r10,PP_ACTIVE_KLOADED(r12) + stw r7,spcFlags(r12) ; Set per_proc copy of the special flags beq cr0,.L_sw_ctx_not_kld stw r5,0(r10) @@ -197,26 +217,131 @@ notonintstack: cswNoTrc: mfmsr r6 /* Get the MSR because the switched to thread should inherit it */ lwz r7,SACvrswap(r7) /* Get the translation from virtual to real */ - lis r0,hi16(SwitchContextCall) /* Top part of switch context */ - lis r9,hi16(EXT(switch_in)) /* Get top of switch in routine */ stw r11,ACT_MACT_PCB(r5) /* Dequeue the savearea we're switching to */ rlwinm r6,r6,0,MSR_FP_BIT+1,MSR_FP_BIT-1 /* Turn off the FP */ - ori r9,r9,lo16(EXT(switch_in)) /* Bottom half of switch in */ - lwz r5,savesrr0(r8) /* Set up the new SRR0 */ + lwz r2,curctx(r5) ; Grab our current context pointer rlwinm r6,r6,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 /* Turn off the vector */ mr r4,r3 /* Save our old thread to pass back */ + + lhz r0,PP_CPU_NUMBER(r12) ; Get our CPU number + lwz r10,FPUowner(r12) ; Grab the owner of the FPU + lwz r9,VMXowner(r12) ; Grab the owner of the vector + cmplw r10,r2 ; Do we have the live float context? + lwz r10,FPUlevel(r2) ; Get the live level + cmplw cr5,r9,r2 ; Do we have the live vector context? + bne+ cswnofloat ; Float is not ours... + + cmplw r10,r11 ; Is the level the same? + lwz r5,FPUcpu(r2) ; Get the owning cpu + bne+ cswnofloat ; Level not the same, this is not live... + + cmplw r5,r0 ; Still owned by this cpu? + lwz r10,FPUsave(r2) ; Get the level + bne+ cswnofloat ; CPU claimed by someone else... + + mr. r10,r10 ; Is there a savearea here? + ori r6,r6,lo16(MASK(MSR_FP)) ; Enable floating point + + beq- cswnofloat ; No savearea to check... + + lwz r3,SAVlevel(r10) ; Get the level + lwz r5,SAVprev(r10) ; Get the previous of this savearea + cmplw r3,r11 ; Is it for the current level? + + bne+ cswnofloat ; Nope... + + stw r5,FPUsave(r2) ; Pop off this savearea + rlwinm r5,r10,0,0,19 ; Move back to start of page + lwz r5,SACvrswap(r5) ; Get the virtual to real conversion + la r9,quickfret(r12) ; Point to the quickfret chain header + xor r5,r10,r5 ; Convert savearea address to real + +#if FPVECDBG + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x4401 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) + lhz r0,PP_CPU_NUMBER(r12) ; (TEST/DEBUG) +#endif + +; +; Note: we need to do the atomic operation here because, even though +; it is impossible with the current implementation, that we may take a +; PTE miss between the load of the quickfret anchor and the subsequent +; store. The interrupt handler will dequeue everything on the list and +; we could end up using stale data. I do not like doing this... +; + +cswfpudq: lwarx r3,0,r9 ; Pick up the old chain head + stw r3,SAVprev(r10) ; Move it to the current guy + stwcx. r5,0,r9 ; Save it + bne- cswfpudq ; Someone chaged the list... + +cswnofloat: bne+ cr5,cswnovect ; Vector is not ours... + + lwz r10,VMXlevel(r2) ; Get the live level + + cmplw r10,r11 ; Is the level the same? + lwz r5,VMXcpu(r2) ; Get the owning cpu + bne+ cswnovect ; Level not the same, this is not live... + + cmplw r5,r0 ; Still owned by this cpu? + lwz r10,VMXsave(r2) ; Get the level + bne+ cswnovect ; CPU claimed by someone else... + + mr. r10,r10 ; Is there a savearea here? + oris r6,r6,hi16(MASK(MSR_VEC)) ; Enable vector + + beq- cswnovect ; No savearea to check... + + lwz r3,SAVlevel(r10) ; Get the level + lwz r5,SAVprev(r10) ; Get the previous of this savearea + cmplw r3,r11 ; Is it for the current level? + + bne+ cswnovect ; Nope... + + stw r5,VMXsave(r2) ; Pop off this savearea + rlwinm r5,r10,0,0,19 ; Move back to start of page + lwz r5,SACvrswap(r5) ; Get the virtual to real conversion + la r9,quickfret(r12) ; Point to the quickfret chain header + xor r5,r10,r5 ; Convert savearea address to real + +#if FPVECDBG + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x4501 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + +; +; Note: we need to do the atomic operation here because, even though +; it is impossible with the current implementation, that we may take a +; PTE miss between the load of the quickfret anchor and the subsequent +; store. The interrupt handler will dequeue everything on the list and +; we could end up using stale data. I do not like doing this... +; + +cswvecdq: lwarx r3,0,r9 ; Pick up the old chain head + stw r3,SAVprev(r10) ; Move it to the current guy + stwcx. r5,0,r9 ; Save it + bne- cswvecdq ; Someone chaged the list... + +cswnovect: lis r9,hi16(EXT(switch_in)) /* Get top of switch in routine */ + lwz r5,savesrr0(r8) /* Set up the new SRR0 */ + ori r9,r9,lo16(EXT(switch_in)) /* Bottom half of switch in */ + lis r0,hi16(SwitchContextCall) /* Top part of switch context */ stw r9,savesrr0(r8) /* Make us jump to the switch in routine */ + li r10,MSR_SUPERVISOR_INT_OFF /* Get the switcher's MSR */ lwz r9,SAVflags(r8) /* Get the flags */ stw r10,savesrr1(r8) /* Set up for switch in */ rlwinm r9,r9,0,15,13 /* Reset the syscall flag */ ori r0,r0,lo16(SwitchContextCall) /* Bottom part of switch context */ - rlwinm r9,r9,0,1,31 /* Clear the attached flag */ xor r3,r7,r8 /* Get the physical address of the new context save area */ stw r9,SAVflags(r8) /* Set the flags */ -/* if blocking on continuation avoid saving state */ - bne cr1,1f + + bne cr1,swtchtocont ; Switch to the continuation sc /* Switch to the new context */ /* We come back here in the new thread context @@ -224,10 +349,22 @@ cswNoTrc: mfmsr r6 /* Get the MSR because the switched to thread should i * R3 where it belongs. */ blr /* Jump into the new thread */ + +; +; This is where we go when a continuation is set. We are actually +; killing off the old context of the new guy so we need to pop off +; any float or vector states for the ditched level. +; +; Note that we do the same kind of thing a chkfac in hw_exceptions.s +; + -1: stw r5,savesrr0(r8) /* go to real pc */ - stw r4,saver3(r8) /* must pass back old thread */ - b EXT(exception_exit) /* blocking on continuation, avoid state save */ +swtchtocont: + stw r5,savesrr0(r8) ; Set the pc + stw r6,savesrr1(r8) ; Set the next MSR to use + stw r4,saver3(r8) ; Make sure we pass back the old thread + + b EXT(exception_exit) ; Blocking on continuation, toss old context... @@ -246,10 +383,13 @@ cswNoTrc: mfmsr r6 /* Get the MSR because the switched to thread should i */ -ENTRY(switch_in, TAG_NO_FRAME_USED) + + .align 5 + .globl EXT(switch_in) + +LEXT(switch_in) lwz r4,saver4(r3) /* Get the old thread */ - li r8,MSR_VM_OFF /* Set to everything off */ lwz r9,THREAD_TOP_ACT(r4) /* Get the switched from ACT */ lwz r5,saver5(r3) /* Get the srr0 value */ lwz r10,ACT_MACT_PCB(r9) /* Get the top PCB on the old thread */ @@ -275,398 +415,158 @@ ENTRY(switch_in, TAG_NO_FRAME_USED) /* - * void fpu_save(thread_act_t act) - * - * To do the floating point and VMX, we keep three thread pointers: one - * to the current thread, one to the thread that has the floating point context - * loaded into the FPU registers, and one for the VMX owner. + * void fpu_save(facility_context ctx) * - * Each of these threads has three PCB pointers. The normal PCB, the FPU pcb, - * and the VMX pcb. There is also a bit for each in the savearea flags. - * When we take an exception, or need to use the FPU/VMX in the kernel, we call - * this routine. It checks to see if there is an owner thread for the facility. - * If so, it saves the facility's state information in the normal PCB. Then, it - * turns on the appropriate flag in the savearea to indicate that the state is - * in that particular savearea. Also, the thread pointer for the owner in - * the per_processor block is cleared. Note that we don't have to worry about the - * PCB pointers in the thread because whenever the state is loaded, the associated - * savearea is released and the pointer cleared. This is done so that the facility - * context always migrates to the normal savearea/PCB. This always insures that - * no more than 2 saveareas are used for a thread. - * - * When the context is loaded into the facility, the associated PCB is released if - * its usage flags indicate that it is empty. (Note that return from exception and - * context switch honor these flags and won't release a savearea if there is unrestored - * facility context.) The per_processor is set to point to the facility owner's - * thread and the associated PCB pointer within the thread is cleared because - * the PCB has been released. - * - * Part of loading a context is to release the savearea. If the savearea contains - * other context, the savearea cannot be released. So, what we're left with is - * that there will be no normal context savearea, but one for the as-not-yet - * restored facility savearea. Again, when that context is reloaded, the PCB - * is released, and when it is again stored, it goes into the "normal" savearea. - * - * So, what do we do when there is no general context, and we have some FPU/VMX - * state to save? Heck if I know, but it happens when we switch threads when - * we shortcut system calls. The question is: does the target thread carry the - * FPU/VMX context with it or not? Actually, it don't matter, not one little bit. - * If we are asked to save it, we gotta. It's a really lousy way to do it, but - * short of starting over with FPUs, it's what's what. Therefore, we'll - * allocate an FPU context save and attach it. - * - * Actually, it's not quite that simple: since we aren't in - * in interrupt handler context (that's only in fpu_switch) we can't use - * quickfret to merge FPU into general context. So, if there is an FPU - * savearea, we need to use that. So what we do is: if there is FPU context - * use that. If there is a general context, then use that. If neither, - * allocate a savearea and make that the FPU context. - * - * The next thing we have to do is to allow the kernel to use both the - * floating point and Altivec. It is not recommended, but there may be a - * good reason to do so. So, what we need to do is to treat each of the - * three types of context the same, by keeping a LIFO chain of states. - * We do have a problem with that in that there can be multiple levels of - * kernel context. For example, we are using floating point and we take a - * page fault, and somehow start using the FPU, and take another page fault, - * etc. - * - * Anyway, we will hope that we only reasonably use floating point and vectors in - * the kernel. And try to pack the context in as few saveareas as possible. - * - * The way we keep these "levels" of floating point or vector context straight is - * to remember the top of the normal savearea chain when we activate the - * facility when it is first used. Then, when we save that context, this value - * is saved in its level field. - * - * What the level concept gives us is a way to distinguish between multiple - * independent contexts under the same thread activation. Any time we take - * any kind of interruption (trap, system call, I/O interruption), we are, - * in effect, running with a different context even though we are in the - * same thread. The top savearea address is used only as a marker. It does not - * point to any context associated with the float or vector context. For example, - * the top savearea pointer will always be 0 for the user context, because there - * it it always last on the list. - * - * As normal context is unstacked, the first facility context is checked and - * if there is a match, the facility savearea is released. This is because we - * are returning to a level before the facility saved there was used. In effect, - * this allows us to unwind the facility context saveareas at different rates. - * - * In conjunction with the current activation, these markers are also used to - * determine the state of the facility enablement. Whenever the facility context is - * "live," i.e., loaded in the hardware registers and belonging to the currently - * running context, the facility is enabled before dispatch. - * - * There is nothing special about using floating point or vector facilities, - * no preliminary saving, enabling, or disabling. You just use them. The only exception - * is during context switching on an SMP system. In this case, the context must - * be saved as there is no guarantee that the thread will resume on the same - * processor. This is not a good thing, not at all. - * - * Whenever we switch out a thread with a dirty context, we always need to save it - * because it can wake up on a different processor. However, once the context has - * been saved, we don't need to save it again until it gets dirty, nor do we need - * to reload it unless someone else's context has been loaded. To handle this - * optimization, we need 3 things. We need to know what processor the saved context - * was last loaded on, whether the loaded context could be dirty, and if we've already - * saved it. - * - * Whenever the facility is enabled, the processor ID is saved in the activation. This - * will show which processor has dirty data. When a context switch occurs, the facility - * contexts are saved, but are still remembered as live. The next time we need to - * context switch, we first check if the state is live, and if not, do no state - * saving. Then we check if the state has already been save and if not, save it. - * The facility is always disabled on a context switch. On a UP, this save function - * does not occur. - * - * Whenever a facility unavailable interruption occurs, the current state is saved - * if it is live and unsaved. However, if the live state is the same as the new - * one to be loaded, the processor ID is checked and if it is the current processor - * the state does not need to be loaded or saved. The facility is simply enabled. - * - * Once allocated, facility saveareas are not released until a return is made to a - * previous level. Once a facility has been enabled, there is no way to tell if - * it will ever be used again, but it is likely. Therefore, discarding a savearea - * when its context is made live is extra overhead. So, we don't do it, but we - * do mark the savearea contents as invalid. - * + * Note that there are some oddities here when we save a context we are using. + * It is really not too cool to do this, but what the hey... Anyway, + * we turn fpus and vecs off before we leave., The oddity is that if you use fpus after this, the + * savearea containing the context just saved will go away. So, bottom line is + * that don't use fpus until after you are done with the saved context. */ + .align 5 + .globl EXT(fpu_save) -/* -; The following is the actual way it is implemented. It doesn't quite match -; the above text. I need to go and fix that. -; -; Context download (operates on owner's data): -; -; 0) enable facility -; 1) if no owner exit to context restore -; 2) if context processor != current processor exit to context restore -; 3) if current activation == owner activation: -; 1) if curr level == active level: -; 1) if top facility savearea exists: -; invalidate savearea by setting level to 1 -; 2) enable facility for user -; 3) exit -; -; 2) else go to 5 -; -; 4) if curr level == active level: -; 1) if top facility savearea exists: -; 1) if top save level == active level exit to context restore -; -; 5) allocate savearea -; 1) if there is a facility save and it is invalid, select it, and break -; 2) scan normal list for free facility area, select if found, and break -; 3) scan other facility for free save: select, if found, and break -; 4) allocate a new save area -; -; 6) save context -; 7) mark facility save with curr level -; 8) if reusing cached savearea (case #1) exit to context restore -; 9) set facility save backchain to facility top savearea -; 10) set facility top to savearea -; 11) exit to context restore -; -; -; Context restore/upload (operates on current activation's data): -; -; 1) set current to activation -; 2) set active level to current level -; 3) set context processor to current processor -; 4) if no facility savearea or top save level != curr level -; initialize facility registers to empty value -; 5) else -; 1) load registers from savearea -; 2) invalidate save area by setting level to 1 -; -; 6) enable facility for user -; 7) exit to interrupt return -; -; -; Context save (operates on specified activation's data): - -; 1) if no owner exit -; 2) if owner != specified activation exit -; 3) if context processor != current processor -; 1) clear owner -; 2) exit -; -; 4) if facility top savearea level exists and == active level exit -; 5) if curr level != active level exit -; 6) allocate savearea -; 1) if there is a facility save and it is invalid, select it, and break -; 2) scan normal list for free facility area, select if found, and break -; 3) scan other facility for free save: select, if found, and break -; 4) allocate a new save area -; 7) save context -; 8) mark facility savearea with curr level -; 9) if reusing cached savearea (case #1) exit -; 10) set facility save backchain to facility top savearea -; 11) set facility top to savearea -; 12) exit -; -; -; Exception exit (hw_exceptions): -; -; 1) disable return facility -; 2) if returning savearea != active level -; 1) if owner != current activation exit -; 2) if context processor != current processor: -; 1) clear owner -; 2) exit -; -; 3) if new level != active level exit -; 4) enable return facility -; 5) exit -; -; 3) if no facility savearea exit -; 4) if top save level == active or top is invalid -; 1) dequeue top facility savearea -; 2) set active level to new top savearea's level -; 3) release savearea -; 4) if owner == current activation clear owner -; 5) exit -; -; -; -; -; if (owner == activation) && (curr level == active level) -; && (activation processor == current processor) ::= context live -*/ - -ENTRY(fpu_save, TAG_NO_FRAME_USED) - - mfmsr r0 ; Get the MSR - rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Turn off floating point forever +LEXT(fpu_save) + + + mfmsr r0 ; Get the MSR + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Force vectors off rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; But do interrupts only for now - ori r2,r2,MASK(MSR_FP) ; Enable the floating point feature for now also - mtmsr r2 ; Set the MSR + ori r2,r2,MASK(MSR_FP) ; Enable the floating point feature for now also + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force floating point off + mtmsr r2 ; Set the MSR isync - - mfsprg r6,0 ; Get the per_processor block - lwz r12,PP_FPU_THREAD(r6) ; Get the thread that owns the FPU + + mfsprg r6,0 ; Get the per_processor block + lwz r12,FPUowner(r6) ; Get the context ID for owner + #if FPVECDBG - mr r7,r0 ; (TEST/DEBUG) - li r4,0 ; (TEST/DEBUG) - mr r10,r3 ; (TEST/DEBUG) - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - mr. r3,r12 ; (TEST/DEBUG) - li r2,0x6F00 ; (TEST/DEBUG) - li r5,0 ; (TEST/DEBUG) - beq- noowneryet ; (TEST/DEBUG) - lwz r4,ACT_MACT_FPUlvl(r12) ; (TEST/DEBUG) - lwz r5,ACT_MACT_FPU(r12) ; (TEST/DEBUG) - -noowneryet: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) - mr r0,r7 ; (TEST/DEBUG) - mr r3,r10 ; (TEST/DEBUG) + mr r7,r0 ; (TEST/DEBUG) + li r4,0 ; (TEST/DEBUG) + mr r10,r3 ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + mr. r3,r12 ; (TEST/DEBUG) + li r2,0x6F00 ; (TEST/DEBUG) + li r5,0 ; (TEST/DEBUG) + beq- noowneryet ; (TEST/DEBUG) + lwz r4,FPUlevel(r12) ; (TEST/DEBUG) + lwz r5,FPUsave(r12) ; (TEST/DEBUG) + +noowneryet: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) + mr r0,r7 ; (TEST/DEBUG) + mr r3,r10 ; (TEST/DEBUG) #endif - mflr r2 ; Save the return address - lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number + mflr r2 ; Save the return address + +fsretry: mr. r12,r12 ; Anyone own the FPU? + lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number + beq- fsret ; Nobody owns the FPU, no save required... - mr. r12,r12 ; Anyone own the FPU? - cmplw cr1,r3,r12 ; Is the specified thread the owner? + cmplw cr1,r3,r12 ; Is the specified context live? - beq- fsretnr ; Nobody owns the FPU, no save required... + isync ; Force owner check first - li r4,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word - bne- cr1,fsretnr ; Facility belongs to some other activation... + lwz r9,FPUcpu(r12) ; Get the cpu that context was last on + bne- cr1,fsret ; No, it is not... -fsvSpin2: lwarx r9,r4,r12 ; Get and reserve the last used CPU - mr. r9,r9 ; Is it changing now? - oris r3,r9,hi16(fvChk) ; Set the "changing" flag - blt- fsvSpin2 ; Spin if changing - stwcx. r3,r4,r12 ; Lock it up - bne- fsvSpin2 ; Someone is messing right now + cmplw cr1,r9,r11 ; Was the context for this processor? + beq- cr1,fsgoodcpu ; Facility last used on this processor... - isync ; Make sure we see everything + b fsret ; Someone else claimed it... - cmplw cr1,r9,r11 ; Was the context for this processor? - li r3,0 ; Assume we need a fix-me-up - beq- cr1,fsgoodcpu ; Facility last used on this processor... - stw r3,PP_FPU_THREAD(r6) ; Clear owner because it was really on the other processor - b fsret ; Bail now with no save... + .align 5 -fsgoodcpu: lwz r3,ACT_MACT_FPU(r12) ; Get the current FPU savearea for the thread - lwz r9,ACT_MACT_FPUlvl(r12) ; Get our current level indicator +fsgoodcpu: lwz r3,FPUsave(r12) ; Get the current FPU savearea for the thread + lwz r9,FPUlevel(r12) ; Get our current level indicator - cmplwi cr1,r3,0 ; Have we ever saved this facility context? - beq- cr1,fsneedone ; Never saved it, so we need an area... + cmplwi cr1,r3,0 ; Have we ever saved this facility context? + beq- cr1,fsneedone ; Never saved it, so go do it... - lwz r8,SAVlvlfp(r3) ; Get the level this savearea is for - cmplwi r8,1 ; See if it is a spare - cmplw cr1,r9,r8 ; Correct level? - beq+ fsusespare ; We have a spare to use... - beq- cr1,fsret ; The current level is already saved, bail out... + lwz r8,SAVlevel(r3) ; Get the level this savearea is for + cmplw cr1,r9,r8 ; Correct level? + beq- cr1,fsret ; The current level is already saved, bail out... -fsneedone: li r3,0 ; Tell the routine to allocate an area if none found - bl fpsrchsave ; Find a free savearea - - mfsprg r6,0 ; Get back per_processor block - oris r7,r7,hi16(SAVfpuvalid) ; Set the allocated bit - lwz r12,PP_FPU_THREAD(r6) ; Get back our thread - mtlr r2 ; Restore return - lwz r8,ACT_MACT_FPU(r12) ; Get the current top floating point savearea - lwz r9,ACT_MACT_FPUlvl(r12) ; Get our current level indicator again - stw r3,ACT_MACT_FPU(r12) ; Set this as the latest FPU savearea for the thread - stw r8,SAVprefp(r3) ; And then chain this in front - stw r7,SAVflags(r3) ; Set the validity flags - stw r12,SAVact(r3) ; Make sure we point to the right guy +fsneedone: bl EXT(save_get) ; Get a savearea for the context + + mfsprg r6,0 ; Get back per_processor block + li r4,SAVfloat ; Get floating point tag + lwz r12,FPUowner(r6) ; Get back our thread + stb r4,SAVflags+2(r3) ; Mark this savearea as a float + mr. r12,r12 ; See if we were disowned while away. Very, very small chance of it... + beq- fsbackout ; If disowned, just toss savearea... + lwz r4,facAct(r12) ; Get the activation associated with live context + mtlr r2 ; Restore return + lwz r8,FPUsave(r12) ; Get the current top floating point savearea + stw r4,SAVact(r3) ; Indicate the right activation for this context + lwz r9,FPUlevel(r12) ; Get our current level indicator again + stw r3,FPUsave(r12) ; Set this as the most current floating point context + stw r8,SAVprev(r3) ; And then chain this in front -fsusespare: stw r9,SAVlvlfp(r3) ; And set the level this savearea is for + stw r9,SAVlevel(r3) ; Show level in savearea ; ; Save the current FPU state into the PCB of the thread that owns it. ; - la r11,savefp0(r3) ; Point to the 1st line - dcbz 0,r11 ; Allocate the first savearea line + la r11,savefp0(r3) ; Point to the 1st line + dcbz 0,r11 ; Allocate the first savearea line - la r11,savefp4(r3) /* Point to the 2nd line */ + la r11,savefp4(r3) ; Point to the 2nd line stfd f0,savefp0(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f1,savefp1(r3) stfd f2,savefp2(r3) - la r11,savefp8(r3) /* Point to the 3rd line */ + la r11,savefp8(r3) ; Point to the 3rd line stfd f3,savefp3(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f4,savefp4(r3) stfd f5,savefp5(r3) stfd f6,savefp6(r3) - la r11,savefp12(r3) /* Point to the 4th line */ + la r11,savefp12(r3) ; Point to the 4th line stfd f7,savefp7(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f8,savefp8(r3) stfd f9,savefp9(r3) stfd f10,savefp10(r3) - la r11,savefp16(r3) /* Point to the 5th line */ + la r11,savefp16(r3) ; Point to the 5th line stfd f11,savefp11(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f12,savefp12(r3) stfd f13,savefp13(r3) stfd f14,savefp14(r3) - la r11,savefp20(r3) /* Point to the 6th line */ + la r11,savefp20(r3) ; Point to the 6th line stfd f15,savefp15(r3) stfd f16,savefp16(r3) stfd f17,savefp17(r3) stfd f18,savefp18(r3) - la r11,savefp24(r3) /* Point to the 7th line */ + la r11,savefp24(r3) ; Point to the 7th line stfd f19,savefp19(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f20,savefp20(r3) - lwz r10,liveFPSCR(r6) ; Get the previously saved FPSCR stfd f21,savefp21(r3) stfd f22,savefp22(r3) - li r9,0 ; Just clear this out - la r11,savefp28(r3) /* Point to the 8th line */ + la r11,savefp28(r3) ; Point to the 8th line stfd f23,savefp23(r3) - dcbz 0,r11 /* allocate it */ + dcbz 0,r11 ; Allocate it stfd f24,savefp24(r3) stfd f25,savefp25(r3) stfd f26,savefp26(r3) stfd f27,savefp27(r3) stfd f28,savefp28(r3) -; Note that we just save the FPSCR here for ease. It is really already saved -; in the "normal" context area of the savearea. - - stw r9,savefpscrpad(r3) ; Save the FPSCR pad - stw r10,savefpscr(r3) ; Save the FPSCR - stfd f29,savefp29(r3) stfd f30,savefp30(r3) stfd f31,savefp31(r3) - lfd f0,savefp0(r3) ; We need to restore F0 because we used it - ; to get the FPSCR - -#if 0 - la r9,savefp0(r3) ; (TEST/DEBUG) - la r10,savefp31(r3) ; (TEST/DEBUG) - -chkkillmedead: - lha r8,0(r9) ; (TEST/DEBUG) - addi r9,r9,8 ; (TEST/DEBUG) - cmpwi r8,-8 ; (TEST/DEBUG) - cmplw cr1,r9,r10 ; (TEST/DEBUG) - bne+ dontkillmedead ; (TEST/DEBUG) - BREAKPOINT_TRAP ; (TEST/DEBUG) - -dontkillmedead: ; (TEST/DEBUG) - ble+ cr1,chkkillmedead ; (TEST/DEBUG) -#endif - -fsret: lwz r4,ACT_MACT_FPUcpu(r12) ; Get back the owner CPU - rlwinm r4,r4,0,fvChkb+1,31 ; Clear lock - sync - stw r4,ACT_MACT_FPUcpu(r12) ; Unlock the context - -fsretnr: mtmsr r0 ; Put interrupts on if they were and floating point off + +fsret: mtmsr r0 ; Put interrupts on if they were and floating point off isync blr +fsbackout: mr r12,r0 ; Save the original MSR + b EXT(save_ret_join) ; Toss savearea and return from there... + /* * fpu_switch() * @@ -685,356 +585,271 @@ fsretnr: mtmsr r0 ; Put interrupts on if they were and floating point off * */ -ENTRY(fpu_switch, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(fpu_switch) + +LEXT(fpu_switch) + #if DEBUG -#if GDDBG - mr r7,r4 ; Save input parameter - lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter - ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter - lwz r1,0(r3) - lis r5,hi16(EXT(GratefulDeb)) ; Point to top of display - ori r5,r5,lo16(EXT(GratefulDeb)) ; Put in bottom part - addi r1,r1,1 - mtlr r5 ; Set link register - stw r1,0(r3) - mr r4,r1 - li r3,0 - blrl ; Display count - mr r4,r7 ; Restore the parameter -#else lis r3,hi16(EXT(fpu_trap_count)) ; Get address of FP trap counter ori r3,r3,lo16(EXT(fpu_trap_count)) ; Get address of FP trap counter lwz r1,0(r3) addi r1,r1,1 stw r1,0(r3) -#endif #endif /* DEBUG */ - mfsprg r6,0 ; Get the per_processor block - mfmsr r19 ; Get the current MSR - - lwz r10,PP_CPU_DATA(r6) ; Get the CPU data pointer - lwz r12,PP_FPU_THREAD(r6) ; Get the thread that owns the FPU - lwz r10,CPU_ACTIVE_THREAD(r10) ; Get the pointer to the active thread - ori r19,r19,lo16(MASK(MSR_FP)) ; Enable the floating point feature - lwz r17,THREAD_TOP_ACT(r10) ; Now get the activation that is running - -; R12 has the "old" activation -; R17 has the "new" activation - -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F01 ; (TEST/DEBUG) - mr r3,r12 ; (TEST/DEBUG) - mr r5,r17 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - mr. r12,r12 ; See if there is any live FP status + mfsprg r26,0 ; Get the per_processor block + mfmsr r19 ; Get the current MSR - lhz r18,PP_CPU_NUMBER(r6) ; Get the current CPU, we will need it later + mr r25,r4 ; Save the entry savearea + lwz r22,FPUowner(r26) ; Get the thread that owns the FPU + lwz r10,PP_ACTIVE_THREAD(r26) ; Get the pointer to the active thread + ori r19,r19,lo16(MASK(MSR_FP)) ; Enable the floating point feature + lwz r17,THREAD_TOP_ACT(r10) ; Now get the activation that is running - mtmsr r19 ; Enable floating point instructions + mtmsr r19 ; Enable floating point instructions isync - - beq- fsnosave ; No live context, so nothing to save... - li r20,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word + lwz r27,ACT_MACT_PCB(r17) ; Get the current level + lwz r29,curctx(r17) ; Grab the current context anchor of the current thread -fsSpin1: lwarx r19,r20,r12 ; Get and reserve the last used CPU - mr. r19,r19 ; Is it changing now? - oris r21,r19,hi16(fvChk) ; Set the "changing" flag - blt- fsSpin1 ; Spin if changing - stwcx. r21,r20,r12 ; Lock it up - bne- fsSpin1 ; Someone is messing right now +; R22 has the "old" context anchor +; R29 has the "new" context anchor - isync ; Make sure we see everything - - lwz r15,ACT_MACT_PCB(r12) ; Get the current level of the "old" one - cmplw r18,r19 ; Check the CPU that the old context is live on - lwz r14,ACT_MACT_FPU(r12) ; Point to the top of the old context stack - bne- fsnosaverel ; Context is not live if used on a different CPU... - lwz r13,ACT_MACT_FPUlvl(r12) ; Get the "old" active level - -; -; First, check to see if all we are doing is enabling because the -; "new" context is live. -; #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F02 ; (TEST/DEBUG) - mr r1,r15 ; (TEST/DEBUG) - mr r3,r13 ; (TEST/DEBUG) - mr r5,r14 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F01 ; (TEST/DEBUG) + mr r3,r22 ; (TEST/DEBUG) + mr r5,r29 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + + lhz r16,PP_CPU_NUMBER(r26) ; Get the current CPU number - cmplw cr1,r12,r17 ; Are the "old" activation and the "new" the same? - cmplwi cr2,r14,0 ; Is there any saved context on the "old" activation? - bne+ cr1,fsmstsave ; The activations are different so "old" context must be saved... +fswretry: mr. r22,r22 ; See if there is any live FP status -; -; Here we know that both the "old" and "new" activations are the same. We will -; check the current level and active levels. If they are the same, the context is -; already live, so all we do is turn on the facility and invalidate the top -; savearea. -; -; If the current level, the active level, and the top savearea level are the -; same, then the context was saved as part of a thread context switch and neither -; needs saving or restoration. -; -; In all other cases, the context must be saved unless we are just re-enabling -; floating point. -; + beq- fsnosave ; No live context, so nothing to save... - cmplw r13,r15 ; Are the levels the same? - cmplwi cr2,r14,0 ; Is there any saved context? - bne- fsmstsave ; Levels are different, we need to save... - - beq- cr2,fsenableret ; No saved context at all, enable and go... - - lwz r20,SAVlvlfp(r14) ; Get the level of the top savearea + isync ; Make sure we see this in the right order -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F03 ; (TEST/DEBUG) - mr r3,r15 ; (TEST/DEBUG) - mr r5,r20 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - cmplw r15,r20 ; Is the top level the same as the current? - li r0,1 ; Get the invalid flag - bne- fsenableret ; Not the same, just enable and go... - - stw r0,SAVlvlfp(r14) ; Invalidate that top savearea -fsenableret: - sync ; Make sure everything is saved - stw r19,ACT_MACT_FPUcpu(r12) ; Say we are not using the context anymore + lwz r30,FPUsave(r22) ; Get the top savearea + cmplw cr2,r22,r29 ; Are both old and new the same context? + lwz r18,FPUcpu(r22) ; Get the last CPU we ran on + cmplwi cr1,r30,0 ; Anything saved yet? + cmplw r18,r16 ; Make sure we are on the right processor + lwz r31,FPUlevel(r22) ; Get the context level - b fsenable ; Then enable and go... - + bne- fsnosave ; No, not on the same processor... + ; -; We need to save the "old" context here. The LIFO queueing scheme works -; out for all cases because if both the "new" and "old" activations are the -; same, there can not be any saved state to load. the "new" level is -; truely new. +; Check to see if the live context has already been saved. +; Also check to see if all we are here just to re-enable the MSR +; and handle specially if so. ; -; When we save the context, we either use a new savearea, or the free -; one that is cached at the head of the list. + + cmplw r31,r27 ; See if the current and active levels are the same + crand cr0_eq,cr2_eq,cr0_eq ; Remember if both the levels and contexts are the same + li r3,0 ; Clear this -fsmstsave: beq- cr2,fsgetsave ; There is no possible cached save area + beq- fsthesame ; New and old are the same, just go enable... + + beq- cr1,fsmstsave ; Not saved yet, go do it... - lwz r5,SAVlvlfp(r14) ; Get the level of first facility savearea -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F04 ; (TEST/DEBUG) - mr r3,r15 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#endif - mr r3,r14 ; Assume we are invalid - cmplwi r5,1 ; Is it invalid? - cmplw cr1,r5,r13 ; Is the SA level the active one? - beq+ fsusecache ; Invalid, just use it... - beq- cr1,fsnosaverel ; The SA level is active, it is already saved... + lwz r11,SAVlevel(r30) ; Get the level of top saved context -fsgetsave: mr r3,r4 ; Use the interrupt save as the context savearea if none cached + cmplw r31,r11 ; Are live and saved the same? + #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F05 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F02 ; (TEST/DEBUG) + mr r3,r30 ; (TEST/DEBUG) + mr r5,r31 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + + beq+ fsnosave ; Same level, so already saved... + - bl fpsrchsave ; Find a free savearea +fsmstsave: stw r3,FPUowner(r26) ; Kill the context now + eieio ; Make sure everyone sees it + bl EXT(save_get) ; Go get a savearea + + la r11,savefp0(r3) ; Point to the 1st line in new savearea + lwz r12,facAct(r22) ; Get the activation associated with the context + dcbz 0,r11 ; Allocate cache + stw r3,FPUsave(r22) ; Set this as the latest context savearea for the thread - stw r3,ACT_MACT_FPU(r12) ; Set this as the latest context savearea for the thread - mfsprg r6,0 ; Get back per_processor block - stw r14,SAVprefp(r3) ; And then chain this in front - oris r7,r7,hi16(SAVfpuvalid) ; Set the allocated bit - stw r12,SAVact(r3) ; Make sure we point to the right guy - stw r7,SAVflags(r3) ; Set the allocation flags + stw r30,SAVprev(r3) ; Point us to the old context + stw r31,SAVlevel(r3) ; Tag our level + li r7,SAVfloat ; Get the floating point ID + stw r12,SAVact(r3) ; Make sure we point to the right guy + stb r7,SAVflags+2(r3) ; Set that we have a floating point save area -fsusecache: la r11,savefp0(r3) ; Point to the 1st line in area - stw r13,SAVlvlfp(r3) ; Set this context level #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F06 ; (TEST/DEBUG) - mr r5,r13 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F03 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif ; ; Now we will actually save the old context ; - dcbz 0,r11 ; Allocate the output area - - la r11,savefp4(r3) ; Point to the 2nd line + la r11,savefp4(r3) ; Point to the 2nd line stfd f0,savefp0(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f1,savefp1(r3) stfd f2,savefp2(r3) - la r11,savefp8(r3) ; Point to the 3rd line + la r11,savefp8(r3) ; Point to the 3rd line stfd f3,savefp3(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f4,savefp4(r3) stfd f5,savefp5(r3) stfd f6,savefp6(r3) - la r11,savefp12(r3) ; Point to the 4th line + la r11,savefp12(r3) ; Point to the 4th line stfd f7,savefp7(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f8,savefp8(r3) stfd f9,savefp9(r3) stfd f10,savefp10(r3) - la r11,savefp16(r3) ; Point to the 5th line + la r11,savefp16(r3) ; Point to the 5th line stfd f11,savefp11(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f12,savefp12(r3) stfd f13,savefp13(r3) stfd f14,savefp14(r3) - la r11,savefp20(r3) ; Point to the 6th line + la r11,savefp20(r3) ; Point to the 6th line stfd f15,savefp15(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f16,savefp16(r3) stfd f17,savefp17(r3) stfd f18,savefp18(r3) - la r11,savefp24(r3) ; Point to the 7th line + la r11,savefp24(r3) ; Point to the 7th line stfd f19,savefp19(r3) - dcbz 0,r11 ; Allocate cache + dcbz 0,r11 ; Allocate cache stfd f20,savefp20(r3) - li r14,0 ; Clear this for now - lwz r15,liveFPSCR(r6) ; Get the previously saved FPSCR - stfd f21,savefp21(r3) stfd f22,savefp22(r3) - la r11,savefp28(r3) ; Point to the 8th line + la r11,savefp28(r3) ; Point to the 8th line stfd f23,savefp23(r3) - dcbz 0,r11 ; allocate it + dcbz 0,r11 ; allocate it stfd f24,savefp24(r3) stfd f25,savefp25(r3) stfd f26,savefp26(r3) - la r11,savefpscrpad(r3) ; Point to the 9th line stfd f27,savefp27(r3) - dcbz 0,r11 ; allocate it + dcbz 0,r11 ; allocate it stfd f28,savefp28(r3) stfd f29,savefp29(r3) stfd f30,savefp30(r3) stfd f31,savefp31(r3) -; Note that we just save the FPSCR here for ease. It is really already saved -; in the "normal" context area of the savearea. - - stw r14,savefpscrpad(r3) ; Save the FPSCR pad - stw r15,savefpscr(r3) ; Save the FPSCR - ; ; The context is all saved now and the facility is free. ; -; Now check out the "new" and see if we need to load up his context. -; If we do (and this should be the normal case), do it and then invalidate the -; savearea. (This will keep it cached for quick access next time around.) -; -; If we do not (remember, we already took care of the case where we just enable -; the FPU), we need to fill the registers with junk, because this level has +; If we do not we need to fill the registers with junk, because this level has ; never used them before and some thieving bastard could hack the old values ; of some thread! Just imagine what would happen if they could! Why, nothing ; would be safe! My God! It is terrifying! ; -fsnosaverel: - sync ; Make sure everything is saved - stw r19,ACT_MACT_FPUcpu(r12) ; Say we are not using the context anymore - -fsnosave: - li r20,ACT_MACT_FPUcpu ; Point to the CPU indication/lock word - -fsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU - mr. r19,r19 ; Is it changing now? - oris r21,r19,hi16(fvChk) ; Set the "changing" flag - blt- fsSpin2 ; Spin if changing - stwcx. r21,r20,r17 ; Lock it up - bne- fsSpin2 ; Someone is messing right now +fsnosave: lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one + lwz r19,FPUcpu(r29) ; Get the last CPU we ran on + lwz r14,FPUsave(r29) ; Point to the top of the "new" context stack - isync ; Make sure we see everything + stw r16,FPUcpu(r29) ; Claim context for us + eieio - lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one - lwz r14,ACT_MACT_FPU(r17) ; Point to the top of the "new" context stack - lwz r13,ACT_MACT_FPUlvl(r17) ; Get the "new" active level #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F07 ; (TEST/DEBUG) - mr r1,r15 ; (TEST/DEBUG) - mr r3,r14 ; (TEST/DEBUG) - mr r5,r13 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lwz r13,FPUlevel(r29) ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F04 ; (TEST/DEBUG) + mr r1,r15 ; (TEST/DEBUG) + mr r3,r14 ; (TEST/DEBUG) + mr r5,r13 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - - cmplwi cr1,r14,0 ; Do we possibly have some context to load? - stw r15,ACT_MACT_FPUlvl(r17) ; Set the "new" active level - la r11,savefp0(r14) ; Point to first line to bring in - stw r17,PP_FPU_THREAD(r6) ; Store current thread address in fpu_thread to claim fpu for thread + + lis r18,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r19,r19,ppSize ; Find offset to the owner per_proc + ori r18,r18,lo16(EXT(per_proc_info)) ; Set base per_proc + li r16,FPUowner ; Displacement to float owner + add r19,r18,r19 ; Point to the owner per_proc + li r0,0 + +fsinvothr: lwarx r18,r16,r19 ; Get the owner + cmplw r18,r29 ; Does he still have this context? + bne fsinvoths ; Nope... + stwcx. r0,r16,r19 ; Try to invalidate it + bne- fsinvothr ; Try again if there was a collision... + +fsinvoths: cmplwi cr1,r14,0 ; Do we possibly have some context to load? + la r11,savefp0(r14) ; Point to first line to bring in + stw r15,FPUlevel(r29) ; Set the "new" active level + eieio + stw r29,FPUowner(r26) ; Mark us as having the live context beq+ cr1,MakeSureThatNoTerroristsCanHurtUsByGod ; No "new" context to load... - lwz r0,SAVlvlfp(r14) ; Get the level of first facility savearea - cmplw r0,r15 ; Top level correct to load? + + dcbt 0,r11 ; Touch line in + + lwz r3,SAVprev(r14) ; Get the previous context + lwz r0,SAVlevel(r14) ; Get the level of first facility savearea + cmplw r0,r15 ; Top level correct to load? bne- MakeSureThatNoTerroristsCanHurtUsByGod ; No, go initialize... + + stw r3,FPUsave(r29) ; Pop the context (we will toss the savearea later) #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F08 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F05 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - dcbt 0,r11 ; Touch line in - li r0,1 ; Get the level invalid indication - - la r11,savefp4(r14) ; Point to next line - dcbt 0,r11 ; Touch line in + la r11,savefp4(r14) ; Point to next line + dcbt 0,r11 ; Touch line in lfd f0, savefp0(r14) lfd f1,savefp1(r14) - stw r0,SAVlvlfp(r14) ; Mark the savearea invalid because we are activating again lfd f2,savefp2(r14) - la r11,savefp8(r14) ; Point to next line + la r11,savefp8(r14) ; Point to next line lfd f3,savefp3(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f4,savefp4(r14) lfd f5,savefp5(r14) lfd f6,savefp6(r14) - la r11,savefp12(r14) ; Point to next line + la r11,savefp12(r14) ; Point to next line lfd f7,savefp7(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f8,savefp8(r14) lfd f9,savefp9(r14) lfd f10,savefp10(r14) - la r11,savefp16(r14) ; Point to next line + la r11,savefp16(r14) ; Point to next line lfd f11,savefp11(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f12,savefp12(r14) lfd f13,savefp13(r14) lfd f14,savefp14(r14) - la r11,savefp20(r14) ; Point to next line + la r11,savefp20(r14) ; Point to next line lfd f15,savefp15(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f16,savefp16(r14) lfd f17,savefp17(r14) lfd f18,savefp18(r14) - la r11,savefp24(r14) ; Point to next line + la r11,savefp24(r14) ; Point to next line lfd f19,savefp19(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f20,savefp20(r14) lfd f21,savefp21(r14) - la r11,savefp28(r14) ; Point to next line + la r11,savefp28(r14) ; Point to next line lfd f22,savefp22(r14) lfd f23,savefp23(r14) - dcbt 0,r11 ; Touch line in + dcbt 0,r11 ; Touch line in lfd f24,savefp24(r14) lfd f25,savefp25(r14) lfd f26,savefp26(r14) @@ -1044,35 +859,31 @@ fsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU lfd f30,savefp30(r14) lfd f31,savefp31(r14) -fsenablexx: sync ; Make sure all is saved - stw r18,ACT_MACT_FPUcpu(r17) ; Set the active CPU and release - -fsenable: lwz r9,SAVflags(r4) /* Get the flags of the current savearea */ - lwz r8,savesrr1(r4) ; Get the msr of the interrupted guy - rlwinm r5,r4,0,0,19 /* Get the page address of the savearea */ - ori r8,r8,MASK(MSR_FP) ; Enable the floating point feature - lwz r10,ACT_MACT_SPF(r17) ; Get the special flags - lis r7,hi16(SAVattach) /* Get the attached flag */ - lwz r5,SACvrswap(r5) /* Get Virtual to Real translation */ + mr r3,r14 ; Get the old savearea (we popped it before) + bl EXT(save_ret) ; Toss it + +fsenable: lwz r8,savesrr1(r25) ; Get the msr of the interrupted guy + rlwinm r5,r25,0,0,19 ; Get the page address of the savearea + ori r8,r8,MASK(MSR_FP) ; Enable the floating point feature + lwz r10,ACT_MACT_SPF(r17) ; Get the special flags + lwz r5,SACvrswap(r5) ; Get Virtual to Real translation oris r10,r10,hi16(floatUsed|floatCng) ; Set that we used floating point - mr. r15,r15 ; See if we are doing this for user state - stw r8,savesrr1(r4) ; Set the msr of the interrupted guy - andc r9,r9,r7 /* Clear the attached bit */ - xor r3,r4,r5 /* Get the real address of the savearea */ - bne- fsnuser ; We are not user state... - stw r10,ACT_MACT_SPF(r17) ; Set the activation copy - stw r10,spcFlags(r6) ; Set per_proc copy + rlwinm. r0,r8,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are doing this for user state + stw r8,savesrr1(r25) ; Set the msr of the interrupted guy + xor r3,r25,r5 ; Get the real address of the savearea + bne- fsnuser ; We are not user state... + stw r10,ACT_MACT_SPF(r17) ; Set the activation copy + stw r10,spcFlags(r26) ; Set per_proc copy fsnuser: #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F0A ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F07 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - stw r9,SAVflags(r4) /* Set the flags of the current savearea */ - b EXT(exception_exit) /* Exit from the fray... */ + b EXT(exception_exit) ; Exit to the fray... /* * Initialize the registers to some bogus value @@ -1080,27 +891,16 @@ fsnuser: MakeSureThatNoTerroristsCanHurtUsByGod: -#if 0 - lwz r10,savesrr1(r4) ; (TEST/DEBUG) - rlwinm. r10,r10,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG) - beq- nxxxxxx ; (TEST/DEBUG) - lwz r10,ACT_MACT_SPF(r17) ; (TEST/DEBUG) - rlwinm. r10,r10,0,1,1 ; (TEST/DEBUG) - beq+ nxxxxxx - BREAKPOINT_TRAP ; (TEST/DEBUG) -nxxxxxx: -#endif - #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x7F09 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F06 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - lis r5,hi16(EXT(FloatInit)) /* Get top secret floating point init value address */ - ori r5,r5,lo16(EXT(FloatInit)) /* Slam bottom */ - lfd f0,0(r5) /* Initialize FP0 */ - fmr f1,f0 ; Do them all + lis r5,hi16(EXT(FloatInit)) ; Get top secret floating point init value address + ori r5,r5,lo16(EXT(FloatInit)) ; Slam bottom + lfd f0,0(r5) ; Initialize FP0 + fmr f1,f0 ; Do them all fmr f2,f0 fmr f3,f0 fmr f4,f0 @@ -1117,11 +917,9 @@ nxxxxxx: fmr f15,f0 fmr f16,f0 fmr f17,f0 - fsub f31,f31,f31 ; Get set to initialize the FPSCR fmr f18,f0 fmr f19,f0 fmr f20,f0 - mtfsf 0xff,f31 ; Clear all FPSCR exception eanbles fmr f21,f0 fmr f22,f0 fmr f23,f0 @@ -1133,46 +931,93 @@ nxxxxxx: fmr f29,f0 fmr f30,f0 fmr f31,f0 - b fsenablexx ; Finish setting it all up... + b fsenable ; Finish setting it all up... + ; -; Finds an unused floating point area in the activation pointed -; to by R12s saved contexts. If none are found (unlikely but possible) -; and R3 is 0, a new area is allocated. If R3 is non-zero, it contains -; a pointer to an floating point savearea that is free. +; We get here when we are switching to the same context at the same level and the context +; is still live. Essentially, all we are doing is turning on the faility. It may have +; gotten turned off due to doing a context save for the current level or a context switch +; back to the live guy. ; -fpsrchsave: - lwz r6,ACT_MACT_PCB(r12) ; Get the first "normal" savearea + + .align 5 -fpsrnorm: mr. r5,r6 ; Is there another? - beq- fpsrvect ; No, search the vector saveareas... - lwz r7,SAVflags(r5) ; Get the flags for this guy - lwz r6,SAVprev(r5) ; Get the previous savearea, just in case - andis. r8,r7,hi16(SAVfpuvalid) ; Have we found an empty FPU save in normal? - beq+ fpsrgot ; We found one... - b fpsrnorm ; Search again... +fsthesame: -fpsrvect: lwz r6,ACT_MACT_VMX(r12) ; Get the first "vector" savearea +#if FPVECDBG + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x7F0A ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + beq- cr1,fsenable ; Not saved yet, nothing to pop, go enable and exit... -fpsrvectx: mr. r5,r6 ; Is there another? - beq- fpsrget ; No, try to allocate one... - lwz r7,SAVflags(r5) ; Get the flags for this guy - lwz r6,SAVprevec(r5) ; Get the previous savearea, just in case - andis. r8,r7,hi16(SAVfpuvalid) ; Have we found an empty FPU save in vector? - bne- fpsrvectx ; Search again... + lwz r11,SAVlevel(r30) ; Get the level of top saved context + lwz r14,SAVprev(r30) ; Get the previous savearea -fpsrgot: mr r3,r5 ; Get the savearea into the right register - blr ; Return... + cmplw r11,r31 ; Are live and saved the same? -fpsrget: mr. r5,r3 ; Do we allocate or use existing? - beq+ fpsrallo ; Allocate one... + bne+ fsenable ; Level not the same, nothing to pop, go enable and exit... - lwz r7,SAVflags(r3) ; Get the passed in area flags - blr ; Return... -; -; NOTE: save_get will return directly and set R7 to 0... + mr r3,r30 ; Get the old savearea (we popped it before) + bl EXT(save_ret) ; Toss it + b fsenable ; Go enable and exit... + + +; +; This function invalidates any live floating point context for the passed in facility_context. +; This is intended to be called just before act_machine_sv_free tosses saveareas. +; + + .align 5 + .globl EXT(toss_live_fpu) + +LEXT(toss_live_fpu) + + + mfmsr r9 ; Get the MSR + rlwinm r0,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interuptions + rlwinm. r8,r9,0,MSR_FP_BIT,MSR_FP_BIT ; Are floats on right now? + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Make sure vectors are turned off + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Make sure floats are turned off + mtmsr r0 ; No interruptions + isync + beq+ tlfnotours ; Floats off, can not be live here... + + mfsprg r8,0 ; Get the per proc + +; +; Note that at this point, since floats are on, we are the owner +; of live state on this processor ; -fpsrallo: b EXT(save_get) ; Get a fresh savearea + + lwz r6,FPUowner(r8) ; Get the thread that owns the floats + li r0,0 ; Clear this just in case we need it + cmplw r6,r3 ; Are we tossing our own context? + bne- tlfnotours ; Nope... + + fsub f1,f1,f1 ; Make a 0 + mtfsf 0xFF,f1 ; Clear it + +tlfnotours: lwz r11,FPUcpu(r3) ; Get the cpu on which we last loaded context + lis r12,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r11,r11,ppSize ; Find offset to the owner per_proc + ori r12,r12,lo16(EXT(per_proc_info)) ; Set base per_proc + li r10,FPUowner ; Displacement to float owner + add r11,r12,r11 ; Point to the owner per_proc + li r0,0 ; Set a 0 to invalidate context + +tlfinvothr: lwarx r12,r10,r11 ; Get the owner + cmplw r12,r3 ; Does he still have this context? + bne+ tlfexit ; Nope, leave... + stwcx. r0,r10,r11 ; Try to invalidate it + bne- tlfinvothr ; Try again if there was a collision... + +tlfexit: mtmsr r9 ; Restore interruptions + isync ; Could be turning off floats here + blr ; Leave... + /* * Altivec stuff is here. The techniques used are pretty identical to @@ -1188,89 +1033,118 @@ fpsrallo: b EXT(save_get) ; Get a fresh savearea * don't want to load any registers we don't have a copy of, we want to set them * to zero instead. * + * Note that there are some oddities here when we save a context we are using. + * It is really not too cool to do this, but what the hey... Anyway, + * we turn vectors and fpu off before we leave. + * The oddity is that if you use vectors after this, the + * savearea containing the context just saved will go away. So, bottom line is + * that don't use vectors until after you are done with the saved context. + * */ -ENTRY(vec_save, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(vec_save) + +LEXT(vec_save) - mfmsr r0 ; Get the MSR - rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Turn off vector forever + mfmsr r0 ; Get the MSR + rlwinm r0,r0,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Make sure vectors are turned off when we leave rlwinm r2,r0,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; But do interrupts only for now - oris r2,r2,hi16(MASK(MSR_VEC)) ; Enable the vector facility for now also - mtmsr r2 ; Set the MSR + oris r2,r2,hi16(MASK(MSR_VEC)) ; Enable the vector facility for now also + rlwinm r0,r0,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Force off fp + mtmsr r2 ; Set the MSR isync - mfsprg r6,0 ; Get the per_processor block - lwz r12,PP_VMX_THREAD(r6) ; Get the thread that owns the vector + mfsprg r6,0 ; Get the per_processor block + lwz r12,VMXowner(r6) ; Get the context ID for owner + #if FPVECDBG - mr r7,r0 ; (TEST/DEBUG) - li r4,0 ; (TEST/DEBUG) - mr r10,r3 ; (TEST/DEBUG) - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - mr. r3,r12 ; (TEST/DEBUG) - li r2,0x5F00 ; (TEST/DEBUG) - li r5,0 ; (TEST/DEBUG) - beq- noowneryeu ; (TEST/DEBUG) - lwz r4,ACT_MACT_VMXlvl(r12) ; (TEST/DEBUG) - lwz r5,ACT_MACT_VMX(r12) ; (TEST/DEBUG) - -noowneryeu: oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) - mr r0,r7 ; (TEST/DEBUG) - mr r3,r10 ; (TEST/DEBUG) + mr r7,r0 ; (TEST/DEBUG) + li r4,0 ; (TEST/DEBUG) + mr r10,r3 ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + mr. r3,r12 ; (TEST/DEBUG) + li r2,0x5F00 ; (TEST/DEBUG) + li r5,0 ; (TEST/DEBUG) + beq- noowneryeu ; (TEST/DEBUG) + lwz r4,VMXlevel(r12) ; (TEST/DEBUG) + lwz r5,VMXsave(r12) ; (TEST/DEBUG) + +noowneryeu: oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) + mr r0,r7 ; (TEST/DEBUG) + mr r3,r10 ; (TEST/DEBUG) #endif - mflr r2 ; Save the return address - lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number + mflr r2 ; Save the return address + +vsretry: mr. r12,r12 ; Anyone own the vector? + lhz r11,PP_CPU_NUMBER(r6) ; Get our CPU number + beq- vsret ; Nobody owns the vector, no save required... + + cmplw cr1,r3,r12 ; Is the specified context live? + + isync ; Force owner check first + + lwz r9,VMXcpu(r12) ; Get the cpu that context was last on + bne- cr1,vsret ; Specified context is not live + + cmplw cr1,r9,r11 ; Was the context for this processor? + beq+ cr1,vsgoodcpu ; Facility last used on this processor... + + b vsret ; Someone else claimed this... + + .align 5 + +vsgoodcpu: lwz r3,VMXsave(r12) ; Get the current vector savearea for the thread + lwz r10,liveVRS(r6) ; Get the right VRSave register + lwz r9,VMXlevel(r12) ; Get our current level indicator + + + cmplwi cr1,r3,0 ; Have we ever saved this facility context? + beq- cr1,vsneedone ; Never saved it, so we need an area... + + lwz r8,SAVlevel(r3) ; Get the level this savearea is for + mr. r10,r10 ; Is VRsave set to 0? + cmplw cr1,r9,r8 ; Correct level? + bne- cr1,vsneedone ; Different level, so we need to save... - mr. r12,r12 ; Anyone own the vector? - cmplw cr1,r3,r12 ; Is the specified thread the owner? + bne+ vsret ; VRsave is non-zero so we need to keep what is saved... - beq- vsretnr ; Nobody owns the vector, no save required... - - li r4,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word - bne- cr1,vsretnr ; Facility belongs to some other activation... - -vsvSpin2: lwarx r9,r4,r12 ; Get and reserve the last used CPU - mr. r9,r9 ; Is it changing now? - oris r3,r9,hi16(fvChk) ; Set the "changing" flag - blt- vsvSpin2 ; Spin if changing - stwcx. r3,r4,r12 ; Lock it up - bne- vsvSpin2 ; Someone is messing right now - - isync ; Make sure we see everything - - cmplw cr1,r9,r11 ; Was the context for this processor? - li r3,0 ; Assume we need a fix-me-up - beq- cr1,vsgoodcpu ; Facility last used on this processor... - stw r3,PP_VMX_THREAD(r6) ; Clear owner because it was really on the other processor - b vsret ; Bail now with no save... - -vsgoodcpu: lwz r3,ACT_MACT_VMX(r12) ; Get the current vector savearea for the thread - lwz r9,ACT_MACT_VMXlvl(r12) ; Get our current level indicator - - cmplwi cr1,r3,0 ; Have we ever saved this facility context? - beq- cr1,vsneedone ; Never saved it, so we need an area... - - lwz r8,SAVlvlvec(r3) ; Get the level this savearea is for - cmplwi r8,1 ; See if this is a spare - cmplw cr1,r9,r8 ; Correct level? - beq+ vsusespare ; It is still live... - beq- cr1,vsret ; The current level is already saved, bail out... - -vsneedone: li r3,0 ; Tell the routine to allocate an area if none found - bl vsrchsave ; Find a free savearea - - mfsprg r6,0 ; Get back per_processor block - oris r7,r7,hi16(SAVvmxvalid) ; Set the allocated bit - lwz r12,PP_VMX_THREAD(r6) ; Get back our thread - mtlr r2 ; Restore return - lwz r8,ACT_MACT_VMX(r12) ; Get the current top vector savearea - lwz r9,ACT_MACT_VMXlvl(r12) ; Get our current level indicator again - stw r3,ACT_MACT_VMX(r12) ; Set this as the latest vector savearea for the thread - stw r8,SAVprevec(r3) ; And then chain this in front - stw r7,SAVflags(r3) ; Set the allocation flags - stw r12,SAVact(r3) ; Make sure we point to the right guy - -vsusespare: stw r9,SAVlvlvec(r3) ; And set the level this savearea is for + lwz r4,SAVprev(r3) ; Pick up the previous area + lwz r5,SAVlevel(r4) ; Get the level associated with save + stw r4,VMXsave(r12) ; Dequeue this savearea + stw r5,VMXlevel(r12) ; Save the level + + li r3,0 ; Clear + stw r3,VMXowner(r12) ; Show no live context here + eieio + +vsbackout: mr r12,r0 ; Set the saved MSR + b EXT(save_ret_join) ; Toss the savearea and return from there... + + .align 5 + +vsneedone: mr. r10,r10 ; Is VRsave set to 0? + beq- vsret ; Yeah, they do not care about any of them... + + bl EXT(save_get) ; Get a savearea for the context + + mfsprg r6,0 ; Get back per_processor block + li r4,SAVvector ; Get vector tag + lwz r12,VMXowner(r6) ; Get back our context ID + stb r4,SAVflags+2(r3) ; Mark this savearea as a vector + mr. r12,r12 ; See if we were disowned while away. Very, very small chance of it... + beq- vsbackout ; If disowned, just toss savearea... + lwz r4,facAct(r12) ; Get the activation associated with live context + mtlr r2 ; Restore return + lwz r8,VMXsave(r12) ; Get the current top vector savearea + stw r4,SAVact(r3) ; Indicate the right activation for this context + lwz r9,VMXlevel(r12) ; Get our current level indicator again + stw r3,VMXsave(r12) ; Set this as the most current floating point context + stw r8,SAVprev(r3) ; And then chain this in front + + stw r9,SAVlevel(r3) ; Set level in savearea + mfcr r2 ; Save non-volatile CRs lwz r10,liveVRS(r6) ; Get the right VRSave register lis r9,0x5555 ; Mask with odd bits set @@ -1282,11 +1156,9 @@ vsusespare: stw r9,SAVlvlvec(r3) ; And set the level this savearea is for la r6,savevr0(r3) ; Point to line 0 rlwinm r4,r11,15,0,15 ; Move line 8-15 flags to high order odd bits - la r9,savevrvalid(r3) ; Point to the saved register mask field or r4,r11,r4 ; Set the odd bits ; (bit 0 is line 0, bit 1 is line 8, ; bit 2 is line 1, bit 3 is line 9, etc. - dcba br0,r9 ; Allocate the cache for it rlwimi r4,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 la r7,savevr2(r3) ; Point to line 1 mtcrf 255,r4 ; Load up the CRs @@ -1533,37 +1405,17 @@ snovr28: stvxl v29,r11,r8 ; Save VR29 snovr29: - mfvscr v27 ; Get the VSCR - la r8,savevscr(r3) ; Point to the VSCR save area bf 30,snovr30 ; Do not save VR30... stvxl v30,br0,r7 ; Save VR30 snovr30: - dcba br0,r8 ; Allocate VSCR savearea bf 31,snovr31 ; Do not save VR31... stvxl v31,r11,r7 ; Save VR31 snovr31: - add r11,r11,r9 ; Point to V27s saved value - stvxl v27,br0,r8 ; Save the VSCR - bt 27,v27ok ; V27 has been saved and is marked as wanted - - lis r11,hi16(EXT(QNaNbarbarian)) ; V27 is not wanted, so get empty value - ori r11,r11,lo16(EXT(QNaNbarbarian)) - -v27ok: mtcrf 255,r2 ; Restore all non-volatile CRs - lvxl v27,br0,r11 ; Restore or load empty value into V27 because we used it + mtcrf 255,r2 ; Restore all cr -; -; Save the current vector state into the savearea of the thread that owns it. -; - -vsret: lwz r4,ACT_MACT_VMXcpu(r12) ; Get back the owner CPU - rlwinm r4,r4,0,fvChkb+1,31 ; Clear lock - sync - stw r4,ACT_MACT_VMXcpu(r12) ; Unlock the context - -vsretnr: mtmsr r0 ; Put interrupts on if they were and vector off +vsret: mtmsr r0 ; Put interrupts on if they were and vector off isync blr @@ -1586,1162 +1438,1082 @@ vsretnr: mtmsr r0 ; Put interrupts on if they were and vector off * */ -ENTRY(vec_switch, TAG_NO_FRAME_USED) + .align 5 + .globl EXT(vec_switch) + +LEXT(vec_switch) #if DEBUG -#if GDDBG - mr r7,r4 ; Save input parameter - lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter - ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter - lwz r1,0(r3) - lis r5,hi16(EXT(GratefulDeb)) ; Point to top of display - ori r5,r5,lo16(EXT(GratefulDeb)) ; Put in bottom part - addi r1,r1,1 - mtlr r5 ; Set link register - stw r1,0(r3) - mr r4,r1 - lis r3,1 - blrl ; Display count - mr r4,r7 ; Restore the parameter -#else lis r3,hi16(EXT(vec_trap_count)) ; Get address of vector trap counter ori r3,r3,lo16(EXT(vec_trap_count)) ; Get address of vector trap counter lwz r1,0(r3) addi r1,r1,1 stw r1,0(r3) -#endif #endif /* DEBUG */ - mfsprg r6,0 /* Get the per_processor block */ - mfmsr r19 /* Get the current MSR */ + mfsprg r26,0 ; Get the per_processor block + mfmsr r19 ; Get the current MSR - lwz r10,PP_CPU_DATA(r6) /* Get the CPU data pointer */ - lwz r12,PP_VMX_THREAD(r6) /* Get the thread that owns the vector */ - lwz r10,CPU_ACTIVE_THREAD(r10) /* Get the pointer to the active thread */ - oris r19,r19,hi16(MASK(MSR_VEC)) /* Enable the vector feature */ - lwz r17,THREAD_TOP_ACT(r10) /* Now get the activation that is running */ - -; R12 has the "old" activation -; R17 has the "new" activation - -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F01 ; (TEST/DEBUG) - mr r3,r12 ; (TEST/DEBUG) - mr r5,r17 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r18,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r18 ; Restore it - mfsprg r6,0 ; Get the per_processor block back -#endif -#endif - mr. r12,r12 ; See if there is any live vector status - - lhz r18,PP_CPU_NUMBER(r6) ; Get our CPU number - - mtmsr r19 /* Set vector available */ + mr r25,r4 ; Save the entry savearea + lwz r22,VMXowner(r26) ; Get the thread that owns the vector + lwz r10,PP_ACTIVE_THREAD(r26) ; Get the pointer to the active thread + oris r19,r19,hi16(MASK(MSR_VEC)) ; Enable the vector feature + lwz r17,THREAD_TOP_ACT(r10) ; Now get the activation that is running + + mtmsr r19 ; Enable vector instructions isync - beq- vsnosave ; No live context, so nothing to save... - - li r20,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word - -vsSpin1: lwarx r19,r20,r12 ; Get and reserve the last used CPU - mr. r19,r19 ; Is it changing now? - oris r21,r19,hi16(fvChk) ; Set the "changing" flag - blt- vsSpin1 ; Spin if changing - stwcx. r21,r20,r12 ; Lock it up - bne- vsSpin1 ; Someone is messing right now + lwz r27,ACT_MACT_PCB(r17) ; Get the current level + lwz r29,curctx(r17) ; Grab the current context anchor of the current thread - isync ; Make sure we see everything +; R22 has the "old" context anchor +; R29 has the "new" context anchor - lwz r15,ACT_MACT_PCB(r12) ; Get the current level of the "old" one - cmplw r18,r19 ; Check the CPU that the old context is live on - lwz r14,ACT_MACT_VMX(r12) ; Point to the top of the old context stack - bne- vsnosaverel ; Context is not live if used on a different CPU... - lwz r13,ACT_MACT_VMXlvl(r12) ; Get the "old" active level - -; -; First, check to see if all we are doing is enabling because the -; "new" context is live. -; #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F02 ; (TEST/DEBUG) - mr r1,r15 ; (TEST/DEBUG) - mr r3,r13 ; (TEST/DEBUG) - mr r5,r14 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it -#endif + lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) + li r2,0x5F01 ; (TEST/DEBUG) + mr r3,r22 ; (TEST/DEBUG) + mr r5,r29 ; (TEST/DEBUG) + oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - cmplw cr1,r12,r17 ; Is the "old" activation and the "new" the same? - cmplwi cr2,r14,0 ; Is there any saved context on the "old" activation? - bne+ cr1,vsmstsave ; The activations are different so "old" context must be saved... - -; -; Here we know that both the "old" and "new" activations are the same. We will -; check the current level and active levels. If they are the same, the context is -; already live, so all we do is turn on the facility and invalidate the top -; savearea. -; -; If the current level, the active level, and the top savearea level are the -; same, then the context was saved as part of a thread context switch and neither -; needs saving or restoration. -; -; In all other cases, the context must be saved unless we are just re-enabling -; vector. -; - - cmplw r13,r15 ; Are the levels the same? - cmplwi cr2,r14,0 ; Is there any saved context? - bne- vsmstsave ; Levels are different, we need to save... + lhz r16,PP_CPU_NUMBER(r26) ; Get the current CPU number - beq- cr2,vrenableret ; No saved context at all, enable and go... +vsvretry: mr. r22,r22 ; See if there is any live vector status - lwz r20,SAVlvlvec(r14) ; Get the level of the top savearea + beq- vsnosave ; No live context, so nothing to save... -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F03 ; (TEST/DEBUG) - mr r3,r15 ; (TEST/DEBUG) - mr r5,r20 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it -#endif -#endif - cmplw r15,r20 ; Is the top level the same as the current? - li r0,1 ; Get the invalid flag - bne- vrenableret ; Not the same, just enable and go... - - stw r0,SAVlvlvec(r14) ; Invalidate that top savearea + isync ; Make sure we see this in the right order -vrenableret: - sync ; Make sure everything is saved - stw r19,ACT_MACT_VMXcpu(r12) ; Say we are not using the context anymore - b vrenable ; Then enable and go... + lwz r30,VMXsave(r22) ; Get the top savearea + cmplw cr2,r22,r29 ; Are both old and new the same context? + lwz r18,VMXcpu(r22) ; Get the last CPU we ran on + cmplwi cr1,r30,0 ; Anything saved yet? + cmplw r18,r16 ; Make sure we are on the right processor + lwz r31,VMXlevel(r22) ; Get the context level + lwz r10,liveVRS(r26) ; Get the right VRSave register + + bne- vsnosave ; No, not on the same processor... + ; -; We need to save the "old" context here. The LIFO queueing scheme works -; out for all cases because if both the "new" and "old" activations are the -; same, there can not be any saved state to load. the "new" level is -; truely new. +; Check to see if the live context has already been saved. +; Also check to see if all we are here just to re-enable the MSR +; and handle specially if so. ; -; When we save the context, we either use a new savearea, or the free -; one that is cached at the head of the list. + + cmplw r31,r27 ; See if the current and active levels are the same + crand cr0_eq,cr2_eq,cr0_eq ; Remember if both the levels and contexts are the same + li r8,0 ; Clear this -vsmstsave: beq- cr2,vsgetsave ; There is no possible cached save area + beq- vsthesame ; New and old are the same, just go enable... + + cmplwi cr2,r10,0 ; Check VRSave to see if we really need to save anything... + beq- cr1,vsmstsave ; Not saved yet, go do it... - lwz r5,SAVlvlvec(r14) ; Get the level of first facility savearea -#if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F04 ; (TEST/DEBUG) - mr r3,r15 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - mr r7,r5 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it - mr r5,r7 ; Restore it -#endif -#endif - mr r3,r14 ; Assume we are invalid - cmplwi r5,1 ; Is it invalid? - cmplw cr1,r5,r13 ; Is the SA level the active one? - beq+ vsusecache ; Invalid, just use it... - beq- cr1,vsnosaverel ; The SA level is active, it is already saved... + lwz r11,SAVlevel(r30) ; Get the level of top saved context -vsgetsave: mr r3,r4 ; Use the interrupt save as the context savearea if none cached + cmplw r31,r11 ; Are live and saved the same? + #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F05 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it - mr r3,r8 ; This too -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F02 ; (TEST/DEBUG) + mr r3,r30 ; (TEST/DEBUG) + mr r5,r31 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + + bne- vsmstsave ; Live context has not been saved yet... + + bne- cr2,vsnosave ; Live context saved and VRSave not 0, no save and keep context... - bl vsrchsave ; Find a free savearea + lwz r4,SAVprev(r30) ; Pick up the previous area + li r5,0 ; Assume this is the only one (which should be the ususal case) + mr. r4,r4 ; Was this the only one? + stw r4,VMXsave(r22) ; Dequeue this savearea + beq+ vsonlyone ; This was the only one... + lwz r5,SAVlevel(r4) ; Get the level associated with previous save + +vsonlyone: stw r5,VMXlevel(r22) ; Save the level + stw r8,VMXowner(r26) ; Clear owner + eieio + mr r3,r30 ; Copy the savearea we are tossing + bl EXT(save_ret) ; Toss the savearea + b vsnosave ; Go load up the context... + + .align 5 - stw r3,ACT_MACT_VMX(r12) ; Set this as the latest context savearea for the thread - mfsprg r6,0 ; Get back per_processor block - stw r14,SAVprevec(r3) ; And then chain this in front - oris r7,r7,hi16(SAVvmxvalid) ; Set the allocated bit - stw r12,SAVact(r3) ; Make sure we point to the right guy - stw r7,SAVflags(r3) ; Set the allocation flags + +vsmstsave: stw r8,VMXowner(r26) ; Clear owner + eieio + beq- cr2,vsnosave ; The VRSave was 0, so there is nothing to save... + + bl EXT(save_get) ; Go get a savearea + + lwz r12,facAct(r22) ; Get the activation associated with the context + stw r3,VMXsave(r22) ; Set this as the latest context savearea for the thread + + stw r30,SAVprev(r3) ; Point us to the old context + stw r31,SAVlevel(r3) ; Tag our level + li r7,SAVvector ; Get the vector ID + stw r12,SAVact(r3) ; Make sure we point to the right guy + stb r7,SAVflags+2(r3) ; Set that we have a vector save area -vsusecache: la r11,savevr0(r3) ; Point to the 1st line in area - stw r13,SAVlvlvec(r3) ; Set this context level #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F06 ; (TEST/DEBUG) - mr r5,r13 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - mr r10,r3 - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it - mr r3,r10 - mfsprg r6,0 ; Get back per_processor block -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F03 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif -vsgotsave: - lwz r10,liveVRS(r6) ; Get the right VRSave register - lis r9,0x5555 ; Mask with odd bits set - rlwinm r11,r10,1,0,31 ; Shift over 1 - ori r9,r9,0x5555 ; Finish mask - or r21,r10,r11 ; After this, even bits show which lines to zap - - stw r13,SAVlvlvec(r3) ; Set the savearea level - andc r13,r21,r9 ; Clear out odd bits - - la r20,savevr0(r3) ; Point to line 0 - rlwinm r24,r13,15,0,15 ; Move line 8-15 flags to high order odd bits - la r23,savevrvalid(r3) ; Point to the saved register mask field - or r24,r13,r24 ; Set the odd bits - ; (bit 0 is line 0, bit 1 is line 8, - ; bit 2 is line 1, bit 3 is line 9, etc. - dcba br0,r23 ; Allocate the cache for it - rlwimi r24,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 - la r21,savevr2(r3) ; Point to line 1 - mtcrf 255,r24 ; Load up the CRs - stw r10,savevrvalid(r3) ; Save the validity information - mr r22,r20 ; Start registers off + lwz r10,liveVRS(r26) ; Get the right VRSave register + lis r9,0x5555 ; Mask with odd bits set + rlwinm r11,r10,1,0,31 ; Shift over 1 + ori r9,r9,0x5555 ; Finish mask + or r21,r10,r11 ; After this, even bits show which lines to zap + + andc r13,r21,r9 ; Clear out odd bits + + la r11,savevr0(r3) ; Point to line 0 + rlwinm r24,r13,15,0,15 ; Move line 8-15 flags to high order odd bits + or r24,r13,r24 ; Set the odd bits + ; (bit 0 is line 0, bit 1 is line 8, + ; bit 2 is line 1, bit 3 is line 9, etc. + rlwimi r24,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 + la r21,savevr2(r3) ; Point to line 1 + mtcrf 255,r24 ; Load up the CRs + stw r10,savevrvalid(r3) ; Save the validity information + mr r12,r11 ; Start registers off ; ; Save the current vector state ; - bf 0,nol0 ; No line 0 to do... - dcba br0,r20 ; Allocate cache line 0 + bf 0,nol0 ; No line 0 to do... + dcba br0,r11 ; Allocate cache line 0 nol0: - la r20,savevr4(r3) ; Point to line 2 - bf 2,nol1 ; No line 1 to do... - dcba br0,r21 ; Allocate cache line 1 + la r11,savevr4(r3) ; Point to line 2 + bf 2,nol1 ; No line 1 to do... + dcba br0,r21 ; Allocate cache line 1 nol1: - la r21,savevr6(r3) ; Point to line 3 - bf 4,nol2 ; No line 2 to do... - dcba br0,r20 ; Allocate cache line 2 + la r21,savevr6(r3) ; Point to line 3 + bf 4,nol2 ; No line 2 to do... + dcba br0,r11 ; Allocate cache line 2 nol2: - li r30,16 ; Get offset for odd registers - bf 16,novr0 ; Do not save VR0... - stvxl v0,br0,r22 ; Save VR0 + li r14,16 ; Get offset for odd registers + bf 16,novr0 ; Do not save VR0... + stvxl v0,br0,r12 ; Save VR0 novr0: - la r23,savevr2(r3) ; Point to V2/V3 pair - bf 17,novr1 ; Do not save VR1... - stvxl v1,r30,r22 ; Save VR1 + la r13,savevr2(r3) ; Point to V2/V3 pair + bf 17,novr1 ; Do not save VR1... + stvxl v1,r14,r12 ; Save VR1 novr1: - la r20,savevr8(r3) ; Point to line 4 - bf 6,nol3 ; No line 3 to do... - dcba br0,r21 ; Allocate cache line 3 + la r11,savevr8(r3) ; Point to line 4 + bf 6,nol3 ; No line 3 to do... + dcba br0,r21 ; Allocate cache line 3 nol3: - la r22,savevr4(r3) ; Point to V4/V5 pair - bf 18,novr2 ; Do not save VR2... - stvxl v2,br0,r23 ; Save VR2 + la r12,savevr4(r3) ; Point to V4/V5 pair + bf 18,novr2 ; Do not save VR2... + stvxl v2,br0,r13 ; Save VR2 novr2: - bf 19,novr3 ; Do not save VR3... - stvxl v3,r30,r23 ; Save VR3 + bf 19,novr3 ; Do not save VR3... + stvxl v3,r14,r13 ; Save VR3 novr3: ; ; Note: CR4 is now free ; - la r21,savevr10(r3) ; Point to line 5 - bf 8,nol4 ; No line 4 to do... - dcba br0,r20 ; Allocate cache line 4 + la r21,savevr10(r3) ; Point to line 5 + bf 8,nol4 ; No line 4 to do... + dcba br0,r11 ; Allocate cache line 4 nol4: - la r23,savevr6(r3) ; Point to R6/R7 pair - bf 20,novr4 ; Do not save VR4... - stvxl v4,br0,r22 ; Save VR4 + la r13,savevr6(r3) ; Point to R6/R7 pair + bf 20,novr4 ; Do not save VR4... + stvxl v4,br0,r12 ; Save VR4 novr4: - bf 21,novr5 ; Do not save VR5... - stvxl v5,r30,r22 ; Save VR5 + bf 21,novr5 ; Do not save VR5... + stvxl v5,r14,r12 ; Save VR5 novr5: - mtcrf 0x08,r10 ; Set CRs for registers 16-19 - la r20,savevr12(r3) ; Point to line 6 - bf 10,nol5 ; No line 5 to do... - dcba br0,r21 ; Allocate cache line 5 + mtcrf 0x08,r10 ; Set CRs for registers 16-19 + la r11,savevr12(r3) ; Point to line 6 + bf 10,nol5 ; No line 5 to do... + dcba br0,r21 ; Allocate cache line 5 nol5: - la r22,savevr8(r3) ; Point to V8/V9 pair - bf 22,novr6 ; Do not save VR6... - stvxl v6,br0,r23 ; Save VR6 + la r12,savevr8(r3) ; Point to V8/V9 pair + bf 22,novr6 ; Do not save VR6... + stvxl v6,br0,r13 ; Save VR6 novr6: - bf 23,novr7 ; Do not save VR7... - stvxl v7,r30,r23 ; Save VR7 + bf 23,novr7 ; Do not save VR7... + stvxl v7,r14,r13 ; Save VR7 novr7: ; ; Note: CR5 is now free ; - la r21,savevr14(r3) ; Point to line 7 - bf 12,nol6 ; No line 6 to do... - dcba br0,r20 ; Allocate cache line 6 + la r21,savevr14(r3) ; Point to line 7 + bf 12,nol6 ; No line 6 to do... + dcba br0,r11 ; Allocate cache line 6 nol6: - la r23,savevr10(r3) ; Point to V10/V11 pair - bf 24,novr8 ; Do not save VR8... - stvxl v8,br0,r22 ; Save VR8 + la r13,savevr10(r3) ; Point to V10/V11 pair + bf 24,novr8 ; Do not save VR8... + stvxl v8,br0,r12 ; Save VR8 novr8: - bf 25,novr9 ; Do not save VR9... - stvxl v9,r30,r22 ; Save VR9 + bf 25,novr9 ; Do not save VR9... + stvxl v9,r14,r12 ; Save VR9 novr9: - mtcrf 0x04,r10 ; Set CRs for registers 20-23 - la r20,savevr16(r3) ; Point to line 8 - bf 14,nol7 ; No line 7 to do... - dcba br0,r21 ; Allocate cache line 7 + mtcrf 0x04,r10 ; Set CRs for registers 20-23 + la r11,savevr16(r3) ; Point to line 8 + bf 14,nol7 ; No line 7 to do... + dcba br0,r21 ; Allocate cache line 7 nol7: - la r22,savevr12(r3) ; Point to V12/V13 pair - bf 26,novr10 ; Do not save VR10... - stvxl v10,br0,r23 ; Save VR10 + la r12,savevr12(r3) ; Point to V12/V13 pair + bf 26,novr10 ; Do not save VR10... + stvxl v10,br0,r13 ; Save VR10 novr10: - bf 27,novr11 ; Do not save VR11... - stvxl v11,r30,r23 ; Save VR11 + bf 27,novr11 ; Do not save VR11... + stvxl v11,r14,r13 ; Save VR11 novr11: ; ; Note: CR6 is now free ; - la r21,savevr18(r3) ; Point to line 9 - bf 1,nol8 ; No line 8 to do... - dcba br0,r20 ; Allocate cache line 8 + la r21,savevr18(r3) ; Point to line 9 + bf 1,nol8 ; No line 8 to do... + dcba br0,r11 ; Allocate cache line 8 nol8: - la r23,savevr14(r3) ; Point to V14/V15 pair - bf 28,novr12 ; Do not save VR12... - stvxl v12,br0,r22 ; Save VR12 + la r13,savevr14(r3) ; Point to V14/V15 pair + bf 28,novr12 ; Do not save VR12... + stvxl v12,br0,r12 ; Save VR12 novr12: - bf 29,novr13 ; Do not save VR13... - stvxl v13,r30,r22 ; Save VR13 + bf 29,novr13 ; Do not save VR13... + stvxl v13,r14,r12 ; Save VR13 novr13: - mtcrf 0x02,r10 ; Set CRs for registers 24-27 - la r20,savevr20(r3) ; Point to line 10 - bf 3,nol9 ; No line 9 to do... - dcba br0,r21 ; Allocate cache line 9 + mtcrf 0x02,r10 ; Set CRs for registers 24-27 + la r11,savevr20(r3) ; Point to line 10 + bf 3,nol9 ; No line 9 to do... + dcba br0,r21 ; Allocate cache line 9 nol9: - la r22,savevr16(r3) ; Point to V16/V17 pair - bf 30,novr14 ; Do not save VR14... - stvxl v14,br0,r23 ; Save VR14 + la r12,savevr16(r3) ; Point to V16/V17 pair + bf 30,novr14 ; Do not save VR14... + stvxl v14,br0,r13 ; Save VR14 novr14: - bf 31,novr15 ; Do not save VR15... - stvxl v15,r30,r23 ; Save VR15 + bf 31,novr15 ; Do not save VR15... + stvxl v15,r14,r13 ; Save VR15 novr15: ; ; Note: CR7 is now free ; - la r21,savevr22(r3) ; Point to line 11 - bf 5,nol10 ; No line 10 to do... - dcba br0,r20 ; Allocate cache line 10 + la r21,savevr22(r3) ; Point to line 11 + bf 5,nol10 ; No line 10 to do... + dcba br0,r11 ; Allocate cache line 10 nol10: - la r23,savevr18(r3) ; Point to V18/V19 pair - bf 16,novr16 ; Do not save VR16... - stvxl v16,br0,r22 ; Save VR16 + la r13,savevr18(r3) ; Point to V18/V19 pair + bf 16,novr16 ; Do not save VR16... + stvxl v16,br0,r12 ; Save VR16 novr16: - bf 17,novr17 ; Do not save VR17... - stvxl v17,r30,r22 ; Save VR17 + bf 17,novr17 ; Do not save VR17... + stvxl v17,r14,r12 ; Save VR17 novr17: - mtcrf 0x01,r10 ; Set CRs for registers 28-31 + mtcrf 0x01,r10 ; Set CRs for registers 28-31 ; ; Note: All registers have been or are accounted for in CRs ; - la r20,savevr24(r3) ; Point to line 12 - bf 7,nol11 ; No line 11 to do... - dcba br0,r21 ; Allocate cache line 11 + la r11,savevr24(r3) ; Point to line 12 + bf 7,nol11 ; No line 11 to do... + dcba br0,r21 ; Allocate cache line 11 nol11: - la r22,savevr20(r3) ; Point to V20/V21 pair - bf 18,novr18 ; Do not save VR18... - stvxl v18,br0,r23 ; Save VR18 + la r12,savevr20(r3) ; Point to V20/V21 pair + bf 18,novr18 ; Do not save VR18... + stvxl v18,br0,r13 ; Save VR18 novr18: - bf 19,novr19 ; Do not save VR19... - stvxl v19,r30,r23 ; Save VR19 + bf 19,novr19 ; Do not save VR19... + stvxl v19,r14,r13 ; Save VR19 novr19: - la r21,savevr26(r3) ; Point to line 13 - bf 9,nol12 ; No line 12 to do... - dcba br0,r20 ; Allocate cache line 12 + la r21,savevr26(r3) ; Point to line 13 + bf 9,nol12 ; No line 12 to do... + dcba br0,r11 ; Allocate cache line 12 nol12: - la r23,savevr22(r3) ; Point to V22/V23 pair - bf 20,novr20 ; Do not save VR20... - stvxl v20,br0,r22 ; Save VR20 + la r13,savevr22(r3) ; Point to V22/V23 pair + bf 20,novr20 ; Do not save VR20... + stvxl v20,br0,r12 ; Save VR20 novr20: - bf 21,novr21 ; Do not save VR21... - stvxl v21,r30,r22 ; Save VR21 + bf 21,novr21 ; Do not save VR21... + stvxl v21,r14,r12 ; Save VR21 novr21: - la r20,savevr28(r3) ; Point to line 14 - bf 11,nol13 ; No line 13 to do... - dcba br0,r21 ; Allocate cache line 13 + la r11,savevr28(r3) ; Point to line 14 + bf 11,nol13 ; No line 13 to do... + dcba br0,r21 ; Allocate cache line 13 nol13: - la r22,savevr24(r3) ; Point to V24/V25 pair - bf 22,novr22 ; Do not save VR22... - stvxl v22,br0,r23 ; Save VR22 + la r12,savevr24(r3) ; Point to V24/V25 pair + bf 22,novr22 ; Do not save VR22... + stvxl v22,br0,r13 ; Save VR22 novr22: - bf 23,novr23 ; Do not save VR23... - stvxl v23,r30,r23 ; Save VR23 + bf 23,novr23 ; Do not save VR23... + stvxl v23,r14,r13 ; Save VR23 novr23: - la r21,savevr30(r3) ; Point to line 15 - bf 13,nol14 ; No line 14 to do... - dcba br0,r20 ; Allocate cache line 14 + la r21,savevr30(r3) ; Point to line 15 + bf 13,nol14 ; No line 14 to do... + dcba br0,r11 ; Allocate cache line 14 nol14: - la r23,savevr26(r3) ; Point to V26/V27 pair - bf 24,novr24 ; Do not save VR24... - stvxl v24,br0,r22 ; Save VR24 + la r13,savevr26(r3) ; Point to V26/V27 pair + bf 24,novr24 ; Do not save VR24... + stvxl v24,br0,r12 ; Save VR24 novr24: - bf 25,novr25 ; Do not save VR25... - stvxl v25,r30,r22 ; Save VR25 + bf 25,novr25 ; Do not save VR25... + stvxl v25,r14,r12 ; Save VR25 novr25: - bf 15,nol15 ; No line 15 to do... - dcba br0,r21 ; Allocate cache line 15 + bf 15,nol15 ; No line 15 to do... + dcba br0,r21 ; Allocate cache line 15 nol15: ; ; Note: All cache lines allocated now ; - la r22,savevr28(r3) ; Point to V28/V29 pair - bf 26,novr26 ; Do not save VR26... - stvxl v26,br0,r23 ; Save VR26 + la r12,savevr28(r3) ; Point to V28/V29 pair + bf 26,novr26 ; Do not save VR26... + stvxl v26,br0,r13 ; Save VR26 novr26: - bf 27,novr27 ; Do not save VR27... - stvxl v27,r30,r23 ; Save VR27 + bf 27,novr27 ; Do not save VR27... + stvxl v27,r14,r13 ; Save VR27 novr27: - la r23,savevr30(r3) ; Point to V30/V31 pair - bf 28,novr28 ; Do not save VR28... - stvxl v28,br0,r22 ; Save VR28 + la r13,savevr30(r3) ; Point to V30/V31 pair + bf 28,novr28 ; Do not save VR28... + stvxl v28,br0,r12 ; Save VR28 novr28: - mfvscr v27 ; Get the VSCR - bf 29,novr29 ; Do not save VR29... - stvxl v29,r30,r22 ; Save VR29 + bf 29,novr29 ; Do not save VR29... + stvxl v29,r14,r12 ; Save VR29 novr29: - la r22,savevscr(r3) ; Point to the VSCR save area - bf 30,novr30 ; Do not save VR30... - stvxl v30,br0,r23 ; Save VR30 + bf 30,novr30 ; Do not save VR30... + stvxl v30,br0,r13 ; Save VR30 novr30: - dcba br0,r22 ; Allocate VSCR savearea - bf 31,novr31 ; Do not save VR31... - stvxl v31,r30,r23 ; Save VR31 + bf 31,novr31 ; Do not save VR31... + stvxl v31,r14,r13 ; Save VR31 novr31: - stvxl v27,br0,r22 ; Save the VSCR -/* - * Now check out the current thread and see if we need to load up his context. - * If we do (and this should be the normal case), do it and then release the - * savearea. - * - * If we don't (remember, we already took care of the case where we just enable - * the vector), we need to fill the registers with garbage, because this thread has - * never used them before and some thieving bastard could hack the old values - * of some thread! Just imagine what would happen if they could! Why, nothing - * would be safe! My Gosh! It's terrifying! - */ +; +; The context is all saved now and the facility is free. +; +; If we do not we need to fill the registers with junk, because this level has +; never used them before and some thieving bastard could hack the old values +; of some thread! Just imagine what would happen if they could! Why, nothing +; would be safe! My God! It is terrifying! +; +; Also, along the way, thanks to Ian Ollmann, we generate the 0x7FFFDEAD (QNaNbarbarian) +; constant that we may need to fill unused vector registers. +; -vsnosaverel: - sync ; Make sure everything is saved - stw r19,ACT_MACT_VMXcpu(r12) ; Say we are not using the context anymore -vsnosave: - li r20,ACT_MACT_VMXcpu ; Point to the CPU indication/lock word - -vsSpin2: lwarx r19,r20,r17 ; Get and reserve the last used CPU - mr. r19,r19 ; Is it changing now? - oris r21,r19,hi16(fvChk) ; Set the "changing" flag - blt- vsSpin2 ; Spin if changing - stwcx. r21,r20,r17 ; Lock it up - bne- vsSpin2 ; Someone is messing right now - isync ; Make sure we see everything - - lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one - lwz r14,ACT_MACT_VMX(r17) ; Point to the top of the "new" context stack - lwz r13,ACT_MACT_VMXlvl(r17) ; Get the "new" active level +vsnosave: vspltisb v31,-10 ; Get 0xF6F6F6F6 + lwz r15,ACT_MACT_PCB(r17) ; Get the current level of the "new" one + vspltisb v30,5 ; Get 0x05050505 + lwz r19,VMXcpu(r29) ; Get the last CPU we ran on + vspltish v29,4 ; Get 0x00040004 + lwz r14,VMXsave(r29) ; Point to the top of the "new" context stack + vrlb v31,v31,v30 ; Get 0xDEDEDEDE + + stw r16,VMXcpu(r29) ; Claim context for us + eieio #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F07 ; (TEST/DEBUG) - mr r1,r15 ; (TEST/DEBUG) - mr r3,r14 ; (TEST/DEBUG) - mr r5,r13 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) + lwz r13,VMXlevel(r29) ; (TEST/DEBUG) + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F04 ; (TEST/DEBUG) + mr r1,r15 ; (TEST/DEBUG) + mr r3,r14 ; (TEST/DEBUG) + mr r5,r13 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif + + lis r18,hi16(EXT(per_proc_info)) ; Set base per_proc + vspltisb v28,-2 ; Get 0xFEFEFEFE + mulli r19,r19,ppSize ; Find offset to the owner per_proc + vsubuhm v31,v31,v29 ; Get 0xDEDADEDA + ori r18,r18,lo16(EXT(per_proc_info)) ; Set base per_proc + vpkpx v30,v28,v3 ; Get 0x7FFF7FFF + li r16,VMXowner ; Displacement to vector owner + add r19,r18,r19 ; Point to the owner per_proc + vrlb v31,v31,v29 ; Get 0xDEADDEAD + li r0,0 + +vsinvothr: lwarx r18,r16,r19 ; Get the owner + cmplw r18,r29 ; Does he still have this context? + bne vsinvoths ; Nope... + stwcx. r0,r16,r19 ; Try to invalidate it + bne- vsinvothr ; Try again if there was a collision... + + +vsinvoths: cmplwi cr1,r14,0 ; Do we possibly have some context to load? + vmrghh v31,v30,v31 ; Get 0x7FFFDEAD. V31 keeps this value until the bitter end + stw r15,VMXlevel(r29) ; Set the "new" active level + eieio + stw r29,VMXowner(r26) ; Mark us as having the live context - cmplwi cr1,r14,0 ; Do we possibly have some context to load? - stw r15,ACT_MACT_VMXlvl(r17) ; Set the "new" active level - la r23,savevscr(r14) ; Point to the VSCR - la r20,savevr0(r14) ; Point to first line to bring in - stw r17,PP_VMX_THREAD(r6) ; Store current thread address in vmx_thread to claim vector for thread - beq- cr1,ProtectTheAmericanWay ; Nothing to restore, first time use... - lwz r0,SAVlvlvec(r14) ; Get the level of first facility savearea - cmplw r0,r15 ; Top level correct to load? - bne- ProtectTheAmericanWay ; No, go initialize... + beq- cr1,ProtectTheAmericanWay ; Nothing to restore, first time use... + + lwz r3,SAVprev(r14) ; Get the previous context + lwz r0,SAVlevel(r14) ; Get the level of first facility savearea + cmplw r0,r15 ; Top level correct to load? + bne- ProtectTheAmericanWay ; No, go initialize... + stw r3,VMXsave(r29) ; Pop the context (we will toss the savearea later) + #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F08 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - mr r8,r3 - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r22,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r22 ; Restore it - mr r3,r8 -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F05 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - li r0,1 ; Get the level invalid indication - lwz r22,savevrsave(r4) ; Get the most current VRSAVE - lwz r10,savevrvalid(r14) ; Get the valid VRs in the savearea - lis r9,0x5555 ; Mask with odd bits set - and r10,r10,r22 ; Figure out just what registers need to be loaded - ori r9,r9,0x5555 ; Finish mask - rlwinm r11,r10,1,0,31 ; Shift over 1 - stw r0,SAVlvlvec(r14) ; Mark the savearea invalid because we are activating again - or r12,r10,r11 ; After this, even bits show which lines to touch - dcbt br0,r23 ; Touch in the VSCR - andc r13,r12,r9 ; Clear out odd bits - - la r20,savevr0(r14) ; Point to line 0 - rlwinm r3,r13,15,0,15 ; Move line 8-15 flags to high order odd bits - la r21,savevr2(r3) ; Point to line 1 - or r3,r13,r3 ; Set the odd bits - ; (bit 0 is line 0, bit 1 is line 8, - ; bit 2 is line 1, bit 3 is line 9, etc. - lvxl v31,br0,r23 ; Get the VSCR - rlwimi r3,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 - mtvscr v31 ; Slam the VSCR value - mtcrf 255,r3 ; Load up the CRs - mr r22,r20 ; Start registers off + lwz r22,savevrsave(r25) ; Get the most current VRSAVE + lwz r10,savevrvalid(r14) ; Get the valid VRs in the savearea + lis r9,0x5555 ; Mask with odd bits set + and r10,r10,r22 ; Figure out just what registers need to be loaded + ori r9,r9,0x5555 ; Finish mask + rlwinm r11,r10,1,0,31 ; Shift over 1 + or r12,r10,r11 ; After this, even bits show which lines to touch + andc r13,r12,r9 ; Clear out odd bits + + la r20,savevr0(r14) ; Point to line 0 + rlwinm r3,r13,15,0,15 ; Move line 8-15 flags to high order odd bits + la r21,savevr2(r3) ; Point to line 1 + or r3,r13,r3 ; Set the odd bits + ; (bit 0 is line 0, bit 1 is line 8, + ; bit 2 is line 1, bit 3 is line 9, etc. + rlwimi r3,r10,16,16,31 ; Put vrsave 0 - 15 into positions 16 - 31 + mtcrf 255,r3 ; Load up the CRs + mr r22,r20 ; Start registers off ; ; Load the new vector state ; - bf 0,lnol0 ; No line 0 to do... - dcbt br0,r20 ; Touch cache line 0 + bf 0,lnol0 ; No line 0 to do... + dcbt br0,r20 ; Touch cache line 0 lnol0: - la r20,savevr4(r14) ; Point to line 2 - bf 2,lnol1 ; No line 1 to do... - dcbt br0,r21 ; Touch cache line 1 + la r20,savevr4(r14) ; Point to line 2 + bf 2,lnol1 ; No line 1 to do... + dcbt br0,r21 ; Touch cache line 1 lnol1: - la r21,savevr6(r14) ; Point to line 3 - bf 4,lnol2 ; No line 2 to do... - dcbt br0,r20 ; Touch cache line 2 + la r21,savevr6(r14) ; Point to line 3 + bf 4,lnol2 ; No line 2 to do... + dcbt br0,r20 ; Touch cache line 2 lnol2: - li r30,16 ; Get offset for odd registers - bf 16,lnovr0 ; Do not restore VR0... - lvxl v0,br0,r22 ; Restore VR0 + li r30,16 ; Get offset for odd registers + bf 16,lnovr0 ; Do not restore VR0... + lvxl v0,br0,r22 ; Restore VR0 lnovr0: - la r23,savevr2(r14) ; Point to V2/V3 pair - bf 17,lnovr1 ; Do not restore VR1... - lvxl v1,r30,r22 ; Restore VR1 + la r23,savevr2(r14) ; Point to V2/V3 pair + bf 17,lnovr1 ; Do not restore VR1... + lvxl v1,r30,r22 ; Restore VR1 lnovr1: - la r20,savevr8(r14) ; Point to line 4 - bf 6,lnol3 ; No line 3 to do... - dcbt br0,r21 ; Touch cache line 3 + la r20,savevr8(r14) ; Point to line 4 + bf 6,lnol3 ; No line 3 to do... + dcbt br0,r21 ; Touch cache line 3 lnol3: - la r22,savevr4(r14) ; Point to V4/V5 pair - bf 18,lnovr2 ; Do not restore VR2... - lvxl v2,br0,r23 ; Restore VR2 + la r22,savevr4(r14) ; Point to V4/V5 pair + bf 18,lnovr2 ; Do not restore VR2... + lvxl v2,br0,r23 ; Restore VR2 lnovr2: - bf 19,lnovr3 ; Do not restore VR3... - lvxl v3,r30,r23 ; Restore VR3 + bf 19,lnovr3 ; Do not restore VR3... + lvxl v3,r30,r23 ; Restore VR3 lnovr3: ; ; Note: CR4 is now free ; - la r21,savevr10(r14) ; Point to line 5 - bf 8,lnol4 ; No line 4 to do... - dcbt br0,r20 ; Touch cache line 4 + la r21,savevr10(r14) ; Point to line 5 + bf 8,lnol4 ; No line 4 to do... + dcbt br0,r20 ; Touch cache line 4 lnol4: - la r23,savevr6(r14) ; Point to R6/R7 pair - bf 20,lnovr4 ; Do not restore VR4... - lvxl v4,br0,r22 ; Restore VR4 + la r23,savevr6(r14) ; Point to R6/R7 pair + bf 20,lnovr4 ; Do not restore VR4... + lvxl v4,br0,r22 ; Restore VR4 lnovr4: - bf 21,lnovr5 ; Do not restore VR5... - lvxl v5,r30,r22 ; Restore VR5 + bf 21,lnovr5 ; Do not restore VR5... + lvxl v5,r30,r22 ; Restore VR5 lnovr5: - mtcrf 0x08,r10 ; Set CRs for registers 16-19 - la r20,savevr12(r14) ; Point to line 6 - bf 10,lnol5 ; No line 5 to do... - dcbt br0,r21 ; Touch cache line 5 + mtcrf 0x08,r10 ; Set CRs for registers 16-19 + la r20,savevr12(r14) ; Point to line 6 + bf 10,lnol5 ; No line 5 to do... + dcbt br0,r21 ; Touch cache line 5 lnol5: - la r22,savevr8(r14) ; Point to V8/V9 pair - bf 22,lnovr6 ; Do not restore VR6... - lvxl v6,br0,r23 ; Restore VR6 + la r22,savevr8(r14) ; Point to V8/V9 pair + bf 22,lnovr6 ; Do not restore VR6... + lvxl v6,br0,r23 ; Restore VR6 lnovr6: - bf 23,lnovr7 ; Do not restore VR7... - lvxl v7,r30,r23 ; Restore VR7 + bf 23,lnovr7 ; Do not restore VR7... + lvxl v7,r30,r23 ; Restore VR7 lnovr7: ; ; Note: CR5 is now free ; - la r21,savevr14(r14) ; Point to line 7 - bf 12,lnol6 ; No line 6 to do... - dcbt br0,r20 ; Touch cache line 6 + la r21,savevr14(r14) ; Point to line 7 + bf 12,lnol6 ; No line 6 to do... + dcbt br0,r20 ; Touch cache line 6 lnol6: - la r23,savevr10(r14) ; Point to V10/V11 pair - bf 24,lnovr8 ; Do not restore VR8... - lvxl v8,br0,r22 ; Restore VR8 + la r23,savevr10(r14) ; Point to V10/V11 pair + bf 24,lnovr8 ; Do not restore VR8... + lvxl v8,br0,r22 ; Restore VR8 lnovr8: - bf 25,lnovr9 ; Do not save VR9... - lvxl v9,r30,r22 ; Restore VR9 + bf 25,lnovr9 ; Do not save VR9... + lvxl v9,r30,r22 ; Restore VR9 lnovr9: - mtcrf 0x04,r10 ; Set CRs for registers 20-23 - la r20,savevr16(r14) ; Point to line 8 - bf 14,lnol7 ; No line 7 to do... - dcbt br0,r21 ; Touch cache line 7 + mtcrf 0x04,r10 ; Set CRs for registers 20-23 + la r20,savevr16(r14) ; Point to line 8 + bf 14,lnol7 ; No line 7 to do... + dcbt br0,r21 ; Touch cache line 7 lnol7: - la r22,savevr12(r14) ; Point to V12/V13 pair - bf 26,lnovr10 ; Do not restore VR10... - lvxl v10,br0,r23 ; Restore VR10 + la r22,savevr12(r14) ; Point to V12/V13 pair + bf 26,lnovr10 ; Do not restore VR10... + lvxl v10,br0,r23 ; Restore VR10 lnovr10: - bf 27,lnovr11 ; Do not restore VR11... - lvxl v11,r30,r23 ; Restore VR11 + bf 27,lnovr11 ; Do not restore VR11... + lvxl v11,r30,r23 ; Restore VR11 lnovr11: ; ; Note: CR6 is now free ; - la r21,savevr18(r14) ; Point to line 9 - bf 1,lnol8 ; No line 8 to do... - dcbt br0,r20 ; Touch cache line 8 + la r21,savevr18(r14) ; Point to line 9 + bf 1,lnol8 ; No line 8 to do... + dcbt br0,r20 ; Touch cache line 8 lnol8: - la r23,savevr14(r14) ; Point to V14/V15 pair - bf 28,lnovr12 ; Do not restore VR12... - lvxl v12,br0,r22 ; Restore VR12 + la r23,savevr14(r14) ; Point to V14/V15 pair + bf 28,lnovr12 ; Do not restore VR12... + lvxl v12,br0,r22 ; Restore VR12 lnovr12: - bf 29,lnovr13 ; Do not restore VR13... - lvxl v13,r30,r22 ; Restore VR13 + bf 29,lnovr13 ; Do not restore VR13... + lvxl v13,r30,r22 ; Restore VR13 lnovr13: - mtcrf 0x02,r10 ; Set CRs for registers 24-27 - la r20,savevr20(r14) ; Point to line 10 - bf 3,lnol9 ; No line 9 to do... - dcbt br0,r21 ; Touch cache line 9 + mtcrf 0x02,r10 ; Set CRs for registers 24-27 + la r20,savevr20(r14) ; Point to line 10 + bf 3,lnol9 ; No line 9 to do... + dcbt br0,r21 ; Touch cache line 9 lnol9: - la r22,savevr16(r14) ; Point to V16/V17 pair - bf 30,lnovr14 ; Do not restore VR14... - lvxl v14,br0,r23 ; Restore VR14 + la r22,savevr16(r14) ; Point to V16/V17 pair + bf 30,lnovr14 ; Do not restore VR14... + lvxl v14,br0,r23 ; Restore VR14 lnovr14: - bf 31,lnovr15 ; Do not restore VR15... - lvxl v15,r30,r23 ; Restore VR15 + bf 31,lnovr15 ; Do not restore VR15... + lvxl v15,r30,r23 ; Restore VR15 lnovr15: ; ; Note: CR7 is now free ; - la r21,savevr22(r14) ; Point to line 11 - bf 5,lnol10 ; No line 10 to do... - dcbt br0,r20 ; Touch cache line 10 + la r21,savevr22(r14) ; Point to line 11 + bf 5,lnol10 ; No line 10 to do... + dcbt br0,r20 ; Touch cache line 10 lnol10: - la r23,savevr18(r14) ; Point to V18/V19 pair - bf 16,lnovr16 ; Do not restore VR16... - lvxl v16,br0,r22 ; Restore VR16 + la r23,savevr18(r14) ; Point to V18/V19 pair + bf 16,lnovr16 ; Do not restore VR16... + lvxl v16,br0,r22 ; Restore VR16 lnovr16: - bf 17,lnovr17 ; Do not restore VR17... - lvxl v17,r30,r22 ; Restore VR17 + bf 17,lnovr17 ; Do not restore VR17... + lvxl v17,r30,r22 ; Restore VR17 lnovr17: - mtcrf 0x01,r10 ; Set CRs for registers 28-31 + mtcrf 0x01,r10 ; Set CRs for registers 28-31 ; ; Note: All registers have been or are accounted for in CRs ; - la r20,savevr24(r14) ; Point to line 12 - bf 7,lnol11 ; No line 11 to do... - dcbt br0,r21 ; Touch cache line 11 + la r20,savevr24(r14) ; Point to line 12 + bf 7,lnol11 ; No line 11 to do... + dcbt br0,r21 ; Touch cache line 11 lnol11: - la r22,savevr20(r14) ; Point to V20/V21 pair - bf 18,lnovr18 ; Do not restore VR18... - lvxl v18,br0,r23 ; Restore VR18 + la r22,savevr20(r14) ; Point to V20/V21 pair + bf 18,lnovr18 ; Do not restore VR18... + lvxl v18,br0,r23 ; Restore VR18 lnovr18: - bf 19,lnovr19 ; Do not restore VR19... - lvxl v19,r30,r23 ; Restore VR19 + bf 19,lnovr19 ; Do not restore VR19... + lvxl v19,r30,r23 ; Restore VR19 lnovr19: - la r21,savevr26(r14) ; Point to line 13 - bf 9,lnol12 ; No line 12 to do... - dcbt br0,r20 ; Touch cache line 12 + la r21,savevr26(r14) ; Point to line 13 + bf 9,lnol12 ; No line 12 to do... + dcbt br0,r20 ; Touch cache line 12 lnol12: - la r23,savevr22(r14) ; Point to V22/V23 pair - bf 20,lnovr20 ; Do not restore VR20... - lvxl v20,br0,r22 ; Restore VR20 + la r23,savevr22(r14) ; Point to V22/V23 pair + bf 20,lnovr20 ; Do not restore VR20... + lvxl v20,br0,r22 ; Restore VR20 lnovr20: - bf 21,lnovr21 ; Do not restore VR21... - lvxl v21,r30,r22 ; Restore VR21 + bf 21,lnovr21 ; Do not restore VR21... + lvxl v21,r30,r22 ; Restore VR21 lnovr21: - la r20,savevr28(r14) ; Point to line 14 - bf 11,lnol13 ; No line 13 to do... - dcbt br0,r21 ; Touch cache line 13 + la r20,savevr28(r14) ; Point to line 14 + bf 11,lnol13 ; No line 13 to do... + dcbt br0,r21 ; Touch cache line 13 lnol13: - la r22,savevr24(r14) ; Point to V24/V25 pair - bf 22,lnovr22 ; Do not restore VR22... - lvxl v22,br0,r23 ; Restore VR22 + la r22,savevr24(r14) ; Point to V24/V25 pair + bf 22,lnovr22 ; Do not restore VR22... + lvxl v22,br0,r23 ; Restore VR22 lnovr22: - bf 23,lnovr23 ; Do not restore VR23... - lvxl v23,r30,r23 ; Restore VR23 + bf 23,lnovr23 ; Do not restore VR23... + lvxl v23,r30,r23 ; Restore VR23 lnovr23: - la r21,savevr30(r14) ; Point to line 15 - bf 13,lnol14 ; No line 14 to do... - dcbt br0,r20 ; Touch cache line 14 + la r21,savevr30(r14) ; Point to line 15 + bf 13,lnol14 ; No line 14 to do... + dcbt br0,r20 ; Touch cache line 14 lnol14: - la r23,savevr26(r14) ; Point to V26/V27 pair - bf 24,lnovr24 ; Do not restore VR24... - lvxl v24,br0,r22 ; Restore VR24 + la r23,savevr26(r14) ; Point to V26/V27 pair + bf 24,lnovr24 ; Do not restore VR24... + lvxl v24,br0,r22 ; Restore VR24 lnovr24: - bf 25,lnovr25 ; Do not restore VR25... - lvxl v25,r30,r22 ; Restore VR25 + bf 25,lnovr25 ; Do not restore VR25... + lvxl v25,r30,r22 ; Restore VR25 lnovr25: - bf 15,lnol15 ; No line 15 to do... - dcbt br0,r21 ; Touch cache line 15 + bf 15,lnol15 ; No line 15 to do... + dcbt br0,r21 ; Touch cache line 15 lnol15: ; ; Note: All needed cache lines have been touched now ; - la r22,savevr28(r14) ; Point to V28/V29 pair - bf 26,lnovr26 ; Do not restore VR26... - lvxl v26,br0,r23 ; Restore VR26 + la r22,savevr28(r14) ; Point to V28/V29 pair + bf 26,lnovr26 ; Do not restore VR26... + lvxl v26,br0,r23 ; Restore VR26 lnovr26: - bf 27,lnovr27 ; Do not restore VR27... - lvxl v27,r30,r23 ; Restore VR27 + bf 27,lnovr27 ; Do not restore VR27... + lvxl v27,r30,r23 ; Restore VR27 lnovr27: - la r23,savevr30(r14) ; Point to V30/V31 pair - bf 28,lnovr28 ; Do not restore VR28... - lvxl v28,br0,r22 ; Restore VR28 + la r23,savevr30(r14) ; Point to V30/V31 pair + bf 28,lnovr28 ; Do not restore VR28... + lvxl v28,br0,r22 ; Restore VR28 lnovr28: - bf 29,lnovr29 ; Do not restore VR29... - lvxl v29,r30,r22 ; Restore VR29 + bf 29,lnovr29 ; Do not restore VR29... + lvxl v29,r30,r22 ; Restore VR29 lnovr29: - bf 30,lnovr30 ; Do not restore VR30... - lvxl v30,br0,r23 ; Restore VR30 + bf 30,lnovr30 ; Do not restore VR30... + lvxl v30,br0,r23 ; Restore VR30 lnovr30: ; ; Everything is restored now except for VR31. We need it to get -; the QNaNBarbarian value to put into idle vector registers +; the QNaNBarbarian value to put into idle vector registers. +; Note: V31 was set above to QNaNbarbarian ; - lis r5,hi16(EXT(QNaNbarbarian)) ; Get address of empty value - cmpwi r10,-1 ; Handle the quick case of all registers in use - ori r5,r5,lo16(EXT(QNaNbarbarian)) ; Get low address of empty value - beq- mstlvr31 ; Not likely, but all are in use... - mtcrf 255,r10 ; Get mask of valid registers - lvxl v31,br0,r5 ; Initialize VR31 to the empty value + cmpwi r10,-1 ; Handle the quick case of all registers in use + beq- mstlvr31 ; Not likely, but all are in use... + mtcrf 255,r10 ; Get mask of valid registers - bt 0,ni0 ; Register is ok already... - vor v0,v31,v31 ; Copy into the next register + bt 0,ni0 ; Register is ok already... + vor v0,v31,v31 ; Copy into the next register ni0: - bt 1,ni1 ; Register is ok already... - vor v1,v31,v31 ; Copy into the next register + bt 1,ni1 ; Register is ok already... + vor v1,v31,v31 ; Copy into the next register ni1: - bt 2,ni2 ; Register is ok already... - vor v2,v31,v31 ; Copy into the next register + bt 2,ni2 ; Register is ok already... + vor v2,v31,v31 ; Copy into the next register ni2: - bt 3,ni3 ; Register is ok already... - vor v3,v31,v31 ; Copy into the next register + bt 3,ni3 ; Register is ok already... + vor v3,v31,v31 ; Copy into the next register ni3: - bt 4,ni4 ; Register is ok already... - vor v4,v31,v31 ; Copy into the next register + bt 4,ni4 ; Register is ok already... + vor v4,v31,v31 ; Copy into the next register ni4: - bt 5,ni5 ; Register is ok already... - vor v5,v31,v31 ; Copy into the next register + bt 5,ni5 ; Register is ok already... + vor v5,v31,v31 ; Copy into the next register ni5: - bt 6,ni6 ; Register is ok already... - vor v6,v31,v31 ; Copy into the next register + bt 6,ni6 ; Register is ok already... + vor v6,v31,v31 ; Copy into the next register ni6: - bt 7,ni7 ; Register is ok already... - vor v7,v31,v31 ; Copy into the next register + bt 7,ni7 ; Register is ok already... + vor v7,v31,v31 ; Copy into the next register ni7: - bt 8,ni8 ; Register is ok already... - vor v8,v31,v31 ; Copy into the next register + bt 8,ni8 ; Register is ok already... + vor v8,v31,v31 ; Copy into the next register ni8: - bt 9,ni9 ; Register is ok already... - vor v9,v31,v31 ; Copy into the next register + bt 9,ni9 ; Register is ok already... + vor v9,v31,v31 ; Copy into the next register ni9: - bt 10,ni10 ; Register is ok already... - vor v10,v31,v31 ; Copy into the next register + bt 10,ni10 ; Register is ok already... + vor v10,v31,v31 ; Copy into the next register ni10: - bt 11,ni11 ; Register is ok already... - vor v11,v31,v31 ; Copy into the next register + bt 11,ni11 ; Register is ok already... + vor v11,v31,v31 ; Copy into the next register ni11: - bt 12,ni12 ; Register is ok already... - vor v12,v31,v31 ; Copy into the next register + bt 12,ni12 ; Register is ok already... + vor v12,v31,v31 ; Copy into the next register ni12: - bt 13,ni13 ; Register is ok already... - vor v13,v31,v31 ; Copy into the next register + bt 13,ni13 ; Register is ok already... + vor v13,v31,v31 ; Copy into the next register ni13: - bt 14,ni14 ; Register is ok already... - vor v14,v31,v31 ; Copy into the next register + bt 14,ni14 ; Register is ok already... + vor v14,v31,v31 ; Copy into the next register ni14: - bt 15,ni15 ; Register is ok already... - vor v15,v31,v31 ; Copy into the next register + bt 15,ni15 ; Register is ok already... + vor v15,v31,v31 ; Copy into the next register ni15: - bt 16,ni16 ; Register is ok already... - vor v16,v31,v31 ; Copy into the next register + bt 16,ni16 ; Register is ok already... + vor v16,v31,v31 ; Copy into the next register ni16: - bt 17,ni17 ; Register is ok already... - vor v17,v31,v31 ; Copy into the next register + bt 17,ni17 ; Register is ok already... + vor v17,v31,v31 ; Copy into the next register ni17: - bt 18,ni18 ; Register is ok already... - vor v18,v31,v31 ; Copy into the next register + bt 18,ni18 ; Register is ok already... + vor v18,v31,v31 ; Copy into the next register ni18: - bt 19,ni19 ; Register is ok already... - vor v19,v31,v31 ; Copy into the next register + bt 19,ni19 ; Register is ok already... + vor v19,v31,v31 ; Copy into the next register ni19: - bt 20,ni20 ; Register is ok already... - vor v20,v31,v31 ; Copy into the next register + bt 20,ni20 ; Register is ok already... + vor v20,v31,v31 ; Copy into the next register ni20: - bt 21,ni21 ; Register is ok already... - vor v21,v31,v31 ; Copy into the next register + bt 21,ni21 ; Register is ok already... + vor v21,v31,v31 ; Copy into the next register ni21: - bt 22,ni22 ; Register is ok already... - vor v22,v31,v31 ; Copy into the next register + bt 22,ni22 ; Register is ok already... + vor v22,v31,v31 ; Copy into the next register ni22: - bt 23,ni23 ; Register is ok already... - vor v23,v31,v31 ; Copy into the next register + bt 23,ni23 ; Register is ok already... + vor v23,v31,v31 ; Copy into the next register ni23: - bt 24,ni24 ; Register is ok already... - vor v24,v31,v31 ; Copy into the next register + bt 24,ni24 ; Register is ok already... + vor v24,v31,v31 ; Copy into the next register ni24: - bt 25,ni25 ; Register is ok already... - vor v25,v31,v31 ; Copy into the next register + bt 25,ni25 ; Register is ok already... + vor v25,v31,v31 ; Copy into the next register ni25: - bt 26,ni26 ; Register is ok already... - vor v26,v31,v31 ; Copy into the next register + bt 26,ni26 ; Register is ok already... + vor v26,v31,v31 ; Copy into the next register ni26: - bt 27,ni27 ; Register is ok already... - vor v27,v31,v31 ; Copy into the next register + bt 27,ni27 ; Register is ok already... + vor v27,v31,v31 ; Copy into the next register ni27: - bt 28,ni28 ; Register is ok already... - vor v28,v31,v31 ; Copy into the next register + bt 28,ni28 ; Register is ok already... + vor v28,v31,v31 ; Copy into the next register ni28: - bt 29,ni29 ; Register is ok already... - vor v29,v31,v31 ; Copy into the next register + bt 29,ni29 ; Register is ok already... + vor v29,v31,v31 ; Copy into the next register ni29: - bt 30,ni30 ; Register is ok already... - vor v30,v31,v31 ; Copy into the next register + bt 30,ni30 ; Register is ok already... + vor v30,v31,v31 ; Copy into the next register ni30: - bf 31,lnovr31 ; R31 is empty, no need to restore... + bf 31,lnovr31 ; V31 is empty, no need to restore... -mstlvr31: lvxl v31,r30,r23 ; Restore VR31 +mstlvr31: lvxl v31,r30,r23 ; Restore VR31 -lnovr31: - -vrenablexx: sync ; Make sure all is saved - stw r18,ACT_MACT_VMXcpu(r17) ; Set the active CPU and release +lnovr31: mr r3,r14 ; Get the old savearea (we popped it before) + bl EXT(save_ret) ; Toss it -vrenable: - lwz r9,SAVflags(r4) /* Get the flags of the current savearea */ - lwz r8,savesrr1(r4) ; Get the msr of the interrupted guy - rlwinm r5,r4,0,0,19 /* Get the page address of the savearea */ - oris r8,r8,hi16(MASK(MSR_VEC)) ; Enable the vector facility - lwz r10,ACT_MACT_SPF(r17) ; Get the special flags - lis r7,hi16(SAVattach) /* Get the attached flag */ - lwz r5,SACvrswap(r5) /* Get Virtual to Real translation */ +vrenable: lwz r8,savesrr1(r25) ; Get the msr of the interrupted guy + rlwinm r5,r25,0,0,19 ; Get the page address of the savearea + oris r8,r8,hi16(MASK(MSR_VEC)) ; Enable the vector facility + lwz r10,ACT_MACT_SPF(r17) ; Get the special flags + lwz r5,SACvrswap(r5) ; Get Virtual to Real translation oris r10,r10,hi16(vectorUsed|vectorCng) ; Set that we used vectors - mr. r15,r15 ; See if we are doing this for user state - stw r8,savesrr1(r4) ; Set the msr of the interrupted guy - andc r9,r9,r7 /* Clear the attached bit */ - xor r3,r4,r5 /* Get the real address of the savearea */ - stw r9,SAVflags(r4) /* Set the flags of the current savearea */ - bne- vrnuser ; We are not user state... - stw r10,ACT_MACT_SPF(r17) ; Set the activation copy - stw r10,spcFlags(r6) ; Set per_proc copy + rlwinm. r0,r8,0,MSR_PR_BIT,MSR_PR_BIT ; See if we are doing this for user state + stw r8,savesrr1(r25) ; Set the msr of the interrupted guy + xor r3,r25,r5 ; Get the real address of the savearea + bne- vrnuser ; We are not user state... + stw r10,ACT_MACT_SPF(r17) ; Set the activation copy + stw r10,spcFlags(r26) ; Set per_proc copy vrnuser: #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F0A ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - mr r8,r3 ; Save this - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r3,r8 ; Restore it -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F07 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - b EXT(exception_exit) /* Exit from the fray... */ + b EXT(exception_exit) ; Exit to the fray... /* * Initialize the registers to some bogus value - * We make sure that non-Java mode is the default here */ ProtectTheAmericanWay: -#if 0 - lwz r10,savesrr1(r4) ; (TEST/DEBUG) - rlwinm. r10,r10,0,MSR_PR_BIT,MSR_PR_BIT ; (TEST/DEBUG) - beq- nxxxxxx2 ; (TEST/DEBUG) - lwz r10,ACT_MACT_SPF(r17) ; (TEST/DEBUG) - rlwinm. r10,r10,0,2,2 ; (TEST/DEBUG) - beq+ nxxxxxx2 - BREAKPOINT_TRAP ; (TEST/DEBUG) -nxxxxxx2: -#endif #if FPVECDBG - lis r0,HIGH_ADDR(CutTrace) ; (TEST/DEBUG) - li r2,0x5F09 ; (TEST/DEBUG) - oris r0,r0,LOW_ADDR(CutTrace) ; (TEST/DEBUG) - sc ; (TEST/DEBUG) -#if GDDBG - lis r3,hi16(EXT(GratefulDeb)) ; Point to top of display - mr r8,r4 ; Save this - ori r3,r3,lo16(EXT(GratefulDeb)) ; Put in bottom part - mr r4,r2 ; Set value - mtlr r3 ; Set link register - li r3,1 ; Display address - blrl ; Display it - mr r4,r8 ; Restore it -#endif + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F06 ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) #endif - lis r5,hi16(EXT(QNaNbarbarian)) ; Get address of empty value - vspltish v1,1 ; Turn on the non-Java bit and saturate - ori r5,r5,lo16(EXT(QNaNbarbarian)) ; Get low address of empty value - vspltisw v2,1 ; Turn on the saturate bit - lvxl v0,br0,r5 ; Initialize VR0 - vxor v1,v1,v2 ; Turn off saturate - - vor v2,v0,v0 ; Copy into the next register - mtvscr v1 ; Clear the vector status register - vor v3,v0,v0 ; Copy into the next register - vor v1,v0,v0 ; Copy into the next register - vor v4,v0,v0 ; Copy into the next register - vor v5,v0,v0 ; Copy into the next register - vor v6,v0,v0 ; Copy into the next register - vor v7,v0,v0 ; Copy into the next register - vor v8,v0,v0 ; Copy into the next register - vor v9,v0,v0 ; Copy into the next register - vor v10,v0,v0 ; Copy into the next register - vor v11,v0,v0 ; Copy into the next register - vor v12,v0,v0 ; Copy into the next register - vor v13,v0,v0 ; Copy into the next register - vor v14,v0,v0 ; Copy into the next register - vor v15,v0,v0 ; Copy into the next register - vor v16,v0,v0 ; Copy into the next register - vor v17,v0,v0 ; Copy into the next register - vor v18,v0,v0 ; Copy into the next register - vor v19,v0,v0 ; Copy into the next register - vor v20,v0,v0 ; Copy into the next register - vor v21,v0,v0 ; Copy into the next register - vor v22,v0,v0 ; Copy into the next register - vor v23,v0,v0 ; Copy into the next register - vor v24,v0,v0 ; Copy into the next register - vor v25,v0,v0 ; Copy into the next register - vor v26,v0,v0 ; Copy into the next register - vor v27,v0,v0 ; Copy into the next register - vor v28,v0,v0 ; Copy into the next register - vor v29,v0,v0 ; Copy into the next register - vor v30,v0,v0 ; Copy into the next register - vor v31,v0,v0 ; Copy into the next register - b vrenablexx ; Finish setting it all up... - -; -; Finds a unused vector area in the activation pointed -; to by R12s saved contexts. If none are found (unlikely but possible) -; and R3 is 0, a new area is allocated. If R3 is non-zero, it contains -; a pointer to a vector savearea that is free. -; - -vsrchsave: lwz r6,ACT_MACT_PCB(r12) ; Get the first "normal" savearea - -vsrnorm: mr. r5,r6 ; Is there another? - beq- vsrvect ; No, search the floating point saveareas... - lwz r7,SAVflags(r5) ; Get the flags for this guy - lwz r6,SAVprev(r5) ; Get the previous savearea, just in case - andis. r8,r7,hi16(SAVvmxvalid) ; Have we found an empty vector save in normal? - beq+ vsrgot ; We found one... - b vsrnorm ; Search again... - -vsrvect: lwz r6,ACT_MACT_FPU(r12) ; Get the first "floating point" savearea - -vsrvectx: mr. r5,r6 ; Is there another? - beq- vsrget ; No, try to allocate one... - lwz r7,SAVflags(r5) ; Get the flags for this guy - lwz r6,SAVprefp(r5) ; Get the previous savearea, just in case - andis. r8,r7,hi16(SAVvmxvalid) ; Have we found an empty vector save in float? - bne- vsrvectx ; Search again... - -vsrgot: mr r3,r5 ; Get the savearea into the right register - blr ; Return... - -vsrget: mr. r5,r3 ; Do we allocate or use existing? - beq+ vsrallo ; Allocate one... - - lwz r7,SAVflags(r3) ; Get the passed in area flags - blr ; Return... -; -; NOTE: save_get will return directly and set R7 to 0... + + vor v0,v31,v31 ; Copy into the next register + vor v1,v31,v31 ; Copy into the next register + vor v2,v31,v31 ; Copy into the next register + vor v3,v31,v31 ; Copy into the next register + vor v4,v31,v31 ; Copy into the next register + vor v5,v31,v31 ; Copy into the next register + vor v6,v31,v31 ; Copy into the next register + vor v7,v31,v31 ; Copy into the next register + vor v8,v31,v31 ; Copy into the next register + vor v9,v31,v31 ; Copy into the next register + vor v10,v31,v31 ; Copy into the next register + vor v11,v31,v31 ; Copy into the next register + vor v12,v31,v31 ; Copy into the next register + vor v13,v31,v31 ; Copy into the next register + vor v14,v31,v31 ; Copy into the next register + vor v15,v31,v31 ; Copy into the next register + vor v16,v31,v31 ; Copy into the next register + vor v17,v31,v31 ; Copy into the next register + vor v18,v31,v31 ; Copy into the next register + vor v19,v31,v31 ; Copy into the next register + vor v20,v31,v31 ; Copy into the next register + vor v21,v31,v31 ; Copy into the next register + vor v22,v31,v31 ; Copy into the next register + vor v23,v31,v31 ; Copy into the next register + vor v24,v31,v31 ; Copy into the next register + vor v25,v31,v31 ; Copy into the next register + vor v26,v31,v31 ; Copy into the next register + vor v27,v31,v31 ; Copy into the next register + vor v28,v31,v31 ; Copy into the next register + vor v29,v31,v31 ; Copy into the next register + vor v30,v31,v31 ; Copy into the next register + b vrenable ; Finish setting it all up... + + + +; +; We get here when we are switching to the same context at the same level and the context +; is still live. Essentially, all we are doing is turning on the faility. It may have +; gotten turned off due to doing a context save for the current level or a context switch +; back to the live guy. +; + + .align 5 + +vsthesame: + +#if FPVECDBG + lis r0,hi16(CutTrace) ; (TEST/DEBUG) + li r2,0x5F0A ; (TEST/DEBUG) + oris r0,r0,lo16(CutTrace) ; (TEST/DEBUG) + sc ; (TEST/DEBUG) +#endif + beq- cr1,vrenable ; Not saved yet, nothing to pop, go enable and exit... + + lwz r11,SAVlevel(r30) ; Get the level of top saved context + lwz r14,SAVprev(r30) ; Get the previous savearea + + cmplw r11,r31 ; Are live and saved the same? + + bne+ vrenable ; Level not the same, nothing to pop, go enable and exit... + + mr r3,r30 ; Get the old savearea (we popped it before) + bl EXT(save_ret) ; Toss it + b vrenable ; Go enable and exit... + + +; +; This function invalidates any live vector context for the passed in facility_context. +; This is intended to be called just before act_machine_sv_free tosses saveareas. ; -vsrallo: b EXT(save_get) ; Get a fresh savearea + .align 5 + .globl EXT(toss_live_vec) -/* - * void lfs(fpsp,fpdp) - * - * load the single precision float to the double - * - * This routine is used by the alignment handler. - * - */ -ENTRY(lfs, TAG_NO_FRAME_USED) - lfs f1, 0(r3) - stfd f1, 0(r4) - blr +LEXT(toss_live_vec) + + mfmsr r9 ; Get the MSR + rlwinm r0,r9,0,MSR_EE_BIT+1,MSR_EE_BIT-1 ; Clear interuptions + rlwinm. r8,r9,0,MSR_VEC_BIT,MSR_VEC_BIT ; Is vector on right now? + rlwinm r9,r9,0,MSR_VEC_BIT+1,MSR_VEC_BIT-1 ; Make sure vector is turned off + rlwinm r9,r9,0,MSR_FP_BIT+1,MSR_FP_BIT-1 ; Make sure fpu is turned off + mtmsr r0 ; No interruptions + isync + beq+ tlvnotours ; Vector off, can not be live here... -/* - * fpsp stfs(fpdp,fpsp) - * - * store the double precision float to the single - * - * This routine is used by the alignment handler. - * - */ -ENTRY(stfs, TAG_NO_FRAME_USED) - lfd f1, 0(r3) - stfs f1, 0(r4) - blr + mfsprg r8,0 ; Get the per proc + +; +; Note that at this point, since vecs are on, we are the owner +; of live state on this processor +; + + lwz r6,VMXowner(r8) ; Get the thread that owns the vector + li r0,0 ; Clear this just in case we need it + cmplw r6,r3 ; Are we tossing our own context? + bne- tlvnotours ; Nope... + + vspltish v1,1 ; Turn on the non-Java bit and saturate + vspltisw v0,1 ; Turn on the saturate bit + vxor v1,v1,v0 ; Turn off saturate + mtspr vrsave,r0 ; Clear VRSAVE + mtvscr v1 ; Set the non-java, no saturate status + +tlvnotours: lwz r11,VMXcpu(r3) ; Get the cpu on which we last loaded context + lis r12,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r11,r11,ppSize ; Find offset to the owner per_proc + ori r12,r12,lo16(EXT(per_proc_info)) ; Set base per_proc + li r10,VMXowner ; Displacement to vector owner + add r11,r12,r11 ; Point to the owner per_proc + li r0,0 ; Set a 0 to invalidate context + +tlvinvothr: lwarx r12,r10,r11 ; Get the owner + cmplw r12,r3 ; Does he still have this context? + bne+ tlvexit ; Nope, leave... + stwcx. r0,r10,r11 ; Try to invalidate it + bne- tlvinvothr ; Try again if there was a collision... + +tlvexit: mtmsr r9 ; Restore interruptions + isync ; Could be turning off vectors here + blr ; Leave.... + +#if 0 +; +; This function invalidates any live vector context for the passed in facility_context +; if the level is current. It also tosses the corresponding savearea if there is one. +; This function is primarily used whenever we detect a VRSave that is all zeros. +; + + .align 5 + .globl EXT(vec_trash) + +LEXT(vec_trash) + + lwz r12,facAct(r3) ; Get the activation + lwz r11,VMXlevel(r3) ; Get the context level + lwz r10,ACT_MACT_PCB(r12) ; Grab the current level for the thread + lwz r9,VMXsave(r3) ; Get the savearea, if any + cmplw r10,r11 ; Are we at the right level? + cmplwi cr1,r9,0 ; Remember if there is a savearea + bnelr+ ; No, we do nothing... + + lwz r11,VMXcpu(r3) ; Get the cpu on which we last loaded context + lis r12,hi16(EXT(per_proc_info)) ; Set base per_proc + mulli r11,r11,ppSize ; Find offset to the owner per_proc + ori r12,r12,lo16(EXT(per_proc_info)) ; Set base per_proc + li r10,VMXowner ; Displacement to vector owner + add r11,r12,r11 ; Point to the owner per_proc + li r0,0 ; Set a 0 to invalidate context + +vtinvothr: lwarx r12,r10,r11 ; Get the owner + cmplw r12,r3 ; Does he still have this context? + bne vtnotlive ; Nope, not live anywhere... + stwcx. r0,r10,r11 ; Try to invalidate it + bne- vtinvothr ; Try again if there was a collision... + +vtnotlive: beqlr+ cr1 ; Leave if there is no savearea + lwz r8,SAVlevel(r9) ; Get the level of the savearea + cmplw r8,r11 ; Savearea for the current level? + bnelr+ ; No, nothing to release... + + lwz r8,SAVprev(r9) ; Pick up the previous area + mr. r8,r8 ; Is there a previous? + beq- vtnoprev ; Nope... + lwz r7,SAVlevel(r8) ; Get the level associated with save + +vtnoprev: stw r8,VMXsave(r3) ; Dequeue this savearea + stw r7,VMXlevel(r3) ; Pop the level + + mr r3,r9 ; Get the savearea to release + b EXT(save_ret) ; Go and toss the save area (note, we will return from there)... +#endif + +; +; Just some test code to force vector and/or floating point in the kernel +; + + .align 5 + .globl EXT(fctx_test) +LEXT(fctx_test) + + mfsprg r3,0 ; Get the per_proc block + lwz r3,PP_ACTIVE_THREAD(r3) ; Get the thread pointer + mr. r3,r3 ; Are we actually up and running? + beqlr- ; No... + + fmr f0,f0 ; Use floating point + mftb r4 ; Get time base for a random number + li r5,1 ; Get a potential vrsave to use + andi. r4,r4,0x3F ; Get a number from 0 - 63 + slw r5,r5,r4 ; Choose a register to save (should be 0 half the time) + mtspr vrsave,r5 ; Set VRSave + vor v0,v0,v0 ; Use vectors + blr