###### ### ###### ## ## ######## ###### ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ######### ###### ## ## ## ## ## ## ######### ## ## ## ## ## ######### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ## ## ###### ## ## ######## ###### ## ## ######## ######## ; Enable/disable/probe the L1/2 data/inst cache ; Probably called using an unknown 68k F-trap. Not usually called on my ; G4, but can be tested by hacking the MPCall table. Uses fancy new CPU ; features (MSSCR0), so probably not legacy code. For CPU accelerator ; cards? `FlushCache` needs to be nopped out to prevent a crash. ; ARGUMENT (r3) ; r3.hi = action flags ; enable specified caches $8000 ; disable specified caches $4000 ; report pre-change state $2000 ; also enable (???) $1000 ; enable/disable I-cache $0800 ; enable/disable D-cache $0400 ; ; r3.lo = which cache (L1/2) ; level 1 1 ; level 2 2 ; ; RETURN VALUE (r3) ; r3.hi = pre-change state flags (resemble action flags) ; both caches disabled $4000 ; either cache enabled $8000 ; I-cache enabled $0800 ; D-cache enabled $0400 ; ; r3.lo = return status ; success 0 ; failure < 0 ; checked L1 but did not set 1 ; checked L2 but did not set 2 ; AUTO-GENERATED SYMBOL LIST ; IMPORTS: ; NKInterrupts ; IntReturn ; EXPORTS: ; FlushCaches (=> NKPowerCalls) ; FlushL1CacheUsingMSSCR0 (=> NKInterrupts) ; kcCacheDispatch (=> NKInit) ; DeclareMPCall 199, kcCacheDispatch ; DEBUG kcCacheDispatch _RegRangeToContextBlock r21, r23 ; get some breathing room ; _log 'kcCacheDispatch ' ; DEBUG ; mr r8, r3 ; DEBUG ; bl printw ; DEBUG ; _log '^n' ; DEBUG clrlwi r8, r3, 16 ; bad selector cmplwi r8, 2 bgt @fail_bad_selector lwz r8, KDP.ProcessorInfo + NKProcessorInfo.ProcessorFlags(r1) andi. r8, r8, 1 << NKProcessorInfo.hasL2CR beq CacheCallFailNoL2 ; no L2CR => fail (what about 601?) rlwinm. r9, r3, 0, 2, 2 ; if flagged, get cache state in r23 bnel CacheCallGetInfoForReturnValue ; (otherwise, r23 is undefined) srwi r8, r3, 30 ; cannot enable *and* disable cmpwi r8, 3 beq CacheCallFailBadFlags clrlwi r8, r3, 16 ; go to main code for level 1/2 cache cmplwi r8, 1 beq CacheCallDispatchL1 cmplwi r8, 2 beq CacheCallDispatchL2 @fail_bad_selector ; fall through => bad selector lisori r3, -2 b CacheCallReturn ### ## ## ### ## ## #### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ### ######## ###### ### CacheCallDispatchL1 rlwinm. r9, r3, 0, 1, 1 bne CacheCallL1DisableSelected rlwinm. r9, r3, 0, 0, 0 bne CacheCallL1EnableSelected rlwinm. r9, r3, 0, 3, 3 ; ??? bl FlushCaches b CacheCallReturn CacheCallL1DisableSelected bl FlushCaches rlwinm r22, r3, 0, 4, 5 ; shift arg bits to align with HID0[DCE/ICE] srwi r22, r22, 12 mfspr r21, hid0 andc r21, r21, r22 ; HID0 &= ~mybits sync mtspr hid0, r21 li r3, 0 b CacheCallReturn CacheCallL1EnableSelected rlwinm r22, r3, 0, 4, 5 ; shift arg bits to align with HID0[DCE/ICE] srwi r22, r22, 12 mfspr r21, hid0 or r21, r21, r22 ; HID0 |= mybits sync mtspr hid0, r21 li r3, 0 b CacheCallReturn ### ## ####### ### ## ## ## ## ## ## ## ## ## ## ## ####### ## ## ## ## ## ## ## ## ## ### ######## ######### ### CacheCallDispatchL2 rlwinm. r9, r3, 0, 1, 1 bne CacheCallL2DisableSelected rlwinm. r9, r3, 0, 0, 0 bne CacheCallL2EnableSelected rlwinm. r9, r3, 0, 3, 3 bne CacheCallL2Flag3 ; goes to DisableSelected rlwinm. r9, r3, 0, 2, 2 ;bne removed? bne CacheCallReturn CacheCallFailBadFlags lisori r3, -4 b CacheCallReturn CacheCallL2Flag3 bl CacheCallL2DisableSelected ; typo? should be `b` CacheCallL2EnableSelected mfspr r21, l2cr ; fail if L2CR[L2E] already set sync andis. r21, r21, 0x8000 bne CacheCallReturn lwz r8, KDP.ProcessorInfo + NKProcessorInfo.ProcessorL2DSize(r1) and. r8, r8, r8 beq CacheCallFailNoL2 ; fail if zero-sized cache reported mfspr r21, hid0 ; save HID0 rlwinm r8, r21, 0, 12, 10 ; clear HID0[DPM] (dynamic power management) mtspr hid0, r8 ; presumably to keep L2 working while we wait? sync addi r8, r1, PSA.ProcessorState lwz r8, NKProcessorState.saveL2CR(r8) and. r8, r8, r8 beq CacheCallReturn ; fail if zero L2CR was saved? sync lis r9, 0x0020 ; set L2CR[GI] (global invalidate) or r8, r8, r9 mtspr l2cr, r8 sync @inval_loop mfspr r8, l2cr ; check L2CR[IP] (invalidate progress) sync andi. r9, r8, 1 bne @inval_loop lis r9, 0x0020 ; clear L2CR[GI] andc r8, r8, r9 mtspr l2cr, r8 sync lis r9, 0x8000 ; set L2CR[L2E] (L2 enable) or r8, r8, r9 mtspr l2cr, r8 sync mtspr hid0, r21 ; restore HID0 sync li r3, 0 ; return successfully b CacheCallReturn CacheCallFailNoL2 li r3, -2 b CacheCallReturn CacheCallL2DisableSelected mfspr r22, l2cr ; return if already disabled per L2CR[L2E] sync andis. r22, r22, 0x8000 beq CacheCallReturn bl FlushCaches mfspr r22, l2cr ; clear L2CR[L2E] sync clrlwi r22, r22, 1 mtspr l2cr, r22 sync addi r8, r1, PSA.ProcessorState stw r22, NKProcessorState.saveL2CR(r8) ; update saveL2CR sync rlwinm r22, r22, 0, 7, 3 ; clear L2CR[3/5/6] (all reserved) oris r22, r22, 0x0010 ; set L2CR[13] (also reserved) mtspr l2cr, r22 sync ;b CacheCallReturn ; fall through ### ######## ######## ######## ## ## ######## ## ## ### ## ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## ## ## ## ## #### ## ## ## ######## ###### ## ## ## ######## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ## ## ## ## ## ## ## ## ## ### ## ### ## ## ######## ## ####### ## ## ## ## ### CacheCallReturn ori r23, r23, 0xffff ; put the r23.hi from CacheCallGetInfoForReturnValue into r3.hi oris r3, r3, 0xffff and r3, r3, r23 CacheCallReturnWithoutFlags _RegRangeFromContextBlock r21, r23 sync ; _log 'Return ' ; DEBUG ; mr r8, r3 ; DEBUG ; bl printw ; DEBUG ; _log '^n' ; DEBUG b IntReturn ### ######## ######## ####### ######## ######## ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ######## ######## ## ## ######## ###### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ### ## ## ## ####### ######## ######## ### ; RET r23.hi = flags describing state of specified cache (see top of file) CacheCallGetInfoForReturnValue clrlwi r8, r3, 16 cmplwi r8, 1 beq @level1 cmplwi r8, 2 beq @level2 lisori r3, -5 b CacheCallReturnWithoutFlags @level1 mfspr r21, hid0 rlwinm. r21, r21, 12, 4, 5 beq @all_off oris r23, r21, 0x8000 blr @level2 lwz r8, KDP.ProcessorInfo + NKProcessorInfo.ProcessorL2DSize(r1) and. r8, r8, r8 beq CacheCallFailNoL2 mfspr r21, hid0 ; same bits as above rlwinm r21, r21, 12, 4, 5 mfspr r22, l2cr ; L2-D is on if L1-D is on and L2CR[DO] is cleared rlwinm r22, r22, 5, 4, 4 andc r21, r21, r22 mfspr r22, l2cr ; then again, both L2s are off if L2CR[L2E] is cleared andis. r22, r22, 0x8000 beq @all_off or r23, r21, r22 blr @all_off lisori r23, 0x40000000 blr ######## ## ## ## ###### ## ## ######## ## ## ## ## ###### ###### ## ## ## ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ## ###### ## ## ## ###### ######### ###### ## ## ## ## ## ## ###### ## ## ## ## ## ## ## ## ## ## ## #### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ### ## ## ## ## ## ######## ####### ###### ## ## ## ####### ## ## ###### ###### ; Flush L1 and L2 caches ; Also used by NKPowerCalls.s ; ARG KDP *r1, ContextBlock *r6 ; CLOB r8, r9, cr FlushCaches ; blr ; DEBUG ; Be cautious mfctr r8 stw r25, ContextBlock.r25(r6) stw r24, ContextBlock.r24(r6) stw r8, ContextBlock.KernelCTR(r6) ; Flush level 1 lhz r25, KDP.ProcessorInfo + NKProcessorInfo.DataCacheLineSize(r1) and. r25, r25, r25 ; r25 = L1-D line size cntlzw r8, r25 beq @return subfic r9, r8, 31 ; r9 = logb(L1-D line size) lwz r8, KDP.ProcessorInfo + NKProcessorInfo.DataCacheTotalSize(r1) and. r8, r8, r8 ; r8 = L1-D size beq @return lwz r24, KDP.ProcessorInfo + NKProcessorInfo.ProcessorFlags(r1) mtcr r24 bc BO_IF, 31 - NKProcessorInfo.hasMSSregs, @use_SPRs_to_invalidate ; => go away to handle weird CPUs bc BO_IF_NOT, 31 - NKProcessorInfo.hasPLRUL1, @no_pseudo_lru slwi r24, r8, 1 add r8, r8, r24 srwi r8, r8, 1 ; be generous with pseudo-LRU caches @no_pseudo_lru srw r8, r8, r9 mtctr r8 ; loop counter = cache/line lwz r8, KDP.PA_ConfigInfo(r1) ; fill the cache with Mac ROM lwz r9, NKConfigurationInfo.ROMImageBaseOffset(r8) add r8, r8, r9 @loop_L1 lwzux r9, r8, r25 bdnz @loop_L1 ; Flush level 2 (very similar to above) lwz r24, KDP.ProcessorInfo + NKProcessorInfo.ProcessorFlags(r1) andi. r24, r24, 1 << NKProcessorInfo.hasL2CR beq @return ; return if L2CR unavailable mfspr r24, l2cr andis. r24, r24, 0x8000 beq @return ; return if L2 off (per L2CR[L2E]) lhz r25, KDP.ProcessorInfo + NKProcessorInfo.ProcessorL2DBlockSize(r1) and. r25, r25, r25 ; r25 = L2-D line size cntlzw r8, r25 beq @return subfic r9, r8, 31 ; r9 = logb(L2-D line size) lwz r8, KDP.ProcessorInfo + NKProcessorInfo.ProcessorL2DSize(r1) and. r8, r8, r8 ; r8 = L2-D size beq @return srw r8, r8, r9 mtctr r8 ; loop counter = cache/line mfspr r24, l2cr ; set L2CR[DO] (disables L2-I) oris r24, r24, 0x0040 mtspr l2cr, r24 isync lwz r8, KDP.PA_ConfigInfo(r1) ; fill the cache with Mac ROM lwz r9, NKConfigurationInfo.ROMImageBaseOffset(r8) add r8, r8, r9 addis r8, r8, 0x19 ; start high in ROM and count backwards neg r25, r25 @loop_L2 lwzux r9, r8, r25 bdnz @loop_L2 rlwinm r24, r24, 0, 10, 8 mtspr l2cr, r24 ; clear L2CR[DO] (reenables L2-I) isync ; Done (this return path is also called from the sneaky code below) @return lwz r8, ContextBlock.KernelCTR(r6) lwz r25, ContextBlock.r25(r6) lwz r24, ContextBlock.r24(r6) sync mtctr r8 blr ; If "hasMSSregs" flag (my name) is set in ProcessorFlags, L1 and L2 can ; instead be flushed by clobbering reserved bits in MSSCR0 and L2CR ; respectively. @use_SPRs_to_invalidate ; Flush level 1: set MSSCR0[8] and spin until it clears dssall ; AltiVec needs to know sync mfspr r8, msscr0 oris r8, r8, 0x0080 mtspr msscr0, r8 sync @loop_msscr0 mfspr r8, msscr0 sync andis. r8, r8, 0x0080 bne @loop_msscr0 ; Flush level 2: set L2CR[4] and spin until it clears mfspr r8, l2cr ori r8, r8, 0x0800 mtspr l2cr, r8 sync @loop_l2cr mfspr r8, l2cr sync andi. r8, r8, 0x0800 bne @loop_l2cr ; Jump back up to main code path to return b @return ; Called when we cop a machine check with the "L1 data cache error" ; flag set in SRR1, followed by an interrupt return. Same trick as ; above. ; CLOB r8, cr FlushL1CacheUsingMSSCR0 ; Return if MSSCR0 unavailable lwz r8, KDP.ProcessorInfo + NKProcessorInfo.ProcessorFlags(r1) mtcr r8 bclr BO_IF_NOT, 31-NKProcessorInfo.hasMSSregs ; Flush level 1: set MSSCR0[8] and spin until it clears dssall ; AltiVec needs to know sync mfspr r8, msscr0 oris r8, r8, 0x0080 mtspr msscr0, r8 sync @loop_msscr0 mfspr r8, msscr0 sync andis. r8, r8, 0x0080 bne @loop_msscr0 blr