powermac-rom/NanoKernel/NKExceptions.s
2018-07-28 13:37:20 +08:00

472 lines
14 KiB
ArmAsm

; AUTO-GENERATED SYMBOL LIST
########################################################################
; MemRetry error
MRException
mtsprg 3, r24
lwz r9, KDP.Enables(r1)
extrwi r23, r17, 5, 26 ; extract accessLen field
rlwnm. r9, r9, r8, 0, 0 ; BGE taken if exception disabled
bcl BO_IF, mrFlagDidLoad, LoadExtraMRRegs
lwz r6, KDP.ContextPtr(r1)
_set r7, r16, bitContextFlagMemRetryErr
neg r23, r23
mtcrf crMaskFlags, r7
add r19, r19, r23 ; convert r19 from end address back to start address??
insrwi r7, r8, 8, 0 ; ec code -> high byte of flags
slwi r8, r8, 2 ; increment counter
add r8, r8, r1
lwz r9, KDP.NKInfo.ExceptionCauseCounts(r8)
addi r9, r9, 1
stw r9, KDP.NKInfo.ExceptionCauseCounts(r8)
; Move regs from KDP to ContextBlock
lwz r8, KDP.r7(r1)
stw r8, CB.r7+4(r6)
lwz r8, KDP.r8(r1)
stw r8, CB.r8+4(r6)
lwz r8, KDP.r9(r1)
stw r8, CB.r9+4(r6)
lwz r8, KDP.r10(r1)
stw r8, CB.r10+4(r6)
lwz r8, KDP.r11(r1)
stw r8, CB.r11+4(r6)
lwz r8, KDP.r12(r1)
stw r8, CB.r12+4(r6)
lwz r8, KDP.r13(r1)
stw r8, CB.r13+4(r6)
bge RunSystemContext ; Alt Context has left exception disabled => Sys Context
;fall through ; exception enabled => run userspace handler
########################################################################
; Exception or MRException that is Enabled (i.e. not being auto-forced to System)
ExceptionCommon
stw r10, CB.FaultSrcPC+4(r6) ; Save r10/SRR0, r12/LR, r3, r4
stw r12, CB.FaultSrcLR+4(r6)
stw r3, CB.FaultSrcR3+4(r6)
stw r4, CB.FaultSrcR4+4(r6)
lwz r8, KDP.Enables(r1) ; Save Enables & Flags, inc ContextFlagMemRetryErr
stw r7, CB.IntraState.Flags(r6)
stw r8, CB.IntraState.Enables(r6)
; Use IntraState because context handles its own error
li r8, 0 ; Enables=0 (any exceptions in handler go to System)
lwz r10, CB.IntraState.Handler+4(r6) ; SRR0 = handler addr
lwz r4, CB.IntraState.HandlerArg+4(r6) ; r4 = arbitrary second argument
lwz r3, KDP.ECBPtrLogical(r1) ; r3 = ContextBlock ptr
bc BO_IF, bitGlobalFlagSystem, @sys
lwz r3, KDP.NCBCacheLA0(r1)
@sys
lwz r12, KDP.EmuKCallTblPtrLogical(r1) ; r12/LR = address of KCallReturnFromException trap
bcl BO_IF, bitContextFlagMemRetryErr, SaveFailingMemRetryState
rlwinm r7, r7, 0, 29, 15 ; unset flags 16-28
stw r8, KDP.Enables(r1)
rlwimi r11, r7, 0, 20, 23 ; threfore unset MSR[FE0/SE/BE/FE1]
b ReturnFromInt
########################################################################
LoadExtraMRRegs
lwz r0, KDP.r0(r1)
lwz r2, KDP.r2(r1)
lwz r3, KDP.r3(r1)
lwz r4, KDP.r4(r1)
lwz r5, KDP.r5(r1)
blr
SaveFailingMemRetryState
stw r17, CB.IntraState.MemRet17+4(r6)
stw r20, CB.IntraState.MemRetData(r6)
stw r21, CB.IntraState.MemRetData+4(r6)
stw r19, CB.IntraState.MemRet19+4(r6)
stw r18, CB.IntraState.MemRet18+4(r6)
lmw r14, KDP.r14(r1)
blr
########################################################################
_alignToCacheBlock
KCallReturnFromExceptionFastPath
lwz r11, KDP.NKInfo.NanoKernelCallCounts(r1)
mr r10, r12
addi r11, r11, 1
stw r11, KDP.NKInfo.NanoKernelCallCounts(r1)
mfsrr1 r11
rlwimi r7, r7, 32+bitMsrSE-bitContextFlagTraceWhenDone, ContextFlagTraceWhenDone
KCallReturnFromException
cmplwi cr1, r3, 1 ; exception handler return value
blt cr1, @dispose
mtcrf crMaskFlags, r7
beq cr1, @propagate
; If handler returns an exception cause code 2-255, "force" this exception to the System Context.
subi r8, r3, 32
lwz r9, KDP.NKInfo.ExceptionForcedCount(r1)
cmplwi r8, 256-32
addi r9, r9, 1
stw r9, KDP.NKInfo.ExceptionForcedCount(r1)
insrwi r7, r3, 8, 0
blt RunSystemContext
li r8, ecTrapInstr
b Exception ; (error if number is > max exception number)
; If handler returns 0 (System Context must always do this), return to userspace.
@dispose
lwz r8, CB.IntraState.Flags(r6) ; Restore Context flags (inc exception number?)
lwz r10, CB.FaultSrcPC+4(r6)
rlwimi r7, r8, 0, maskExceptionNum | maskContextFlags ; preserve global flags
lwz r8, CB.IntraState.Enables(r6)
rlwimi r11, r7, 0, maskMsrFlags
stw r8, KDP.Enables(r1)
andi. r8, r11, MsrFE0 + MsrFE1 ; check: are floating-pt exceptions enabled?
lwz r12, CB.FaultSrcLR+4(r6) ; restore LR/r3/r4
lwz r3, CB.FaultSrcR3+4(r6)
lwz r4, CB.FaultSrcR4+4(r6)
bnel EnableFPU
addi r9, r6, CB.IntraState ; If MemRetry was interrupted, resume it.
b ReturnFromInt
; If handler returns 1, "propagate" this exception to the System Context
; (When we get back to the Alternate Context, it will be as if the exception was disposed.)
@propagate
lwz r9, KDP.NKInfo.ExceptionPropagateCount(r1)
lwz r8, CB.IntraState.Flags(r6)
addi r9, r9, 1
stw r9, KDP.NKInfo.ExceptionPropagateCount(r1)
lwz r10, CB.FaultSrcPC+4(r6)
rlwimi r7, r8, 0, maskExceptionNum | maskContextFlags ; preserve global flags
lwz r8, CB.IntraState.Enables(r6)
mtcrf crMaskContextFlags, r7
rlwimi r11, r7, 0, maskMsrFlags
stw r8, KDP.Enables(r1)
lwz r12, CB.FaultSrcLR+4(r6) ; restore LR/r3/r4
lwz r3, CB.FaultSrcR3+4(r6)
lwz r4, CB.FaultSrcR4+4(r6)
bc BO_IF_NOT, bitContextFlagMemRetryErr, RunSystemContext
stmw r14, KDP.r14(r1) ; When we *do* get back to this context,
lwz r17, CB.IntraState.MemRet17+4(r6) ; make sure MemRetry state can be resumed
lwz r20, CB.IntraState.MemRetData(r6) ; from InterState
lwz r21, CB.IntraState.MemRetData+4(r6)
lwz r19, CB.IntraState.MemRet19+4(r6)
lwz r18, CB.IntraState.MemRet18+4(r6)
b RunSystemContext
########################################################################
; BEFORE
; PowerPC exception vector saved r1/LR in SPRG1/2 and
; jumped where directed by the VecTbl pointed to by
; SPRG3. That function bl'ed here.
;
; AFTER
; Reg Contains Original saved in
; ---------------------------------------------
; r0 (itself)
; r1 KDP SPRG1
; r2 (itself)
; r3 (itself)
; r4 (itself)
; r5 (itself)
; r6 ContextBlock EWA
; r7 Flags ContextBlock
; r8 KDP ContextBlock
; r9 (scratch CB ptr) ContextBlock
; r10 SRR0 ContextBlock
; r11 SRR1 ContextBlock
; r12 LR ContextBlock
; r13 CR ContextBlock
LoadInterruptRegisters
mfsprg r1, 0
stw r6, KDP.r6(r1)
mfsprg r6, 1
stw r6, KDP.r1(r1)
lwz r6, KDP.ContextPtr(r1)
stw r7, CB.r7+4(r6)
stw r8, CB.r8+4(r6)
stw r9, CB.r9+4(r6)
stw r10, CB.r10+4(r6)
stw r11, CB.r11+4(r6)
stw r12, CB.r12+4(r6)
stw r13, CB.r13+4(r6)
mfsrr0 r10
mfcr r13
lwz r7, KDP.Flags(r1)
mfsprg r12, 2
mfsrr1 r11
blr
########################################################################
Exception
lwz r9, KDP.Enables(r1)
mtcrf crMaskFlags, r7
rlwnm. r9, r9, r8, 0, 0 ; BLT taken if exception enabled
insrwi r7, r8, 8, 0 ; Exception code to hi byte of Flags
slwi r8, r8, 2 ; Increment counter, easy enough
add r8, r8, r1
lwz r9, KDP.NKInfo.ExceptionCauseCounts(r8)
addi r9, r9, 1
stw r9, KDP.NKInfo.ExceptionCauseCounts(r8)
blt ExceptionCommon ; exception enabled => run userspace handler
;fall through ; Alt Context has left exception disabled => Sys Context
########################################################################
RunSystemContext
lwz r9, KDP.ECBPtr(r1) ; System ("Emulator") ContextBlock
addi r8, r1, KDP.VecTblSystem ; System VecTbl
mtsprg 3, r8
bcl BO_IF, bitGlobalFlagSystem, SystemCrash ; System Context already running!
; Fallthru (new CB in r9, old CB in r6)
########################################################################
SwitchContext ; OldCB *r6, NewCB *r9
; Run the System or Alternate Context
lwz r8, KDP.Enables(r1)
stw r7, CB.InterState.Flags(r6)
stw r8, CB.InterState.Enables(r6)
bc BO_IF_NOT, bitContextFlagMemRetryErr, @can_dispose_mr_state
stw r17, CB.InterState.MemRet17+4(r6)
stw r20, CB.InterState.MemRetData(r6)
stw r21, CB.InterState.MemRetData+4(r6)
stw r19, CB.InterState.MemRet19+4(r6)
stw r18, CB.InterState.MemRet18+4(r6)
lmw r14, KDP.r14(r1)
@can_dispose_mr_state
mfxer r8
stw r13, CB.CR+4(r6)
stw r8, CB.XER+4(r6)
stw r12, CB.LR+4(r6)
mfctr r8
stw r10, CB.PC+4(r6)
stw r8, CB.CTR+4(r6)
bc BO_IF_NOT, bitGlobalFlagMQReg, @no_mq
lwz r8, CB.MQ+4(r9)
mfspr r12, mq
mtspr mq, r8
stw r12, CB.MQ+4(r6)
@no_mq
lwz r8, KDP.r1(r1)
stw r0, CB.r0+4(r6)
stw r8, CB.r1+4(r6)
stw r2, CB.r2+4(r6)
stw r3, CB.r3+4(r6)
stw r4, CB.r4+4(r6)
lwz r8, KDP.r6(r1)
stw r5, CB.r5+4(r6)
stw r8, CB.r6+4(r6)
_band. r8, r11, bitMsrFP
stw r14, CB.r14+4(r6)
stw r15, CB.r15+4(r6)
stw r16, CB.r16+4(r6)
stw r17, CB.r17+4(r6)
stw r18, CB.r18+4(r6)
stw r19, CB.r19+4(r6)
stw r20, CB.r20+4(r6)
stw r21, CB.r21+4(r6)
stw r22, CB.r22+4(r6)
stw r23, CB.r23+4(r6)
stw r24, CB.r24+4(r6)
stw r25, CB.r25+4(r6)
stw r26, CB.r26+4(r6)
stw r27, CB.r27+4(r6)
stw r28, CB.r28+4(r6)
stw r29, CB.r29+4(r6)
stw r30, CB.r30+4(r6)
stw r31, CB.r31+4(r6)
bnel DisableFPU
lwz r8, KDP.OtherContextDEC(r1)
mfdec r31
cmpwi r8, 0
stw r31, KDP.OtherContextDEC(r1)
mtdec r8
blel ResetDEC ; to r8
lwz r8, CB.InterState.Flags(r9) ; r8 is the new Flags variable
stw r9, KDP.ContextPtr(r1)
xoris r7, r7, GlobalFlagSystem >> 16 ; flip Emulator flag
rlwimi r11, r8, 0, maskMsrFlags
mr r6, r9 ; change the magic ContextBlock register
rlwimi r7, r8, 0, maskContextFlags ; change bottom half of flags only
andi. r8, r11, MsrFE0 + MsrFE1 ; FP exceptions enabled in new context?
lwz r8, CB.InterState.Enables(r6)
lwz r13, CB.CR+4(r6)
stw r8, KDP.Enables(r1)
lwz r8, CB.XER+4(r6)
lwz r12, CB.LR+4(r6)
mtxer r8
lwz r8, CB.CTR+4(r6)
lwz r10, CB.PC+4(r6)
mtctr r8
bnel ReloadFPU ; FP exceptions enabled, so load FPU
stwcx. r0, 0, r1
lwz r8, CB.r1+4(r6)
lwz r0, CB.r0+4(r6)
stw r8, KDP.r1(r1)
lwz r2, CB.r2+4(r6)
lwz r3, CB.r3+4(r6)
lwz r4, CB.r4+4(r6)
lwz r8, CB.r6+4(r6)
lwz r5, CB.r5+4(r6)
stw r8, KDP.r6(r1)
lwz r14, CB.r14+4(r6)
lwz r15, CB.r15+4(r6)
lwz r16, CB.r16+4(r6)
lwz r17, CB.r17+4(r6)
lwz r18, CB.r18+4(r6)
lwz r19, CB.r19+4(r6)
lwz r20, CB.r20+4(r6)
lwz r21, CB.r21+4(r6)
lwz r22, CB.r22+4(r6)
lwz r23, CB.r23+4(r6)
lwz r24, CB.r24+4(r6)
lwz r25, CB.r25+4(r6)
lwz r26, CB.r26+4(r6)
lwz r27, CB.r27+4(r6)
lwz r28, CB.r28+4(r6)
lwz r29, CB.r29+4(r6)
lwz r30, CB.r30+4(r6)
lwz r31, CB.r31+4(r6)
########################################################################
ReturnFromInt ; If ContextFlagMemRetryErr && ContextFlagResumeMemRetry, please pass KernelState ptr in r9
andi. r8, r7, ContextFlagTraceWhenDone | ContextFlagMemRetryErr
bnel @special_cases ; Keep rare cases out of the hot path
stw r7, KDP.Flags(r1) ; Save kernel flags for next interrupt
mtlr r12 ; Restore user SPRs from kernel GPRs
mtsrr0 r10
mtsrr1 r11
mtcr r13
lwz r10, CB.r10+4(r6) ; Restore user GPRs from ContextBlock
lwz r11, CB.r11+4(r6)
lwz r12, CB.r12+4(r6)
lwz r13, CB.r13+4(r6)
lwz r7, CB.r7+4(r6)
lwz r8, CB.r8+4(r6)
lwz r9, CB.r9+4(r6)
lwz r6, KDP.r6(r1) ; Restore last two registers from EWA
lwz r1, KDP.r1(r1)
rfi ; Go
@special_cases
mtcrf crMaskFlags, r7
bc BO_IF_NOT, bitContextFlagMemRetryErr, @no_memretry ; If MemRetry had to be paused for an exception
_clear r7, r7, bitContextFlagMemRetryErr ; which is now finished, finish MemRetry.
bc BO_IF, bitContextFlagResumeMemRetry, @resume_memretry
_clear r7, r7, bitContextFlagTraceWhenDone
b @justreturn
@no_memretry
bc BO_IF_NOT, bitContextFlagTraceWhenDone, @justreturn ; If this current interrupt was raised when
_clear r7, r7, bitContextFlagTraceWhenDone ; every instruction should be followed by a
stw r7, KDP.Flags(r1) ; Trace exception, then raise one.
li r8, ecInstTrace
b Exception
@justreturn
blr
@resume_memretry ; Pick up where an MRException left off, now that the Exception has been disposed.
stw r7, KDP.Flags(r1)
stw r0, KDP.r0(r1)
stw r2, KDP.r2(r1)
stw r3, KDP.r3(r1)
stw r4, KDP.r4(r1)
stw r5, KDP.r5(r1)
lwz r8, CB.r7+4(r6)
stw r8, KDP.r7(r1)
lwz r8, CB.r8+4(r6)
stw r8, KDP.r8(r1)
lwz r8, CB.r9+4(r6)
stw r8, KDP.r9(r1)
lwz r8, CB.r10+4(r6)
stw r8, KDP.r10(r1)
lwz r8, CB.r11+4(r6)
stw r8, KDP.r11(r1)
lwz r8, CB.r12+4(r6)
stw r8, KDP.r12(r1)
lwz r8, CB.r13+4(r6)
stw r8, KDP.r13(r1)
stmw r14, KDP.r14(r1)
lwz r17, KernelState.MemRet17+4(r9) ; Get the MR state from IntraState (if context was never switched)
lwz r20, KernelState.MemRetData(r9) ; or InterState (if exception was propagated to System Context and
lwz r21, KernelState.MemRetData+4(r9) ; we are now switching back to Alternate Context).
lwz r19, KernelState.MemRet19+4(r9)
lwz r18, KernelState.MemRet18+4(r9)
_clear r16, r7, bitContextFlagMemRetryErr
lwz r25, KDP.MRBase(r1) ; MRRestab is indexed by the first arg of MROptab?
extrwi. r22, r17, 4, 27 ;
add r19, r19, r22 ; Correct r19 (EA) by adding len from r17
rlwimi r25, r17, 7, 25, 30
lhz r26, MRRestab-MRBase(r25)
insrwi r25, r19, 3, 28 ; Set Memtab alignment modulus
stw r16, KDP.Flags(r1)
rlwimi r26, r26, 8, 8, 15 ; First byte of MRRestab is for cr3/cr4
insrwi r25, r17, 4, 24 ; len and load/store from second arg of MROptab?
mtcrf 0x10, r26 ; Set CR3
lha r22, MRMemtab-MRBase(r25) ; Jump to MRMemtab...
addi r23, r1, KDP.VecTblMemRetry
add r22, r22, r25
mfsprg r24, 3
mtlr r22
mtsprg 3, r23
mfmsr r14
_set r15, r14, bitMsrDR
mtmsr r15
rlwimi r25, r26, 2, 22, 29 ; Second byte of MRRestab is a secondary routine
bnelr
b MRDoSecondary
########################################################################
ResetDEC ; to r8
lis r31, 0x7FFF
mtdec r31
mtdec r8
blr