+; Handle "vmm_dispatch" (0x6004), of which only some selectors are UFTs.
+
+uftVMM:
+ mtctr r13 ; restore callers ctr
+ lwz r11,spcFlags(r11) ; get the special flags word from per_proc
+ mfcr r13 ; save callers entire cr (we use all fields below)
+ rlwinm r11,r11,16,16,31 ; Extract spcFlags upper bits
+ andi. r11,r11,hi16(runningVM|FamVMena|FamVMmode)
+ cmpwi cr0,r11,hi16(runningVM|FamVMena|FamVMmode) ; Test in VM FAM
+ bne-- uftNormal80 ; not eligible for FAM UFTs
+ cmpwi cr5,r3,kvmmResumeGuest ; Compare r3 with kvmmResumeGuest
+ cmpwi cr2,r3,kvmmSetGuestRegister ; Compare r3 with kvmmSetGuestRegister
+ cror cr1_eq,cr5_lt,cr2_gt ; Set true if out of VMM Fast syscall range
+ bt-- cr1_eq,uftNormalFF ; Exit if out of range (the others are not UFTs)
+ b EXT(vmm_ufp) ; handle UFT range of vmm_dispatch syscall
+
+
+; Handle blue box UFTs (syscalls -1 and -2).
+
+uftIsPreemptiveTask:
+uftIsPreemptiveTaskEnv:
+ mtctr r13 ; restore callers ctr
+ lwz r11,spcFlags(r11) ; get the special flags word from per_proc
+ mfcr r13,0x80 ; save callers cr0 so we can use it
+ andi. r11,r11,bbNoMachSC|bbPreemptive ; Clear what we do not need
+ cmplwi r11,bbNoMachSC ; See if we are trapping syscalls
+ blt-- uftNormal80 ; No...
+ cmpwi r0,-2 ; is this call IsPreemptiveTaskEnv?
+ rlwimi r13,r11,bbPreemptivebit-cr0_eq,cr0_eq,cr0_eq ; Copy preemptive task flag into user cr0_eq
+ mfsprg r11,0 ; Get the per proc once more
+ bne++ uftRestoreThenRFI ; do not load r0 if IsPreemptiveTask
+ lwz r0,ppbbTaskEnv(r11) ; Get the shadowed taskEnv (only difference)
+ b uftRestoreThenRFI ; restore modified cr0 and return
+
+
+; Handle "Thread Info" UFT (0x7FF2)
+
+ .globl EXT(uft_uaw_nop_if_32bit)
+uftThreadInfo:
+ lwz r3,UAW+4(r11) ; get user assist word, assuming a 32-bit processor
+LEXT(uft_uaw_nop_if_32bit)
+ ld r3,UAW(r11) ; get the whole doubleword if 64-bit (patched to nop if 32-bit)
+ mtctr r13 ; restore callers ctr
+ b uftRFI ; done
+
+
+; Handle "Facility Status" UFT (0x7FF3)
+
+uftFacilityStatus:
+ lwz r3,spcFlags(r11) ; get "special flags" word from per_proc
+ mtctr r13 ; restore callers ctr
+ b uftRFI ; done
+
+
+; Handle "Load MSR" UFT (0x7FF4). This is not used on 64-bit processors, though it would work.
+
+uftLoadMSR:
+ mfsrr1 r11 ; get callers MSR
+ mtctr r13 ; restore callers ctr
+ mfcr r13,0x80 ; save callers cr0 so we can test PR
+ rlwinm. r11,r11,0,MSR_PR_BIT,MSR_PR_BIT ; really in the kernel?
+ bne- uftNormal80 ; do not permit from user mode
+ mfsprg r11,0 ; restore per_proc
+ mtsrr1 r3 ; Set new MSR
+
+
+; Return to caller after UFT. When called:
+; r11 = per_proc ptr
+; r13 = callers cr0 in upper nibble (if uftRestoreThenRFI called)
+; sprg2 = callers r13
+; sprg3 = callers r11
+
+uftRestoreThenRFI: ; WARNING: can drop down to here
+ mtcrf 0x80,r13 ; restore callers cr0
+uftRFI:
+ .globl EXT(uft_nop_if_32bit)
+LEXT(uft_nop_if_32bit)
+ b uftX64 ; patched to NOP if 32-bit processor
+
+uftX32: lwz r11,pfAvailable(r11) ; Get the feature flags
+ mfsprg r13,2 ; Restore R13
+ mtsprg 2,r11 ; Set the feature flags
+ mfsprg r11,3 ; Restore R11
+ rfi ; Back to our guy...
+
+uftX64: mtspr hsprg0,r14 ; Save a register in a Hypervisor SPRG
+ ld r14,UAW(r11) ; Get the User Assist DoubleWord
+ lwz r11,pfAvailable(r11) ; Get the feature flags
+ mfsprg r13,2 ; Restore R13
+ mtsprg 2,r11 ; Set the feature flags
+ mfsprg r11,3 ; Restore R11
+ mtsprg 3,r14 ; Set the UAW in sprg3
+ mfspr r14,hsprg0 ; Restore R14
+ rfid ; Back to our guy...
+
+;
+; Quickly cut a trace table entry for the CutTrace firmware call.
+;
+; All registers except R11 and R13 are unchanged.
+;
+; Note that this code cuts a trace table entry for the CutTrace call only.
+; An identical entry is made during normal interrupt processing. Any entry
+; format entry changes made must be done in both places.
+;
+
+ .align 5
+
+ .globl EXT(uft_cuttrace)
+LEXT(uft_cuttrace)
+uftCutTrace:
+ b uftct64 ; patched to NOP if 32-bit processor
+
+ stw r20,tempr0(r11) ; Save some work registers
+ lwz r20,dgFlags(0) ; Get the flags
+ stw r21,tempr1(r11) ; Save some work registers
+ mfsrr1 r21 ; Get the SRR1
+ rlwinm r20,r20,MSR_PR_BIT-enaUsrFCallb,MASK(MSR_PR) ; Shift the validity bit over to pr bit spot
+ stw r25,tempr2(r11) ; Save some work registers
+ orc r20,r20,r21 ; Get ~PR | FC
+ mfcr r25 ; Save the CR
+ stw r22,tempr3(r11) ; Save some work registers
+ lhz r22,PP_CPU_NUMBER(r11) ; Get the logical processor number
+ andi. r20,r20,MASK(MSR_PR) ; Set cr0_eq is we are in problem state and the validity bit is not set
+ stw r23,tempr4(r11) ; Save some work registers
+ lwz r23,traceMask(0) ; Get the trace mask
+ stw r24,tempr5(r11) ; Save some work registers
+ beq- ctbail32 ; Can not issue from user...
+
+
+ addi r24,r22,16 ; Get shift to move cpu mask to syscall mask
+ rlwnm r24,r23,r24,12,12 ; Shift cpu mask bit to rupt type mask
+ and. r24,r24,r23 ; See if both are on
+
+;
+; We select a trace entry using a compare and swap on the next entry field.
+; Since we do not lock the actual trace buffer, there is a potential that
+; another processor could wrap an trash our entry. Who cares?
+;
+
+ li r23,trcWork ; Get the trace work area address
+ lwz r21,traceStart(0) ; Get the start of trace table
+ lwz r22,traceEnd(0) ; Get end of trace table
+
+ beq-- ctdisa32 ; Leave because tracing is disabled...
+
+ctgte32: lwarx r20,0,r23 ; Get and reserve the next slot to allocate
+ addi r24,r20,LTR_size ; Point to the next trace entry
+ cmplw r24,r22 ; Do we need to wrap the trace table?
+ bne+ ctgte32s ; No wrap, we got us a trace entry...
+
+ mr r24,r21 ; Wrap back to start
+
+ctgte32s: stwcx. r24,0,r23 ; Try to update the current pointer
+ bne- ctgte32 ; Collision, try again...
+
+#if ESPDEBUG
+ dcbf 0,r23 ; Force to memory
+ sync
+#endif
+
+ dcbz 0,r20 ; Clear and allocate first trace line
+ li r24,32 ; Offset to next line
+
+ctgte32tb: mftbu r21 ; Get the upper time now
+ mftb r22 ; Get the lower time now
+ mftbu r23 ; Get upper again
+ cmplw r21,r23 ; Has it ticked?
+ bne- ctgte32tb ; Yes, start again...
+
+ dcbz r24,r20 ; Clean second line
+
+;
+; Let us cut that trace entry now.
+;
+; Note that this code cuts a trace table entry for the CutTrace call only.
+; An identical entry is made during normal interrupt processing. Any entry
+; format entry changes made must be done in both places.
+;
+
+ lhz r24,PP_CPU_NUMBER(r11) ; Get the logical processor number
+ li r23,T_SYSTEM_CALL ; Get the system call id
+ mtctr r13 ; Restore the callers CTR
+ sth r24,LTR_cpu(r20) ; Save processor number
+ li r24,64 ; Offset to third line
+ sth r23,LTR_excpt(r20) ; Set the exception code
+ dcbz r24,r20 ; Clean 3rd line
+ mfspr r23,dsisr ; Get the DSISR
+ stw r21,LTR_timeHi(r20) ; Save top of time stamp
+ li r24,96 ; Offset to fourth line
+ mflr r21 ; Get the LR
+ dcbz r24,r20 ; Clean 4th line
+ stw r22,LTR_timeLo(r20) ; Save bottom of time stamp
+ mfsrr0 r22 ; Get SRR0
+ stw r25,LTR_cr(r20) ; Save CR
+ mfsrr1 r24 ; Get the SRR1
+ stw r23,LTR_dsisr(r20) ; Save DSISR
+ stw r22,LTR_srr0+4(r20) ; Save SRR0
+ mfdar r23 ; Get DAR
+ stw r24,LTR_srr1+4(r20) ; Save SRR1
+ stw r23,LTR_dar+4(r20) ; Save DAR
+ stw r21,LTR_lr+4(r20) ; Save LR
+
+ stw r13,LTR_ctr+4(r20) ; Save CTR
+ stw r0,LTR_r0+4(r20) ; Save register
+ stw r1,LTR_r1+4(r20) ; Save register
+ stw r2,LTR_r2+4(r20) ; Save register
+ stw r3,LTR_r3+4(r20) ; Save register
+ stw r4,LTR_r4+4(r20) ; Save register
+ stw r5,LTR_r5+4(r20) ; Save register
+ stw r6,LTR_r6+4(r20) ; Save register
+
+#if 0
+ lwz r21,FPUowner(r11) ; (TEST/DEBUG) Get the current floating point owner
+ stw r21,LTR_rsvd0(r20) ; (TEST/DEBUG) Record the owner
+#endif
+
+#if ESPDEBUG
+ addi r21,r20,32 ; Second line
+ addi r22,r20,64 ; Third line
+ dcbst 0,r20 ; Force to memory
+ dcbst 0,r21 ; Force to memory
+ addi r21,r22,32 ; Fourth line
+ dcbst 0,r22 ; Force to memory
+ dcbst 0,r21 ; Force to memory
+ sync ; Make sure it all goes
+#endif
+
+ctdisa32: mtcrf 0x80,r25 ; Restore the used condition register field
+ lwz r20,tempr0(r11) ; Restore work register
+ lwz r21,tempr1(r11) ; Restore work register
+ lwz r25,tempr2(r11) ; Restore work register
+ mtctr r13 ; Restore the callers CTR
+ lwz r22,tempr3(r11) ; Restore work register
+ lwz r23,tempr4(r11) ; Restore work register
+ lwz r24,tempr5(r11) ; Restore work register
+ b uftX32 ; Go restore the rest and go...
+
+ctbail32: mtcrf 0x80,r25 ; Restore the used condition register field
+ lwz r20,tempr0(r11) ; Restore work register
+ lwz r21,tempr1(r11) ; Restore work register
+ lwz r25,tempr2(r11) ; Restore work register
+ mtctr r13 ; Restore the callers CTR
+ lwz r22,tempr3(r11) ; Restore work register
+ lwz r23,tempr4(r11) ; Restore work register
+ b uftNormalSyscall ; Go pass it on along...
+
+;
+; This is the 64-bit version.
+;
+
+uftct64: std r20,tempr0(r11) ; Save some work registers
+ lwz r20,dgFlags(0) ; Get the flags
+ std r21,tempr1(r11) ; Save some work registers
+ mfsrr1 r21 ; Get the SRR1
+ rlwinm r20,r20,MSR_PR_BIT-enaUsrFCallb,MASK(MSR_PR) ; Shift the validity bit over to pr bit spot
+ std r25,tempr2(r11) ; Save some work registers
+ orc r20,r20,r21 ; Get ~PR | FC
+ mfcr r25 ; Save the CR
+ std r22,tempr3(r11) ; Save some work registers
+ lhz r22,PP_CPU_NUMBER(r11) ; Get the logical processor number
+ andi. r20,r20,MASK(MSR_PR) ; Set cr0_eq when we are in problem state and the validity bit is not set
+ std r23,tempr4(r11) ; Save some work registers
+ lwz r23,traceMask(0) ; Get the trace mask
+ std r24,tempr5(r11) ; Save some work registers
+ beq-- ctbail64 ; Can not issue from user...
+
+ addi r24,r22,16 ; Get shift to move cpu mask to syscall mask
+ rlwnm r24,r23,r24,12,12 ; Shift cpu mask bit to rupt type mask
+ and. r24,r24,r23 ; See if both are on
+
+;
+; We select a trace entry using a compare and swap on the next entry field.
+; Since we do not lock the actual trace buffer, there is a potential that
+; another processor could wrap an trash our entry. Who cares?
+;
+
+ li r23,trcWork ; Get the trace work area address
+ lwz r21,traceStart(0) ; Get the start of trace table
+ lwz r22,traceEnd(0) ; Get end of trace table
+
+ beq-- ctdisa64 ; Leave because tracing is disabled...
+
+ctgte64: lwarx r20,0,r23 ; Get and reserve the next slot to allocate
+ addi r24,r20,LTR_size ; Point to the next trace entry
+ cmplw r24,r22 ; Do we need to wrap the trace table?
+ bne++ ctgte64s ; No wrap, we got us a trace entry...
+
+ mr r24,r21 ; Wrap back to start
+
+ctgte64s: stwcx. r24,0,r23 ; Try to update the current pointer
+ bne-- ctgte64 ; Collision, try again...
+
+#if ESPDEBUG
+ dcbf 0,r23 ; Force to memory
+ sync
+#endif
+
+ dcbz128 0,r20 ; Zap the trace entry
+
+ mftb r21 ; Get the time
+
+;
+; Let us cut that trace entry now.
+;
+; Note that this code cuts a trace table entry for the CutTrace call only.
+; An identical entry is made during normal interrupt processing. Any entry
+; format entry changes made must be done in both places.
+;
+
+ lhz r24,PP_CPU_NUMBER(r11) ; Get the logical processor number
+ li r23,T_SYSTEM_CALL ; Get the system call id
+ sth r24,LTR_cpu(r20) ; Save processor number
+ sth r23,LTR_excpt(r20) ; Set the exception code
+ mfspr r23,dsisr ; Get the DSISR
+ std r21,LTR_timeHi(r20) ; Save top of time stamp
+ mflr r21 ; Get the LR
+ mfsrr0 r22 ; Get SRR0
+ stw r25,LTR_cr(r20) ; Save CR
+ mfsrr1 r24 ; Get the SRR1
+ stw r23,LTR_dsisr(r20) ; Save DSISR
+ std r22,LTR_srr0(r20) ; Save SRR0
+ mfdar r23 ; Get DAR
+ std r24,LTR_srr1(r20) ; Save SRR1
+ std r23,LTR_dar(r20) ; Save DAR
+ std r21,LTR_lr(r20) ; Save LR
+
+ std r13,LTR_ctr(r20) ; Save CTR
+ std r0,LTR_r0(r20) ; Save register
+ std r1,LTR_r1(r20) ; Save register
+ std r2,LTR_r2(r20) ; Save register
+ std r3,LTR_r3(r20) ; Save register
+ std r4,LTR_r4(r20) ; Save register
+ std r5,LTR_r5(r20) ; Save register
+ std r6,LTR_r6(r20) ; Save register
+
+#if 0
+ lwz r21,FPUowner(r11) ; (TEST/DEBUG) Get the current floating point owner
+ stw r21,LTR_rsvd0(r20) ; (TEST/DEBUG) Record the owner
+#endif
+
+#if ESPDEBUG
+ dcbf 0,r20 ; Force to memory
+ sync ; Make sure it all goes
+#endif
+
+ctdisa64: mtcrf 0x80,r25 ; Restore the used condition register field
+ ld r20,tempr0(r11) ; Restore work register
+ ld r21,tempr1(r11) ; Restore work register
+ ld r25,tempr2(r11) ; Restore work register
+ mtctr r13 ; Restore the callers CTR
+ ld r22,tempr3(r11) ; Restore work register
+ ld r23,tempr4(r11) ; Restore work register
+ ld r24,tempr5(r11) ; Restore work register
+ b uftX64 ; Go restore the rest and go...
+
+ctbail64: mtcrf 0x80,r25 ; Restore the used condition register field
+ ld r20,tempr0(r11) ; Restore work register
+ ld r21,tempr1(r11) ; Restore work register
+ ld r25,tempr2(r11) ; Restore work register
+ mtctr r13 ; Restore the callers CTR
+ ld r22,tempr3(r11) ; Restore work register
+ ld r23,tempr4(r11) ; Restore work register
+ li r11,T_SYSTEM_CALL|T_FAM ; Set system code call
+ b extEntry64 ; Go straight to the 64-bit code...
+
+
+
+; Handle a system call that is not a UFT and which thus goes upstairs.
+
+uftNormalFF: ; here with entire cr in r13
+ mtcr r13 ; restore all 8 fields
+ b uftNormalSyscall1 ; Join common...
+
+uftNormal80: ; here with callers cr0 in r13
+ mtcrf 0x80,r13 ; restore cr0
+ b uftNormalSyscall1 ; Join common...
+
+uftNormalSyscall: ; r13 = callers ctr
+ mtctr r13 ; restore ctr
+uftNormalSyscall1:
+ li r11,T_SYSTEM_CALL|T_FAM ; this is a system call (and fall through)
+
+
+/*<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>*/
+/*
+ * .L_exception_entry(type)
+ *
+ * Come here via branch directly from the vector, or falling down from above, with the following
+ * set up:
+ *
+ * ENTRY: interrupts off, VM off, in 64-bit mode if supported
+ * Caller's r13 saved in sprg2.
+ * Caller's r11 saved in sprg3.
+ * Exception code (ie, T_SYSTEM_CALL etc) in r11.
+ * All other registers are live.
+ *
+ */
+
+.L_exception_entry: ; WARNING: can fall through from UFT handler
+
+/*
+ *
+ * Here we will save off a mess of registers, the special ones and R0-R12. We use the DCBZ
+ * instruction to clear and allcoate a line in the cache. This way we won't take any cache
+ * misses, so these stores won't take all that long. Except the first line that is because
+ * we can't do a DCBZ if the L1 D-cache is off. The rest we will skip if they are
+ * off also.
+ *
+ * Note that if we are attempting to sleep (as opposed to nap or doze) all interruptions
+ * are ignored.
+ */
+
+
+ .globl EXT(extPatch32)
+
+
+LEXT(extPatch32)
+ b extEntry64 ; Go do 64-bit (patched to a nop if 32-bit)
+ mfsprg r13,0 ; Load per_proc
+ lwz r13,next_savearea+4(r13) ; Get the exception save area
+ stw r0,saver0+4(r13) ; Save register 0
+ stw r1,saver1+4(r13) ; Save register 1
+