powermac-rom/NanoKernel/NKIntMisc.s
2018-07-04 19:28:34 +08:00

1142 lines
29 KiB
ArmAsm

; AUTO-GENERATED SYMBOL LIST
; IMPORTS:
; NKConsoleLog
; printw
; NKExceptions
; Exception
; IntReturn
; IntReturnToOtherBlueContext
; NKIndex
; LookupID
; NKInit
; ResetBuiltinKernel
; NKIntHandlers
; LoadInterruptRegisters
; MaskedInterruptTaken
; save_all_registers
; NKMPCalls
; kcMPDispatch
; NKPaging
; PagingL2PWithBATs
; NKScheduler
; Restore_v0_v31
; SchExitInterrupt
; SchRestoreStartingAtR14
; SchSaveStartingAtR14
; SchSwitchSpace
; NKSync
; CauseNotification
; NKTranslation
; FDPEmulateInstruction
; EXPORTS:
; HandlePerfMonitorInt (=> NKInit)
; IgnoreSoftwareInt (=> NKInit, NKTranslation)
; IntExternalAlternate (=> NKInit)
; IntExternalSystem (=> NKInit)
; IntPerfMonitor (=> NKInit)
; IntProgram (=> NKInit)
; IntReturnFromSIGP (=> NKExceptions, NKIntHandlers)
; IntSyscall (=> NKInit)
; IntThermalEvent (=> NKInit)
; IntTrace (=> NKInit)
; SIGP (=> NKMPCalls, NKScheduler, NKSleep)
; kcPrioritizeInterrupts (=> NKInit)
; kcResetSystem (=> NKInit)
; kcRunAlternateContext (=> NKInit)
; kcThud (=> NKInit)
; major_0x046d0 (=> NKInit)
; major_0x04a20 (=> NKInit)
; wordfill (=> NKInit, NKPowerCalls)
major_0x04180 ; OUTSIDE REFERER
stw r6, -0x0290(r1)
stw r10, -0x028c(r1)
stw r11, -0x0288(r1)
lwz r6, -0x0014(r1)
lwz r10, 0x00d8(r6)
mfspr r11, srr1
cmpwi r10, 0x00
beql major_0x04180_0x9c
oris r11, r11, 0x200
stw r9, -0x027c(r1)
mtspr srr1, r11
mfmsr r11
oris r11, r11, 0x200
mtmsr r11
isync
bl Restore_v0_v31
lwz r8, -0x0004(r1)
lwz r11, 0x0ed4(r8)
addi r11, r11, 0x01
stw r11, 0x0ed4(r8)
mtcr r13
lwz r6, -0x0290(r1)
lwz r10, -0x028c(r1)
lwz r11, -0x0288(r1)
lwz r13, -0x0284(r1)
lwz r8, -0x0280(r1)
lwz r9, -0x027c(r1)
mfsprg r1, 2
mtlr r1
mfsprg r1, 1
rfi
dcb.b 32, 0
major_0x04180_0x9c
mtcr r13
lwz r6, -0x0290(r1)
lwz r10, -0x028c(r1)
lwz r11, -0x0288(r1)
lwz r13, -0x0284(r1)
bl LoadInterruptRegisters
li r8, ecInvalidInstr
b Exception
### ###### # #
# # # ##### # # ###### ##### ###### ## ## #### # # # ##### #### #####
# ## # # # # # # # # # # # # # # ## # # # # # # #
# # # # # ###### ##### # # ##### # # # # # # # # # # # # # #
# # # # # # # ##### # # # # # # # # # # # # #####
# # ## # # # # # # # # # # # ## # # # # # #
### # # # # ###### # # # # # #### # # # # #### # #
align kIntAlign
IntPerfMonitor ; OUTSIDE REFERER
mtlr r1
mfsprg r1, 0
stw r8, -0x0280(r1)
stw r13, -0x0284(r1)
mflr r8
mfcr r13
cmpwi r8, 0xf20
beq major_0x04180
mtcr r13
lwz r13, -0x0284(r1)
lwz r8, -0x0280(r1)
bl save_all_registers
mr r28, r8
rlwinm. r9, r11, 0, 16, 16
beq MaskedInterruptTaken
_Lock PSA.SchLock, scratch1=r8, scratch2=r9
lwz r8, PSA.PMFHandlerID(r1)
; r8 = id
bl LookupID
cmpwi r9, Notification.kIDClass
mr r30, r8
bne IntPerfMonitor_0x88
lwz r16, -0x0340(r28)
lwz r17, -0x0008(r28)
stw r16, 0x0010(r30)
lwz r16, 0x0000(r17)
stw r16, 0x0014(r30)
mfspr r16, 955
stw r16, 0x0018(r30)
bl CauseNotification
IntPerfMonitor_0x88
_AssertAndRelease PSA.SchLock, scratch=r8
; r6 = ewa
bl SchRestoreStartingAtR14
b IntReturn
; Notify the Thermal Handler
align kIntAlign
IntThermalEvent ; OUTSIDE REFERER
bl save_all_registers
mr r28, r8
rlwinm. r9, r11, 0, 16, 16
beq MaskedInterruptTaken
_log 'Thermal event^n'
_Lock PSA.SchLock, scratch1=r8, scratch2=r9
lwz r8, PSA.ThermalHandlerID(r1)
bl LookupID
cmpwi r9, Notification.kIDClass
mr r30, r8
bne @no_thermal_handler
lwz r16, EWA.CPUBase + CPU.ID(r28)
stw r16, Notification.MsgWord1(r30)
bl CauseNotification
@no_thermal_handler
_AssertAndRelease PSA.SchLock, scratch=r8
bl SchRestoreStartingAtR14
b IntReturn
###### # #####
# # #### # # # # # # # # # ##### ###### ##### # # ## ##### ###### # # #### # # ##### ###### # # #####
# # # # # # # # ## # # # # # # # # ## # # # # # # # # ## # # # # # #
#### # ###### # # # # # # # # # ##### # # # # # # # # ##### # # # # # # # ##### ## #
# # # # # # # # # # ####### # # # ##### # # # ###### # # # # # # # # # # ## #
# # # # # # # # # ## # # # # # # # # ## # # # # # # # # # ## # # # # #
# # #### # # #### # # # # ###### # ###### # # # # # # # ###### ##### #### # # # ###### # # #
; We can assume that this is being called from the emulator
; We accept a logical NCB ptr but the kernel needs a physical one.
; So we keep a four-entry cache in KDP, mapping logical NCB ptrs
; to physical ones. But when are there multiple alt contexts?
; ARG flags? r3, mask r4
align kIntAlign
kcRunAlternateContext
mtcrf 0x3f, r7
bcl BO_IF_NOT, EWA.kFlagBlue, IntReturn
and. r8, r4, r13
lwz r9, KDP.NCBCacheLA0(r1)
rlwinm r8, r3, 0, 0, 25
cmpw cr1, r8, r9
bne IntReturn
lwz r9, KDP.NCBCachePA0(r1)
bne cr1, @search_cache
@found_physical_in_cache ; can come here from below after a more thorough search
addi r8, r1, KDP.VecBaseAlternate ; the only use of this vector table?
mtsprg 3, r8
lwz r8, KDP.LA_EmulatorKernelTrapTable(r1)
mtcrf 0x3f, r7
mfsprg r1, 0
clrlwi r7, r7, 8
stw r8, ContextBlock.LA_EmulatorKernelTrapTable(r9)
stw r9, EWA.PA_ContextBlock(r1)
b IntReturnToOtherBlueContext
@search_cache
lwz r9, KDP.NCBCacheLA1(r1)
cmpw cr1, r8, r9
beq cr1, @found_in_slot_1
lwz r9, KDP.NCBCacheLA2(r1)
cmpw cr1, r8, r9
beq cr1, @found_in_slot_2
lwz r9, KDP.NCBCacheLA3(r1)
cmpw cr1, r8, r9
beq cr1, @found_in_slot_3
; No luck with the cache
mfsprg r1, 0
stmw r14, EWA.r14(r1)
lwz r1, EWA.PA_KDP(r1)
cmpw cr1, r8, r6
beq cr1, @fail
mr r27, r8
addi r29, r1, KDP.BATs + 0xa0
bl PagingL2PWithBATs
clrlwi r23, r8, 20
beq @fail
cmplwi r23, 0x0d00
mr r9, r8
mr r8, r31
ble @not_straddling_pages
addi r27, r27, 0x1000
addi r29, r1, KDP.BATs + 0xa0
bl PagingL2PWithBATs
beq @fail
subi r31, r31, 0x1000
xor r23, r8, r31
rlwinm. r23, r23, 0, 25, 22
bne @fail ; because physical pages are discontiguous
@not_straddling_pages
clrlwi r23, r31, 30
cmpwi r23, 3
rlwimi r8, r9, 0, 20, 31
beq @fail
; Found a non-cached physical address for this NCB!
lwz r23, KDP.NanoKernelInfo + NKNanoKernelInfo.NCBPtrCacheMissCount(r1)
addi r23, r23, 1
stw r23, KDP.NanoKernelInfo + NKNanoKernelInfo.NCBPtrCacheMissCount(r1)
; Stick it in cache slot 3
mfsprg r1, 0
lmw r14, EWA.r14(r1)
lwz r1, EWA.PA_KDP(r1)
stw r8, KDP.NCBCachePA3(r1)
@found_in_slot_3 ; so promote to slot 2
lwz r8, KDP.NCBCacheLA2(r1)
stw r9, KDP.NCBCacheLA2(r1)
stw r8, KDP.NCBCacheLA3(r1)
lwz r9, KDP.NCBCachePA3(r1)
lwz r8, KDP.NCBCachePA2(r1)
stw r9, KDP.NCBCachePA2(r1)
stw r8, KDP.NCBCachePA3(r1)
lwz r9, KDP.NCBCacheLA2(r1)
@found_in_slot_2 ; so promote to slot 1
lwz r8, KDP.NCBCacheLA1(r1)
stw r9, KDP.NCBCacheLA1(r1)
stw r8, KDP.NCBCacheLA2(r1)
lwz r9, KDP.NCBCachePA2(r1)
lwz r8, KDP.NCBCachePA1(r1)
stw r9, KDP.NCBCachePA1(r1)
stw r8, KDP.NCBCachePA2(r1)
lwz r9, KDP.NCBCacheLA1(r1)
@found_in_slot_1 ; so promote to slot 0, save elsewhere, and push on
lwz r8, KDP.NCBCacheLA0(r1)
stw r9, KDP.NCBCacheLA0(r1)
stw r9, KDP.LA_NCB(r1)
stw r8, KDP.NCBCacheLA1(r1)
lwz r9, KDP.NCBCachePA1(r1)
lwz r8, KDP.NCBCachePA0(r1)
stw r9, KDP.NCBCachePA0(r1)
stw r8, KDP.NCBCachePA1(r1)
b @found_physical_in_cache
@fail
mfsprg r1, 0
lmw r14, EWA.r14(r1)
lwz r1, EWA.PA_KDP(r1)
li r8, ecTrapInstr
b Exception
; > r8 = dest
; > r22 = len in bytes
; > r23 = fillword
wordfill ; OUTSIDE REFERER
subic. r22, r22, 4
stwx r23, r8, r22
bne wordfill
blr
###### #####
# # #### # # ###### #### ###### ##### # # # # #### ##### ###### # #
# # # # # # # # # # # # # # # # ## ##
#### # ###### ##### #### ##### # ##### # #### # ##### # ## #
# # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # #
# # #### # # ###### #### ###### # ##### # #### # ###### # #
; Handle a 68k reset trap.
; If A0(r3)/A1(r4) == 'Gary'/$05051955, load the register list in A3? Or is this now disabled?
; New SRR0 = SRR0 & ~r5(D0) | r7(D2)
align kIntAlign
kcResetSystem ; OUTSIDE REFERER
; r6 = ewa
bl SchSaveStartingAtR14
; r8 = sprg0 (not used by me)
; Check for 601 (rtc vs timebase)
mfpvr r9
rlwinm. r9, r9, 0, 0, 14
; This xoris/cmplwi technique is very cool
xoris r8, r3, 'Ga'
beq @is_601
mftb r9
b @endif_601
@is_601
dialect POWER
mfrtcl r9
dialect PowerPC
@endif_601
; Not sure why this would need to hit cr0?
andis. r9, r9, 0xffff
cmplwi r8, 'ry'
bne NonGaryReset
; r4 (i.e. A1) == 5 May 1956?
xoris r8, r4, 0x0505
cmplwi r8, 0x1956
bne NonGaryReset
andc r11, r11, r5
lwz r8, ContextBlock.r7(r6)
or r11, r11, r8
_log 'Skeleton key inserted at'
mr r8, r11
bl Printw
mr r8, r10
bl Printw
_log '^n'
b IntReturn
; NonGaryReset
; A 68k reset trap without Gary Davidian's magic numbers.
NonGaryReset
_log 'ResetSystem trap entered^n'
lwz r8, KDP.OldKDP(r1)
cmpwi r8, 0
beq ResetBuiltinKernel
_log 'Unplugging the replacement nanokernel^n'
lwz r8, KDP.OldKDP(r1)
mfsprg r1, 0
addi r9, r8, KDP.VecBaseSystem
mtsprg 0, r8 ; old NK has only one EWA!
mtsprg 3, r9
lwz r9, EWA.r1(r1)
stw r9, EWA.r1(r8)
lwz r9, EWA.r6(r1)
stw r9, EWA.r6(r8)
stw r6, 0x065c(r8)
stw r7, 0x0660(r8) ; ??????????
lwz r9, EWA.Enables(r1)
stw r9, 0x0664(r8)
; r6 = ewa
bl SchRestoreStartingAtR14
subi r10, r10, 4
lwz r1, -0x0004(r1)
; sprg0 = for r1 and r6
; r1 = kdp
; r6 = register restore area
; r7 = flag to insert into XER
; r10 = new srr0 (return location)
; r11 = new srr1
; r12 = lr restore
; r13 = cr restore
b SchExitInterrupt
###### ###
# # #### # # ##### # #### ##### # ##### # ###### ###### # # # ##### ###### ##### ##### # # ##### ##### ####
# # # # # # # # # # # # # # # # # # # ## # # # # # # # # # # # # #
#### # ###### # # # # # # # # # # # ##### # # # # # ##### # # # # # # # # # ####
# # # # ##### # # # ##### # # # # # # # # # # # ##### ##### # # ##### # #
# # # # # # # # # # # # # # # # # # # ## # # # # # # # # # # # #
# # #### # # # # #### # # # # # ###### ###### ### # # # ###### # # # # #### # # ####
; > r1 = kdp
kcPrioritizeInterrupts ; OUTSIDE REFERER
lwz r9, KDP.PA_InterruptHandler(r1)
mtlr r9
blr
; Move registers from CB to EWA, and Thud.
align kIntAlign
kcThud
stw r2, EWA.r2(r1)
stw r3, EWA.r3(r1)
stw r4, EWA.r4(r1)
stw r5, EWA.r5(r1)
lwz r8, ContextBlock.r7(r6)
lwz r9, ContextBlock.r8(r6)
stw r8, EWA.r7(r1)
stw r9, EWA.r8(r1)
lwz r8, ContextBlock.r9(r6)
lwz r9, ContextBlock.r10(r6)
stw r8, EWA.r9(r1)
stw r9, EWA.r10(r1)
lwz r8, ContextBlock.r11(r6)
lwz r9, ContextBlock.r12(r6)
stw r8, EWA.r11(r1)
stw r9, EWA.r12(r1)
lwz r8, ContextBlock.r13(r6)
stw r8, EWA.r13(r1)
stmw r14, EWA.r14(r1)
bl IntPanicIsland
major_0x046d0 ; OUTSIDE REFERER
bl LoadInterruptRegisters
li r8, ecTrapInstr
b Exception
### ####### #
# # # ##### # # # ##### ###### ##### # # ## # # # # ##### ###### ##### # # ## ##### ######
# ## # # # # # # # # # ## # # # # # # # # # # # ## # # # # #
# # # # # ##### ## # ##### # # # # # # # # # # # # ##### # # # # # # # # #####
# # # # # # ## # # ##### # # # ###### # ####### # # # ##### # # # ###### # #
# # ## # # # # # # # # # ## # # # # # # # # # # # ## # # # #
### # # # ####### # # # ###### # # # # # # ###### # # ###### # ###### # # # # # # # ######
; For when the alternate context is running?
align kIntAlign
IntExternalAlternate
bl LoadInterruptRegisters
mtcrf 0x3f, r7
bcl BO_IF_NOT, EWA.kFlagBlue, IntPanicIsland
li r8, ecNoException
b Exception
### ######
# # # ##### # # ##### #### #### ##### ## # #
# ## # # # # # # # # # # # # # # ## ##
# # # # # ###### # # # # # # # # # # ## #
# # # # # # ##### # # # ### ##### ###### # #
# # ## # # # # # # # # # # # # # #
### # # # # # # #### #### # # # # # #
align kIntAlign
IntProgram
bl LoadInterruptRegisters
lwz r8, KDP.LA_EmulatorKernelTrapTable(r1)
mtcr r11 ; UNUSUAL to have SRR1 in condition register
xor r8, r10, r8
bc BO_IF_NOT, 14, @not_trap
; Program interrupt caused by a trap instruction
; From the table of twis in the emulator code image? Then return will be to LR.
cmplwi cr0, r8, NanoKernelCallTable.ReturnFromException
cmplwi cr1, r8, NanoKernelCallTable.MPDispatch
beq cr0, @emutrap_0_return_from_exception
beq cr1, @emutrap_8_mpdispatch
cmplwi cr0, r8, NanoKernelCallTable.VMDispatch
cmplwi cr1, r8, NanoKernelCallTable.Size
beq cr0, @emutrap_3_vmdispatch
blt cr1, @emutrap_other
; Not from the emulator image? Return will be to next instruction,
; and we will read the trap instruction from memory
; If !MSR[IR], turn on MSR[DR] for just a moment
bc BO_IF_NOT, 26, @_IntProgram_0x58
stw r14, ContextBlock.r14(r6)
mfsprg r14, 3
addi r8, r1, PSA.VecBasePIH
mfmsr r9
mtsprg 3, r8
_bset r8, r9, 27 ; turn on data paging (MSR[DR]) for just a sec
mtmsr r8
isync
@_IntProgram_0x58
; Get the offending instruction!
lwz r8, 0(r10)
; If !MSR[IR], restore MSR
bc BO_IF_NOT, 26, @_IntProgram_0x74
isync
mtmsr r9
isync
mtsprg 3, r14
lwz r14, ContextBlock.r14(r6)
@_IntProgram_0x74
; Switch from SRR1-in-CR to Flags-in-CR
mtcr r7
; Read the bottom half of the non-emu-image trap instruction, getting trapnum*8 in r8
xoris r8, r8, 0xfff
cmplwi cr0, r8, NanoKernelCallTable.Size / 4
cmplwi cr1, r8, NanoKernelCallTable.ReturnFromException / 4
bge cr0, @trap_too_high
cmplwi cr7, r8, NanoKernelCallTable.MPDispatch / 4
cmplwi cr0, r8, NanoKernelCallTable.VMDispatch / 4
slwi r8, r8, 2
beq cr1, @nonemu_return_from_exception
beq cr7, @nonemu_mpdispatch
beq cr0, @nonemu_vmdispatch
; Fall through to some hard truths
bc BO_IF, 16, @_IntProgram_0x150
bc BO_IF, 8, @_IntProgram_0xac
bc BO_IF_NOT, 9, @_IntProgram_0x150
@nonemu_return_from_exception
@nonemu_vmdispatch
@_IntProgram_0xac
add r8, r8, r1
lwz r9, KDP.NanoKernelInfo + NKNanoKernelInfo.NanoKernelCallCounts(r8)
addi r9, r9, 1
stw r9, KDP.NanoKernelInfo + NKNanoKernelInfo.NanoKernelCallCounts(r8)
@nonemu_go
lwz r8, KDP.NanoKernelCallTable(r8)
mtlr r8
addi r10, r10, 4
rlwimi r7, r7, 27, 26, 26 ; copy EWA.kFlagBE into EWA.kFlag26
blr
@nonemu_mpdispatch
lwz r9, ContextBlock.r0(r6)
add r8, r8, r1
cmpwi r9, -1
lwz r9, KDP.NanoKernelInfo + NKNanoKernelInfo.NanoKernelCallCounts(r8)
addi r9, r9, 1
stw r9, KDP.NanoKernelInfo + NKNanoKernelInfo.NanoKernelCallCounts(r8)
bne @nonemu_go
; Non-emu MPDispatch trap with r0 == -1: muck around a bit?
addi r10, r10, 4
rlwimi r7, r7, 27, 26, 26 ; copy EWA.kFlagBE into EWA.kFlag26
mfsprg r8, 0
rlwimi r13, r7, 8, 2, 2
lwz r9, EWA.PA_CurTask(r8)
xoris r13, r13, 0x2000
lwz r8, Task.SomeLabelField(r9)
stw r8, ContextBlock.r0(r6)
b IntReturn
@emutrap_other
@_IntProgram_0x110
mtcr r7
bc BO_IF, 16, @_IntProgram_0x150
bc BO_IF, 8, @_IntProgram_0x120
bc BO_IF_NOT, 9, @_IntProgram_0x150
@emutrap_0_return_from_exception
@emutrap_8_mpdispatch
@emutrap_3_vmdispatch
@_IntProgram_0x120
add r8, r8, r1
lwz r9, KDP.NanoKernelInfo + NKNanoKernelInfo.NanoKernelCallCounts(r8)
lwz r10, KDP.NanoKernelCallTable(r8)
addi r9, r9, 1
stw r9, KDP.NanoKernelInfo + NKNanoKernelInfo.NanoKernelCallCounts(r8)
mtlr r10
mr r10, r12 ; return to whatever the emulator left in the PPC link register
rlwimi r7, r7, 27, 26, 26
blr
; Program interrupt not caused by a trap instruction: consult SRR1 bits 11-13
@not_trap
bc BO_IF+1, 12, FDPEmulateInstruction ; illegal instruction exception
bc BO_IF, 13, FDPEmulateInstruction ; privileged instruction exception
bc BO_IF, 11, @floating_point_exception ; floating point exception
@trap_too_high
@_IntProgram_0x150
rlwinm r8, r11, 17, 28, 29 ; whoa
addi r8, r8, 0x4b3
rlwnm r8, r8, r8, 28, 31
b Exception
@floating_point_exception
li r8, ecFloatException
bc BO_IF, 15, Exception ; if SRR0 points to subsequent instr
addi r10, r10, 4 ; if SRR0 points to offending instr
rlwimi r7, r7, 27, 26, 26 ; copy EWA.kFlagBE into EWA.kFlag26
b Exception
align kIntAlign
IntExternalSystem
bl LoadInterruptRegisters
; Sanity check
rlwinm. r9, r11, 0, MSR_EEbit, MSR_EEbit
beq MaskedInterruptTaken
; How many CPUs?
lwz r9, EWA.CPUBase + CPU.LLL + LLL.Freeform(r8)
lwz r9, CoherenceGroup.CpuCount(r9)
cmpwi r9, 2
; Uniprocessor machine: go straight to PIH
blt kcPrioritizeInterrupts
; Check with the CPU plugin whether this is an interprocessor interrupt
; (i.e. an alert to flag a scheduler evaluation)
bl SchSaveStartingAtR14
li r9, kSIGP9
stw r9, EWA.SIGPSelector(r8)
li r8, 1 ; args are in EWA
bl SIGP
bl SchRestoreStartingAtR14
cmpwi cr0, r8, -29278 ; real external interrupt
cmpwi cr1, r8, -29277 ; ignore
cmpwi cr2, r8, -29279 ; interprocessor interrupt!
; else: real external interrupt
beq cr0, kcPrioritizeInterrupts
beq cr1, IntReturn
bne cr2, kcPrioritizeInterrupts
mfsprg r9, 0 ; "alert" => run scheduler evaluation
li r8, 1
stb r8, EWA.SchEvalFlag(r9)
b IntReturn ; goes to SchReturn
##### ### ##### ######
# # # # # # #
# # # # #
##### # # #### ######
# # # # #
# # # # # #
##### ### ##### #
; "SIGnal Plugin": Call the CPU plugin PEF bundle synchronously.
; (blue address space but in supervisor mode without interrupts)
; ARG:
; if r8 == 0, i.e. userspace MPCpuPlugin call:
; r3 => routine selector
; executing CPU index => r3
; r4-10 => r4-10
; if r8 != 0, i.e. internal NanoKernel call:
; EWA.SIGPSelector => routine selector
; executing CPU index => r3
; PlugCallR4-10 => r4-10
; For most NK SIGPs, r4 contains the index of the CPU being operated on
align 5
SIGP
mfsprg r23, 0
mtcr r7
; r20 = offset into CPU plugin dispatch table = routine number * 4
;
lwz r16, EWA.PA_CurAddressSpace(r23)
slwi r20, r3, 2
stw r16, EWA.SIGPSpacOnResume(r23)
bc BO_IF, EWA.kFlagSIGP, IntReturnFromSIGP ; not sure about this
cmpwi cr2, r8, 0
lwz r18, EWA.SIGPSelector(r23)
beq cr2, @args_in_registers
slwi r20, r18, 2
@args_in_registers
; Check that a CPU plugin is installed and that the
; plugin dispatch table includes this command number.
lwz r22, EWA.CPUBase + CPU.LLL + LLL.Freeform(r23)
li r8, -0x7266
lwz r17, CoherenceGroup.PA_CpuPluginDesc(r22)
lwz r16, CoherenceGroup.CpuPluginSelectorCount(r22)
mr. r17, r17
beqlr
slwi r16, r16, 2
li r8, -0x7267
cmplw r20, r16
bgelr
; Save some registers in advance of this unusual "upcall".
stw r10, EWA.SIGPSavedR10(r23)
stw r11, EWA.SIGPSavedR11(r23)
stw r12, EWA.SIGPSavedR12(r23)
stw r13, EWA.SIGPSavedR13(r23)
mfxer r16
mfctr r17
stw r16, EWA.SIGPSavedXER(r23)
mflr r16
stw r17, EWA.SIGPSavedCTR(r23)
stw r16, EWA.SIGPSavedLR(r23) ; obviously this is getting revisited somewhere
stw r6, EWA.SIGPSavedR6(r23)
stw r7, EWA.SIGPSavedR7(r23)
; Change to the CPU plugin's preferred address space.
lwz r9, EWA.PA_CurAddressSpace(r23)
lwz r8, CoherenceGroup.CpuPluginSpacePtr(r22)
cmpw r9, r8
beq @noNeedToSwitchSpace
bl SchSwitchSpace
@noNeedToSwitchSpace
; Save user registers to ContextBlock (odd way to do this).
lwz r16, EWA.r1(r23)
lwz r17, EWA.r6(r23)
stw r16, ContextBlock.r1(r6)
stw r2, ContextBlock.r2(r6)
stw r3, ContextBlock.r3(r6)
stw r4, ContextBlock.r4(r6)
stw r5, ContextBlock.r5(r6)
stw r17, ContextBlock.r6(r6)
; Return address for CPU plugin code (=> twi 31, r31, 0 => kcReturnFromException)
lwz r17, KDP.LA_EmulatorKernelTrapTable + NanoKernelCallTable.ReturnFromException(r1)
; Need CPU index to look up the CPU plugin stack pointer in a table
lhz r16, EWA.CPUIndex(r23)
; MSR for CPU plugin with EE (external ints) and PR (problem state) switched off
lwz r19, PSA.UserModeMSR(r1)
slwi r16, r16, 2
rlwinm r19, r19, 0, 18, 15
; SRR0 (=> program counter) = TOC[routine_idx][first long]
; r1 (stack ptr) = stackPtrs[cpu_idx]
; r2 (RTOC) = TOC[routine_idx][second long]
lwz r8, CoherenceGroup.PA_CpuPluginTOC(r22)
lwz r9, CoherenceGroup.PA_CpuPluginStackPtrs(r22)
lwzx r20, r8, r20
lwz r18, 0(r20)
mtlr r17
mtspr srr0, r18
mtspr srr1, r19
lwzx r1, r9, r16
lwz r2, 4(r20)
; r3 (first arg) = CPU index
srwi r3, r16, 2
; Flags |= 0x8000
_bset r7, r7, EWA.kFlagSIGP
mr r16, r6
stw r7, EWA.Flags(r23)
; Not sure where this ContextBlock comes from?
addi r6, r23, -0x318
stw r6, EWA.PA_ContextBlock(r23)
beq cr2, @args_in_registers_2
;args not in registers
lwz r4, EWA.SIGPCallR4(r23)
lwz r5, EWA.SIGPCallR5(r23)
lwz r6, EWA.SIGPCallR6(r23)
lwz r7, EWA.SIGPCallR7(r23)
lwz r8, EWA.SIGPCallR8(r23)
lwz r9, EWA.SIGPCallR9(r23)
lwz r10, EWA.SIGPCallR10(r23)
; Go.
rfi
@args_in_registers_2
lwz r6, ContextBlock.r6(r16)
lwz r7, ContextBlock.r7(r16)
lwz r8, ContextBlock.r8(r16)
lwz r9, ContextBlock.r9(r16)
lwz r10, ContextBlock.r10(r16)
; Go.
rfi
major_0x04a20
mfsprg r23, 0
lwz r6, -0x0014(r23)
lwz r7, -0x0010(r23)
lwz r1, -0x0004(r23)
mfspr r10, srr0
mfspr r11, srr1
IntReturnFromSIGP
mfsprg r23, 0
lwz r7, EWA.SIGPSavedR7(r23)
andis. r8, r11, 0x0002 ; MSR bit 14??
stw r7, -0x0010(r23)
bne @msr_14_set
li r3, -29285
@msr_14_set
; Restore address space
lwz r8, EWA.SIGPSpacOnResume(r23)
lwz r9, EWA.PA_CurAddressSpace(r23)
cmpw r9, r8
beq @no_switch_space
bl SchSwitchSpace
@no_switch_space
lwz r10, EWA.SIGPSavedR10(r23)
lwz r11, EWA.SIGPSavedR11(r23)
lwz r12, EWA.SIGPSavedR12(r23)
lwz r13, EWA.SIGPSavedR13(r23)
lwz r8, EWA.SIGPSavedXER(r23)
lwz r9, EWA.SIGPSavedCTR(r23)
mtxer r8
lwz r8, EWA.SIGPSavedLR(r23)
lwz r6, EWA.SIGPSavedR6(r23)
mtctr r9
stw r6, EWA.PA_ContextBlock(r23)
mtlr r8
mr r8, r3
mr r9, r4
lwz r16, ContextBlock.r1(r6)
lwz r2, ContextBlock.r2(r6)
lwz r3, ContextBlock.r3(r6)
lwz r4, ContextBlock.r4(r6)
lwz r5, ContextBlock.r5(r6)
lwz r17, ContextBlock.r6(r6)
stw r16, EWA.r1(r23)
stw r17, EWA.r6(r23)
blr
### #####
# # # ##### # # # # #### #### ## # #
# ## # # # # # # # # # # # #
# # # # # ##### # #### # # # # #
# # # # # # # # # ###### # #
# # ## # # # # # # # # # # # #
### # # # ##### # #### #### # # ###### ######
; IntSyscall
; Not fully sure about this one
IntSyscall ; OUTSIDE REFERER
; Only r1 and LR have been saved, so these compares clobber cr0
cmpwi r0, -3
bne @not_minus_3
; sc -3: used by FDP to go back to supervisor mode after instruction emulation.
; For security reasons, FDP goes into user mode when it emulates loads and stores.
; This is how it goes back into supervisor mode afterwards. During instruction emulation
; it has data paging on, but keeps instruction paging off. User Mode code never has instruction
; paging disabled, so this is not a privilege escalation.
; unset MSR_PR bit
mfspr r1, srr1
rlwinm. r0, r1, 26, 26, 27 ;move MSR_IR bit to sign bit (and a few others that don't matter)
_bclr r1, r1, 17
blt @not_in_FDP ; only do if MSR_IR = 0 (MSR_IR is sign bit, so it is < 0 if it is true)
mtspr srr1, r1
@not_in_FDP
; restore LR from SPRG2, r1 from SPRG1
mfsprg r1, 2
mtlr r1
mfsprg r1, 1
rfi
@not_minus_3
cmpwi r0, -1
mfsprg r1, 0
bne @not_minus_1
; sc -1: quick-test whether "this task" is blue (cr0.eq if not blue)
lwz r0, EWA.Flags(r1)
mfsprg r1, 2
rlwinm. r0, r0, 0, EWA.kFlagBlue, EWA.kFlagBlue
mtlr r1
mfsprg r1, 1
rfi
@not_minus_1
cmpwi r0, -2
bne @not_any_special
; sc -2: more flag nonsense?
lwz r0, EWA.Flags(r1)
lwz r1, -0x0008(r1)
rlwinm. r0, r0, 0, 10, 10
lwz r0, 0x00ec(r1)
mfsprg r1, 2
mtlr r1
mfsprg r1, 1
rfi
@not_any_special
; Positive numbered syscalls are a fast path to MPDispatch (twi 31, r31, 8)
bl LoadInterruptRegisters ; Save the usual suspects and get comfy
lwz r9, KDP.NanoKernelInfo + NKNanoKernelInfo.NanoKernelCallCounts + 32(r1)
addi r9, r9, 1
stw r9, KDP.NanoKernelInfo + NKNanoKernelInfo.NanoKernelCallCounts + 8*4(r1)
; Not sure what to make of these
_bset r11, r11, 14
rlwimi r7, r7, 27, 26, 26
b kcMPDispatch
### #######
# # # ##### # ##### ## #### ######
# ## # # # # # # # # # #
# # # # # # # # # # # #####
# # # # # # ##### ###### # #
# # ## # # # # # # # # #
### # # # # # # # # #### ######
align kIntAlign
IntTrace ; OUTSIDE REFERER
bl LoadInterruptRegisters
li r8, ecInstTrace
b Exception
### ##### ###
# #### # # #### ##### ###### # # #### ###### ##### # # ## ##### ###### # # # #####
# # # ## # # # # # # # # # # # # # # # # # # # ## # #
# # # # # # # # # ##### ##### # # ##### # # # # # # # ##### # # # # #
# # ### # # # # # ##### # # # # # # # ## # ###### ##### # # # # # #
# # # # ## # # # # # # # # # # # ## ## # # # # # # # ## #
### #### # # #### # # ###### ##### #### # # # # # # # # ###### ### # # #
align kIntAlign
IgnoreSoftwareInt ; OUTSIDE REFERER
mfspr r1, srr0
addi r1, r1, 0x04
mtspr srr0, r1
mfsprg r1, 2
mtlr r1
mfsprg r1, 1
rfi
dcb.b 32, 0
# # ###### # # ###
# # ## # # ##### # ###### # # ###### ##### ###### ## ## #### # # # ##### #### ##### # # # #####
# # # # ## # # # # # # # # # # # # # # # # # ## # # # # # # # # ## # #
####### # # # # # # # # ##### ###### ##### # # ##### # # # # # # # # # # # # # # # # # # #
# # ###### # # # # # # # # # ##### # # # # # # # # # # # # ##### # # # # #
# # # # # ## # # # # # # # # # # # # # # ## # # # # # # # # ## #
# # # # # # ##### ###### ###### # ###### # # # # # #### # # # # #### # # ### # # #
align kIntAlign
HandlePerfMonitorInt ; OUTSIDE REFERER
mfspr r1, srr1
oris r1, r1, 0x200
mtspr srr1, r1
mfsprg r1, 2
mtlr r1
mfsprg r1, 1
rfi
dcb.b 32, 0