/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include /* * This file contains implementations for the Virtual Machine Monitor * facility. */ /* * int vmm_dispatch(savearea, act); * vmm_dispatch is a PPC only system call. It is used with a selector (first * parameter) to determine what function to enter. This is treated as an extension * of hw_exceptions. * * Inputs: * R4 = current activation * R16 = current thread * R30 = current savearea */ .align 5 /* Line up on cache line */ .globl EXT(vmm_dispatch_table) LEXT(vmm_dispatch_table) /* Don't change the order of these routines in the table. It's */ /* OK to add new routines, but they must be added at the bottom. */ .long EXT(vmm_get_version_sel) ; Get the version of the VMM interface .long EXT(vmm_get_features_sel) ; Get the features of the VMM interface .long EXT(vmm_init_context_sel) ; Initializes a new VMM context .long EXT(vmm_tear_down_context) ; Tears down a previously-allocated VMM context .long EXT(vmm_tear_down_all) ; Tears down all VMMs .long EXT(vmm_map_page) ; Maps a page from the main address space into the VM space .long EXT(vmm_get_page_mapping) ; Returns client va associated with VM va .long EXT(vmm_unmap_page) ; Unmaps a page from the VM space .long EXT(vmm_unmap_all_pages) ; Unmaps all pages from the VM space .long EXT(vmm_get_page_dirty_flag) ; Gets the change bit for a page and optionally clears it .long EXT(vmm_get_float_state) ; Gets current floating point state .long EXT(vmm_get_vector_state) ; Gets current vector state .long EXT(vmm_set_timer) ; Sets a timer value .long EXT(vmm_get_timer) ; Gets a timer value .long EXT(switchIntoVM) ; Switches to the VM context .set vmm_count,(.-EXT(vmm_dispatch_table))/4 ; Get the top number .align 5 .globl EXT(vmm_dispatch) LEXT(vmm_dispatch) lwz r11,saver3(r30) ; Get the selector mr r3,r4 ; All of our functions want the activation as the first parm lis r10,hi16(EXT(vmm_dispatch_table)) ; Get top half of table cmplwi r11,kVmmExecuteVM ; Should we switch to the VM now? cmplwi cr1,r11,vmm_count ; See if we have a valid selector ori r10,r10,lo16(EXT(vmm_dispatch_table)) ; Get low half of table lwz r4,saver4(r30) ; Get 1st parameter after selector beq+ EXT(switchIntoVM) ; Yes, go switch to it.... rlwinm r11,r11,2,0,29 ; Index into table bgt- cr1,vmmBogus ; It is a bogus entry lwzx r10,r10,r11 ; Get address of routine lwz r5,saver5(r30) ; Get 2nd parameter after selector lwz r6,saver6(r30) ; Get 3rd parameter after selector mtlr r10 ; Set the routine address lwz r7,saver7(r30) ; Get 4th parameter after selector ; ; NOTE: currently the most paramters for any call is 4. We will support at most 8 because we ; do not want to get into any stack based parms. However, here is where we need to add ; code for the 5th - 8th parms if we need them. ; blrl ; Call function stw r3,saver3(r30) ; Pass back the return code li r3,1 ; Set normal return with check for AST b EXT(ppcscret) ; Go back to handler... vmmBogus: eqv r3,r3,r3 ; Bogus selector, treat like a bogus system call b EXT(ppcscret) ; Go back to handler... .align 5 .globl EXT(vmm_get_version_sel) LEXT(vmm_get_version_sel) ; Selector based version of get version lis r3,hi16(EXT(vmm_get_version)) ori r3,r3,lo16(EXT(vmm_get_version)) b selcomm .align 5 .globl EXT(vmm_get_features_sel) LEXT(vmm_get_features_sel) ; Selector based version of get features lis r3,hi16(EXT(vmm_get_features_sel)) ori r3,r3,lo16(EXT(vmm_get_features_sel)) b selcomm .align 5 .globl EXT(vmm_init_context_sel) LEXT(vmm_init_context_sel) ; Selector based version of init context lis r3,hi16(EXT(vmm_init_context_sel)) ori r3,r3,lo16(EXT(vmm_init_context_sel)) selcomm: mtlr r3 ; Set the real routine address mr r3,r30 ; Pass in the savearea blrl ; Call the function b EXT(ppcscret) ; Go back to handler... /* * Here is where we transition to the virtual machine. * * We will swap the register context in the savearea with that which is saved in our shared * context area. We will validity check a bit and clear any nasty bits in the MSR and force * the manditory ones on. * * Then we will setup the new address space to run with, and anything else that is normally part * of a context switch. * * Still need to figure out final floats and vectors. For now, we will go brute * force and when we go into the VM, we will force save any normal floats and * vectors. Then we will hide them and swap the VM copy (if any) into the normal * chain. When we exit VM we will do the opposite. This is not as fast as I would * like it to be. * * */ .align 5 .globl EXT(switchIntoVM) LEXT(switchIntoVM) lwz r5,vmmControl(r3) ; Pick up the control table address subi r4,r4,1 ; Switch to zero offset rlwinm. r2,r5,0,0,30 ; Is there a context there? (Note: we will ignore bit 31 so that we ; do not try this while we are transitioning off to on cmplwi cr1,r4,kVmmMaxContextsPerThread ; Is the index valid? beq- vmmBogus ; Not started, treat like a bogus system call mulli r2,r4,vmmCEntrySize ; Get displacement from index bgt- cr1,swvmmBogus ; Index is bogus... add r2,r2,r5 ; Point to the entry lwz r4,vmmFlags(r2) ; Get the flags for the selected entry lwz r5,vmmContextKern(r2) ; Get the context area address rlwinm. r26,r4,0,vmmInUseb,vmmInUseb ; See if the slot is in use bne+ swvmChkIntcpt ; We are so cool. Go do check for immediate intercepts... swvmmBogus: li r2,kVmmBogusContext ; Set bogus index return li r3,1 ; Set normal return with check for AST stw r2,saver3(r30) ; Pass back the return code b EXT(ppcscret) ; Go back to handler... ; ; Here we check for any immediate intercepts. So far, the only ; one of these is a timer pop. We will not dispatch if the timer has ; already popped. They need to either reset the timer (i.e. set timer ; to 0) or to set a future time. ; swvmChkIntcpt: rlwinm. r26,r4,0,vmmTimerPopb,vmmTimerPopb ; Did the timer pop? beq+ swvmDoSwitch ; No... li r2,kVmmReturnNull ; Set null return li r3,1 ; Set normal return with check for AST stw r2,saver3(r30) ; Pass back the return code stw r2,return_code(r5) ; Save the exit code b EXT(ppcscret) ; Go back to handler... ; ; Here is where we actually swap into the VM (alternate) context. ; We will bulk do a wholesale swap of the registers in the context area (the VMs) ; with the ones in the savearea (our main code). During the copy, we will fix up the ; MSR, forcing on a few bits and turning off a few others. Then we will deal with the ; PMAP and other per_proc stuff. Finally, we will exit back through the main exception ; handler to deal with unstacking saveareas and ASTs, etc. ; swvmDoSwitch: ; ; First, we save the volatile registers we care about. Remember, all register ; handling here is pretty funky anyway, so we just pick the ones that are ok. ; mr r26,r3 ; Save the activation pointer mr r28,r5 ; Save the context pointer mr r27,r2 ; Save the context entry bl vmmxcng ; Exchange the vector and floating point contexts mr r5,r28 ; Restore this register lwz r11,ACT_MACT_SPF(r26) ; Get the special flags lwz r3,vmmPmap(r27) ; Get the pointer to the PMAP oris r15,r11,hi16(runningVM) ; ; Show that we are swapped to the VM right now bl EXT(hw_set_user_space_dis) ; Swap the address spaces lwz r17,vmmFlags(r27) ; Get the status flags mfsprg r10,0 ; Get the per_proc rlwinm. r0,r17,0,vmmMapDoneb,vmmMapDoneb ; Did we just do a map function? stw r27,vmmCEntry(r26) ; Remember what context we are running andc r17,r17,r0 ; Turn off map flag beq+ swvmNoMap ; No mapping done... ; ; This little bit of hoopala here (triggered by vmmMapDone) is ; a performance enhancement. This will change the returning savearea ; to look like we had a DSI rather than a system call. Then, setting ; the redrive bit, the exception handler will redrive the exception as ; a DSI, entering the last mapped address into the hash table. This keeps ; double faults from happening. Note that there is only a gain if the VM ; takes a fault, then the emulator resolves it only, and then begins ; the VM execution again. It seems like this should be the normal case. ; lwz r3,SAVflags(r30) ; Pick up the savearea flags lwz r2,vmmLastMap(r27) ; Get the last mapped address li r20,T_DATA_ACCESS ; Change to DSI fault oris r3,r3,hi16(SAVredrive) ; Set exception redrive stw r2,savedar(r30) ; Set the DAR to the last thing we mapped stw r3,SAVflags(r30) ; Turn on the redrive request lis r2,hi16(MASK(DSISR_HASH)) ; Set PTE/DBAT miss stw r20,saveexception(r30) ; Say we need to emulate a DSI stw r2,savedsisr(r30) ; Pretend we have a PTE miss swvmNoMap: rlwimi r15,r17,32-(floatCngbit-vmmFloatCngdb),floatCngbit,vectorCngbit ; Shift and insert changed bits rlwimi r17,r11,8,24,31 ; Save the old spf flags stw r15,spcFlags(r10) ; Set per_proc copy of the special flags stw r15,ACT_MACT_SPF(r26) ; Get the special flags stw r17,vmmFlags(r27) ; Set the status flags bl swapCtxt ; First, swap the general register state lwz r17,vmmContextKern(r27) ; Get the comm area lwz r15,vmmCntrl(r17) ; Get the control flags rlwinm. r0,r15,0,vmmFloatLoadb,vmmFloatLoadb ; Are there new floating point values? li r14,vmmppcFPRs ; Get displacement to the new values andc r15,r15,r0 ; Clear the bit beq+ swvmNoNewFloats ; Nope, good... lwz r3,ACT_MACT_FPU(r26) ; Get the FPU savearea dcbt r14,r18 ; Touch in first line of new stuff mr. r3,r3 ; Is there one? bne+ swvmGotFloat ; Yes... bl EXT(save_get) ; Get a savearea li r11,0 ; Get a 0 lis r7,hi16(SAVfpuvalid) ; Set the allocated bit stw r3,ACT_MACT_FPU(r26) ; Set the floating point savearea stw r7,SAVflags(r3) ; Set the validity flags stw r11,SAVlvlfp(r3) ; Set the context level swvmGotFloat: dcbt r14,r17 ; Touch in first line of new stuff la r4,savefp0(r3) ; Point to the destination mr r21,r3 ; Save the save area la r3,vmmppcFPRs(r17) ; Point to the source li r5,33*8 ; Get the size (32 FP + FPSCR at 8 bytes each) bl EXT(bcopy) ; Copy the new values lwz r11,ACT_MACT_SPF(r26) ; Get the special flags stw r15,vmmCntrl(r17) ; Save the control flags sans vmmFloatLoad rlwinm r11,r11,0,floatCngbit+1,floatCngbit-1 ; Clear the changed bit here lwz r14,vmmStat(r17) ; Get the status flags mfsprg r10,0 ; Get the per_proc stw r11,ACT_MACT_SPF(r26) ; Get the special flags rlwinm r14,r14,0,vmmFloatCngdb+1,vmmFloatCngdb-1 ; Clear the changed flag stw r11,spcFlags(r10) ; Set per_proc copy of the special flags stw r14,vmmStat(r17) ; Set the status flags sans vmmFloatCngd lwz r11,savefpscrpad(r21) ; Get the new fpscr pad lwz r14,savefpscr(r21) ; Get the new fpscr stw r11,savexfpscrpad(r30) ; Save the new fpscr pad stw r14,savexfpscr(r30) ; Save the new fpscr swvmNoNewFloats: rlwinm. r0,r15,0,vmmVectLoadb,vmmVectLoadb ; Are there new vector values? li r14,vmmppcVRs ; Get displacement to the new values andc r15,r15,r0 ; Clear the bit beq+ swvmNoNewVects ; Nope, good... lwz r3,ACT_MACT_VMX(r26) ; Get the vector savearea dcbt r14,r27 ; Touch in first line of new stuff mr. r3,r3 ; Is there one? bne+ swvmGotVect ; Yes... bl EXT(save_get) ; Get a savearea li r21,0 ; Get a 0 lis r7,hi16(SAVvmxvalid) ; Set the allocated bit stw r3,ACT_MACT_VMX(r26) ; Set the vector savearea indication stw r7,SAVflags(r3) ; Set the validity flags stw r21,SAVlvlvec(r3) ; Set the context level swvmGotVect: dcbt r14,r17 ; Touch in first line of new stuff mr r21,r3 ; Save the pointer to the savearea la r4,savevr0(r3) ; Point to the destination la r3,vmmppcVRs(r17) ; Point to the source li r5,33*16 ; Get the size (32 vectors + VSCR at 16 bytes each) bl EXT(bcopy) ; Copy the new values lwz r11,ACT_MACT_SPF(r26) ; Get the special flags stw r15,vmmCntrl(r17) ; Save the control flags sans vmmVectLoad rlwinm r11,r11,0,vectorCngbit+1,vectorCngbit-1 ; Clear the changed bit here lwz r14,vmmStat(r17) ; Get the status flags mfsprg r10,0 ; Get the per_proc stw r11,ACT_MACT_SPF(r26) ; Get the special flags rlwinm r14,r14,0,vmmVectCngdb+1,vmmVectCngdb-1 ; Clear the changed flag eqv r15,r15,r15 ; Get all foxes stw r11,spcFlags(r10) ; Set per_proc copy of the special flags stw r14,vmmStat(r17) ; Set the status flags sans vmmVectCngd stw r15,savevrvalid(r21) ; Set the valid bits to all foxes swvmNoNewVects: li r3,1 ; Show normal exit with check for AST mr r9,r26 ; Move the activation pointer b EXT(ppcscret) ; Go back to handler... ; ; Here is where we exchange the emulator floating and vector contexts ; for the virtual machines. Remember, this is not so efficient and needs ; a rewrite. Also remember the funky register conventions (i.e., ; we need to know what our callers need saved and what our callees trash. ; ; Note: we expect R26 to contain the activation and R27 to contain the context ; entry pointer. ; vmmxcng: mflr r21 ; Save the return point bl EXT(fpu_save) ; Save any floating point context bl EXT(vec_save) ; Save any vector point context lis r10,hi16(EXT(per_proc_info)) ; Get top of first per_proc li r8,PP_FPU_THREAD ; Index to FPU owner ori r10,r10,lo16(EXT(per_proc_info)) ; Get bottom of first per_proc lis r6,hi16(EXT(real_ncpus)) ; Get number of CPUs li r7,0 ; Get set to clear ori r6,r6,lo16(EXT(real_ncpus)) ; Get number of CPUs li r9,PP_VMX_THREAD ; Index to vector owner lwz r6,0(r6) ; Get the actual CPU count vmmrt1: lwarx r3,r8,r10 ; Get FPU owner cmplw r3,r26 ; Do we own it? bne vmmrt2 ; Nope... stwcx. r7,r8,r10 ; Clear it bne- vmmrt1 ; Someone else diddled, try again.... vmmrt2: lwarx r3,r9,r10 ; Get vector owner cmplw r3,r26 ; Do we own it? bne vmmxnvec ; Nope... stwcx. r7,r9,r10 ; Clear it bne- vmmrt2 ; Someone else diddled, try again.... vmmxnvec: addic. r6,r6,-1 ; Done with all CPUs? addi r10,r10,ppSize ; On to the next bgt vmmrt1 ; Do all processors... ; ; At this point, the FP and Vector states for the current activation ; are saved and not live on any processor. Also, they should be the ; only contexts on the activation. Note that because we are currently ; taking the cowardly way out and insuring that no contexts are live, ; we do not need to worry about the CPU fields. ; lwz r8,ACT_MACT_FPU(r26) ; Get the FPU savearea lwz r9,ACT_MACT_VMX(r26) ; Get the vector savearea lwz r10,vmmFPU_pcb(r27) ; Get the FPU savearea lwz r11,vmmVMX_pcb(r27) ; Get the vector savearea li r7,0 ; Clear this mtlr r21 ; Restore the return stw r10,ACT_MACT_FPU(r26) ; Set the FPU savearea stw r11,ACT_MACT_VMX(r26) ; Set the vector savearea stw r8,vmmFPU_pcb(r27) ; Set the FPU savearea stw r9,vmmVMX_pcb(r27) ; Set the vector savearea stw r7,ACT_MACT_FPUlvl(r26) ; Make sure the level is clear stw r7,ACT_MACT_VMXlvl(r26) ; Make sure the level is clear mr. r8,r8 ; Do we have any old floating point context? lwz r7,savexfpscrpad(r30) ; Get first part of latest fpscr lwz r9,savexfpscr(r30) ; Get second part of the latest fpscr beq- xcngnold ; Nope... stw r7,savefpscrpad(r8) ; Set first part of fpscr stw r9,savefpscr(r8) ; Set fpscr xcngnold: mr. r10,r10 ; Any new context? li r7,0 ; Assume no FP li r9,0 ; Assume no FP beq- xcngnnew ; Nope... lwz r7,savefpscrpad(r10) ; Get first part of latest fpscr lwz r9,savefpscr(r10) ; Get second part of the latest fpscr xcngnnew: stw r7,savexfpscrpad(r30) ; Set the fpsc stw r9,savexfpscr(r30) ; Set the fpscr blr ; Return... ; ; Here is where we exit from vmm mode. We do this on any kind of exception. ; Interruptions (decrementer, external, etc.) are another story though. ; These we just pass through. We also switch back explicity when requested. ; This will happen in response to a timer pop and some kinds of ASTs. ; ; Inputs: ; R3 = activation ; R4 = savearea ; .align 5 .globl EXT(vmm_exit) LEXT(vmm_exit) lwz r2,vmmCEntry(r3) ; Get the context that is active lwz r12,ACT_VMMAP(r3) ; Get the VM_MAP for this guy lwz r11,ACT_MACT_SPF(r3) ; Get the special flags lwz r19,vmmFlags(r2) ; Get the status flags mr r16,r3 ; R16 is safe to use for the activation address rlwimi r19,r11,floatCngbit-vmmFloatCngdb,vmmFloatCngdb,vmmVectCngdb ; Shift and insert changed bits li r0,0 ; Get a zero rlwimi r11,r19,vmmSpfSaveb,floatCngbit,vectorCngbit ; Restore the saved part of the spf lwz r3,VMMAP_PMAP(r12) ; Get the pmap for the activation rlwinm r11,r11,0,runningVMbit+1,runningVMbit-1 ; Clear the "in VM" flag stw r0,vmmCEntry(r16) ; Clear pointer to active context stw r19,vmmFlags(r2) ; Set the status flags mfsprg r10,0 ; Get the per_proc block stw r11,ACT_MACT_SPF(r16) ; Get the special flags stw r11,spcFlags(r10) ; Set per_proc copy of the special flags mr r26,r16 ; Save the activation pointer mr r27,r2 ; Save the context entry bl EXT(hw_set_user_space_dis) ; Swap the address spaces back to the emulator bl vmmxcng ; Exchange the vector and floating point contexts mr r2,r27 ; Restore lwz r5,vmmContextKern(r2) ; Get the context area address mr r3,r16 ; Restore activation address stw r19,vmmStat(r5) ; Save the changed and popped flags bl swapCtxt ; Exchange the VM context for the emulator one stw r8,saver3(r30) ; Set the return code as the return value also b EXT(retFromVM) ; Go back to handler... ; ; Here is where we force exit from vmm mode. We do this when as ; part of termination and is used to insure that we are not executing ; in an alternate context. Because this is called from C we need to save ; all non-volatile registers. ; ; Inputs: ; R3 = activation ; R4 = user savearea ; Interruptions disabled ; .align 5 .globl EXT(vmm_force_exit) LEXT(vmm_force_exit) stwu r1,-(FM_ALIGN(20*4)+FM_SIZE)(r1) ; Get enough space for the registers mflr r0 ; Save the return stmw r13,FM_ARG0(r1) ; Save all non-volatile registers stw r0,(FM_ALIGN(20*4)+FM_SIZE+FM_LR_SAVE)(r1) ; Save the return lwz r2,vmmCEntry(r3) ; Get the context that is active lwz r11,ACT_MACT_SPF(r3) ; Get the special flags lwz r19,vmmFlags(r2) ; Get the status flags lwz r12,ACT_VMMAP(r3) ; Get the VM_MAP for this guy rlwimi r19,r11,floatCngbit-vmmFloatCngdb,vmmFloatCngdb,vmmVectCngdb ; Shift and insert changed bits mr r26,r3 ; Save the activation pointer rlwimi r11,r19,vmmSpfSaveb,floatCngbit,vectorCngbit ; Restore the saved part of the spf li r0,0 ; Get a zero rlwinm r9,r11,0,runningVMbit+1,runningVMbit-1 ; Clear the "in VM" flag cmplw r9,r11 ; Check if we were in a vm lwz r3,VMMAP_PMAP(r12) ; Get the pmap for the activation beq- vfeNotRun ; We were not in a vm.... stw r0,vmmCEntry(r26) ; Clear pointer to active context mfsprg r10,0 ; Get the per_proc block stw r9,ACT_MACT_SPF(r26) ; Get the special flags stw r9,spcFlags(r10) ; Set per_proc copy of the special flags mr r27,r2 ; Save the context entry mr r30,r4 ; Save the savearea bl EXT(hw_set_user_space_dis) ; Swap the address spaces back to the emulator bl vmmxcng ; Exchange the vector and floating point contexts lwz r5,vmmContextKern(r27) ; Get the context area address stw r19,vmmStat(r5) ; Save the changed and popped flags bl swapCtxt ; Exchange the VM context for the emulator one li r8,kVmmReturnNull ; Set a null return when we force an intercept stw r8,saver3(r30) ; Set the return code as the return value also vfeNotRun: lmw r13,FM_ARG0(r1) ; Restore all non-volatile registers lwz r1,0(r1) ; Pop the stack lwz r0,FM_LR_SAVE(r1) ; Get the return address mtlr r0 ; Set return blr ; ; Note: we will not do any DCBTs to the savearea. It was just stored to a few cycles ago and should ; still be in the cache. Note also that the context area registers map identically to the savearea. ; ; NOTE: we do not save any of the non-volatile registers through this swap code ; NOTE NOTE: R16 is important to save!!!! ; NOTE: I am too dumb to figure out a faster way to swap 5 lines of memory. So I go for ; the simple way .align 5 swapCtxt: addi r6,r5,vmm_proc_state ; Point to the state li r25,32 ; Get a cache size increment addi r4,r30,savesrr0 ; Point to the start of the savearea dcbt 0,r6 ; Touch in the first line of the context area lwz r14,saveexception(r30) ; Get the exception code lwz r7,savesrr0(r4) ; First line of savearea lwz r8,savesrr1(r4) lwz r9,saver0(r4) cmplwi cr1,r14,T_SYSTEM_CALL ; Are we switching because of a system call? lwz r10,saver1(r4) lwz r11,saver2(r4) lwz r12,saver3(r4) lwz r13,saver4(r4) lwz r14,saver5(r4) dcbt r25,r6 ; Touch second line of context area addi r25,r25,32 ; Bump lwz r15,savesrr0(r6) ; First line of context lis r22,hi16(MSR_IMPORT_BITS) ; Get the MSR bits that are controllable by user lwz r23,savesrr1(r6) ori r22,r25,lo16(MSR_IMPORT_BITS) ; Get the rest of the MSR bits that are controllable by user lwz r17,saver0(r6) lwz r18,saver1(r6) and r23,r23,r22 ; Keep only the controllable bits lwz r19,saver2(r6) oris r23,r23,hi16(MSR_EXPORT_MASK_SET) ; Force on the required bits lwz r20,saver3(r6) ori r23,r23,lo16(MSR_EXPORT_MASK_SET) ; Force on the other required bits lwz r21,saver4(r6) lwz r22,saver5(r6) dcbt r25,r6 ; Touch third line of context area addi r25,r25,32 ; Bump (r25 is 64 now) stw r7,savesrr0(r6) ; Save emulator context into the context area stw r8,savesrr1(r6) stw r9,saver0(r6) stw r10,saver1(r6) stw r11,saver2(r6) stw r12,saver3(r6) stw r13,saver4(r6) stw r14,saver5(r6) ; ; Save the first 3 parameters if we are an SC (we will take care of the last later) ; bne+ cr1,swapnotsc ; Skip next if not an SC exception... stw r12,return_params+0(r5) ; Save the first return stw r13,return_params+4(r5) ; Save the second return stw r14,return_params+8(r5) ; Save the third return swapnotsc: stw r15,savesrr0(r4) ; Save vm context into the savearea stw r23,savesrr1(r4) stw r17,saver0(r4) stw r18,saver1(r4) stw r19,saver2(r4) stw r20,saver3(r4) stw r21,saver4(r4) stw r22,saver5(r4) ; ; The first hunk is swapped, do the rest in a loop ; li r23,4 ; Four more hunks to swap swaploop: addi r4,r4,32 ; Bump savearea pointer addi r6,r6,32 ; Bump context area pointer addic. r23,r23,-1 ; Count down dcbt r25,r6 ; Touch 4th, 5th, and 6th and 7th which are extra lwz r7,0(r4) ; Read savearea lwz r8,4(r4) lwz r9,8(r4) lwz r10,12(r4) lwz r11,16(r4) lwz r12,20(r4) lwz r13,24(r4) lwz r14,28(r4) lwz r15,0(r6) ; Read vm context lwz r24,4(r6) lwz r17,8(r6) lwz r18,12(r6) lwz r19,16(r6) lwz r20,20(r6) lwz r21,24(r6) lwz r22,28(r6) stw r7,0(r6) ; Write context stw r8,4(r6) stw r9,8(r6) stw r10,12(r6) stw r11,16(r6) stw r12,20(r6) stw r13,24(r6) stw r14,28(r6) stw r15,0(r4) ; Write vm context stw r24,4(r4) stw r17,8(r4) stw r18,12(r4) stw r19,16(r4) stw r20,20(r4) stw r21,24(r4) stw r22,28(r4) bgt+ swaploop ; Do it all... ; ; Cobble up the exception return code and save any specific return values ; lwz r7,saveexception(r30) ; Pick up the exception code rlwinm r8,r7,30,24,31 ; Convert exception to return code cmplwi r7,T_DATA_ACCESS ; Was this a DSI? stw r8,return_code(r5) ; Save the exit code cmplwi cr1,r7,T_INSTRUCTION_ACCESS ; Exiting because of an ISI? beq+ swapDSI ; Yeah... cmplwi r7,T_ALIGNMENT ; Alignment exception? beq+ cr1,swapISI ; We had an ISI... cmplwi cr1,r7,T_SYSTEM_CALL ; Exiting because of an system call? beq+ swapDSI ; An alignment exception looks like a DSI... beq+ cr1,swapSC ; We had a system call... blr ; Return... ; ; Set exit returns for a DSI or alignment exception ; swapDSI: lwz r10,savedar(r30) ; Get the DAR lwz r7,savedsisr(r30) ; and the DSISR stw r10,return_params+0(r5) ; Save DAR as first return parm stw r7,return_params+4(r5) ; Save DSISR as second return parm blr ; Return... ; ; Set exit returns for a ISI ; swapISI: lwz r7,savesrr1+vmm_proc_state(r5) ; Get the SRR1 value lwz r10,savesrr0+vmm_proc_state(r5) ; Get the PC as failing address rlwinm r7,r7,0,1,4 ; Save the bits that match the DSISR stw r10,return_params+0(r5) ; Save PC as first return parm stw r7,return_params+4(r5) ; Save the pseudo-DSISR as second return parm blr ; Return... ; ; Set exit returns for a system call (note: we did the first 3 earlier) ; Do we really need to pass parameters back here???? ; swapSC: lwz r10,saver6+vmm_proc_state(r5) ; Get the fourth paramter stw r10,return_params+12(r5) ; Save it blr ; Return...