mirror of
https://github.com/elliotnunn/powermac-rom.git
synced 2024-05-28 22:41:35 +00:00
532 lines
20 KiB
ArmAsm
532 lines
20 KiB
ArmAsm
; Code to populate the PowerPC "HTAB"/"Hash Table"
|
|
|
|
########################################################################
|
|
|
|
PutPTE ; EA r27 // PTE r30/r31, EQ=Success, GT=Invalid, LT=Fault
|
|
; 1. Find which Segment and PMDT cover this Effective Address
|
|
lwz r29, KDP.CurMap.SegMapPtr(r1)
|
|
rlwinm r28, r27, 7, 0x0000000F << 3 ; get offset into SegMap based on EA
|
|
lwzx r29, r29, r28 ; r29 is now our iterating PMDT ptr
|
|
rlwinm r28, r27, 20, 0x0000FFFF ; r27 = page index within Segment
|
|
lhz r30, 0(r29) ; get first PMDT.PageIdx
|
|
b @find_pmdt
|
|
@next_pmdt
|
|
lhzu r30, 8(r29) ; get next PMDT.PageIdx
|
|
@find_pmdt
|
|
lhz r31, PMDT.PageCount(r29)
|
|
subf r30, r30, r28
|
|
cmplw cr7, r30, r31
|
|
bgt cr7, @next_pmdt ; Save "found PMDT pointer" in r29, "page index within PMDT" in r30
|
|
|
|
; 2. Parse the PMDT into a PTE (three major code paths)
|
|
lwz r28, KDP.HtabSinglePTE(r1)
|
|
lwz r31, PMDT.Word2(r29)
|
|
cmpwi cr7, r28, 0 ; always delete the previous PMDT_PTE_Single entry from the HTAB
|
|
extlwi. r26, r31, 2, 20 ; use the Cond Reg to branch on Pattr_NotPTE/Pattr_PTE_Single
|
|
bne cr7, @del_single_pte
|
|
blt @paged ; PMDT_Paged is the probable meaning of Pattr_NotPTE (will return to @parsed_pmdt)
|
|
@did_del_single_pte ; (optimized return: if LT then @del_single_pte falls thru to @paged)
|
|
bgt @single_pte ; PMDT_PTE_Single is the probable meaning of Pattr_PTE_Single (will return to @parsed_pmdt)
|
|
slwi r28, r30, 12 ; PMDT_PTE_Range is likely otherwise, requiring us to add an offset to the PMDT
|
|
add r31, r31, r28
|
|
@parsed_pmdt ; Save draft PTE in r31 (points to actual page, has PTE-style flags), and r26 =
|
|
; 0 (if PMDT_PTE_Range)
|
|
; 0x5A5A (if PMDT_PTE_Single)
|
|
; PageListEntry ptr (if PMDT_Paged)
|
|
|
|
; 3. Find free slot in HTAB for new entry
|
|
mfsrin r30, r27
|
|
rlwinm r28, r27, 26, 10, 25 ; r28 = (1st arg of XOR) * 64b
|
|
rlwinm r30, r30, 6, 7, 25 ; r30 = (2nd arg of XOR) * 64b
|
|
xor r28, r28, r30 ; r28 = (hash output) * 64b = r28 ^ r30
|
|
lwz r30, KDP.PTEGMask(r1)
|
|
lwz r29, KDP.HTABORG(r1)
|
|
and r28, r28, r30
|
|
or. r29, r29, r28 ; r29 = PTEG pointer (clear CR0.EQ here so that @pteg_full knows we are trying primary hash)
|
|
|
|
@try_secondary_pteg ; @pteg_full jumps here to try sec'dary hash
|
|
lwz r30, 0(r29) ; Find "invalid" (bit 0 clear) PTE (optimized!)
|
|
lwz r28, 8(r29)
|
|
cmpwi cr6, r30, 0
|
|
lwz r30, 16(r29)
|
|
cmpwi cr7, r28, 0
|
|
lwzu r28, 24(r29)
|
|
bge cr6, @found_free_pte
|
|
cmpwi cr6, r30, 0
|
|
lwzu r30, 8(r29)
|
|
bge cr7, @found_free_pte
|
|
cmpwi cr7, r28, 0
|
|
lwzu r28, 8(r29)
|
|
bge cr6, @found_free_pte
|
|
cmpwi cr6, r30, 0
|
|
lwzu r30, 8(r29)
|
|
bge cr7, @found_free_pte
|
|
cmpwi cr7, r28, 0
|
|
lwzu r28, 8(r29)
|
|
bge cr6, @found_free_pte
|
|
cmpwi cr6, r30, 0
|
|
addi r29, r29, 8
|
|
bge cr7, @found_free_pte
|
|
cmpwi cr7, r28, 0
|
|
addi r29, r29, 8
|
|
bge cr6, @found_free_pte
|
|
rlwinm r28, r31, 0, 26, 26 ; wImg bit in PTE???
|
|
addi r29, r29, 8
|
|
blt cr7, @pteg_full ; @pteg_full *may* return to @try_secondary_pteg
|
|
@found_free_pte ; Save PTE ptr + 24 in r29
|
|
|
|
; 4. Save the new PTE and return
|
|
cmpwi r26, 0
|
|
mfsrin r28, r27
|
|
extrwi r30, r27, 6, 4 ; PTE[26-31=API] = high 6 bits of offset-within-segment
|
|
stw r27, KDP.HtabLastEA(r1)
|
|
ori r31, r31, 0x100 ; set PTE[R(eference)]
|
|
rlwimi r30, r31, 27, 25, 25 ; set PTE[H(ash func ID)] to cheeky topmost bit of the phys addr in r31
|
|
rlwinm r31, r31, 0, 21, 19 ; unset upper reserved bit in PTE[lo]
|
|
insrwi r30, r28, 24, 1 ; get PTE[VSID] from segment register
|
|
stw r31, -20(r29) ; PTE[lo] = r31
|
|
oris r30, r30, 0x8000 ; set PTE[V(alid)]
|
|
sync ; because we just wanged the page table
|
|
stwu r30, -24(r29) ; PTE[hi] = r30
|
|
|
|
lwz r28, KDP.NKInfo.HashTableCreateCount(r1)
|
|
stw r29, KDP.HtabLastPTE(r1)
|
|
addi r28, r28, 1
|
|
stw r28, KDP.NKInfo.HashTableCreateCount(r1)
|
|
|
|
beqlr ; PMDT_PTE_Range: return success (EQ)
|
|
|
|
cmpwi r26, 0x5A5A
|
|
bne @ret_notsingle ; PMDT_PTE_Single:
|
|
stw r29, KDP.HtabSinglePTE(r1) ; save ptr to this ephemeral PTE
|
|
cmpw r29, r29 ; return success (EQ)
|
|
blr
|
|
@ret_notsingle
|
|
|
|
lwz r28, 0(r26) ; PMDT_PTE_PageList:
|
|
lwz r30, KDP.HTABORG(r1)
|
|
ori r28, r28, 0x801 ; Set PLE RealPgNum field to point to the PTE it now owns
|
|
subf r30, r30, r29 ; and set flags 20/31
|
|
cmpw r29, r29
|
|
rlwimi r28, r30, 9, 0xFFFFF000
|
|
stw r28, 0(r26)
|
|
blr ; return success (EQ)
|
|
|
|
@del_single_pte ; Delete the PTE most recently created from a PMDT_PTE_Single entry.
|
|
lwz r28, KDP.NKInfo.HashTableDeleteCount(r1)
|
|
lwz r29, KDP.HtabSinglePTE(r1)
|
|
addi r28, r28, 1
|
|
stw r28, KDP.NKInfo.HashTableDeleteCount(r1)
|
|
li r28, 0
|
|
stw r28, 0(r29)
|
|
lwz r29, KDP.HtabSingleEA(r1)
|
|
stw r28, KDP.HtabSingleEA(r1)
|
|
stw r28, KDP.HtabSinglePTE(r1)
|
|
sync
|
|
tlbie r29
|
|
sync
|
|
bge @did_del_single_pte ; Optimization: would otherwise branch to a "blt @par"
|
|
|
|
@paged ; Probably PMDT_Paged
|
|
; r30 = page index within area, r31 = RPN
|
|
extlwi. r28, r31, 2, 21 ; Put remaining two flags into top bits and set Cond Reg
|
|
bge @not_actually_pagelist ; Not PMDT_Paged! (e.g. PMDT_InvalidAddress/PMDT_Available)
|
|
|
|
rlwinm r28, r30, 2, 0xFFFFFFFC ; page index in segment * 4
|
|
rlwinm r26, r31, 22, 0xFFFFFFFC ; ptr to first PLE belonging to this segment
|
|
lwzux r28, r26, r28 ; r26 = PLE ptr, r28 = PLE
|
|
|
|
lwz r31, KDP.PageAttributeInit(r1)
|
|
andi. r30, r28, M68pdInHTAB | M68pdSupProtect | M68pdResident
|
|
rlwimi r31, r28, 0, 0xFFFFF000
|
|
cmplwi r30, M68pdResident
|
|
cmplwi cr7, r30, M68pdSupProtect | M68pdResident
|
|
|
|
ori r31, r31, LpteReference
|
|
_mvbit r31, bLpteChange, r28, bM68pdModified
|
|
_mvbit r31, bLpteInhibcache, r28, bM68pdCacheinhib
|
|
_mvbit r31, bLpteWritethru, r28, bM68pdCacheNotIO
|
|
xori r31, r31, LpteWritethru
|
|
_mvbit r31, bLpteP1, r28, bM68pdWriteProtect
|
|
|
|
beq @parsed_pmdt ; if resident but outside HTAB, put in HTAB
|
|
bltlr cr7 ; if no flags, return invalid (GT)
|
|
bl CrashPageTable ; crash hard in any other case
|
|
|
|
@single_pte ; PMDT_PTE_Single
|
|
ori r28, r27, 0xfff ; r27 = EA, r31 = PMDT (low word, RPN)
|
|
stw r28, KDP.HtabSingleEA(r1)
|
|
rlwinm r31, r31, 0, ~(Pattr_NotPTE | Pattr_PTE_Single) ; clear the flag that got us here, leaving none
|
|
li r26, 0x5A5A ; so that KDP.HtabSinglePTE gets set and we return correctly
|
|
b @parsed_pmdt ; RTS with r26 = 0x5A5A and r31 having flags cleared
|
|
|
|
@not_actually_pagelist ; Pattr_NotPTE set, but not PMDT_Paged
|
|
bgtlr ; PMDT_InvalidAddress/PMDT_Available: return invalid (GT)
|
|
addi r29, r1, KDP.SupervisorMap
|
|
b SetMap ; 800 (unknown) -> SetMap returns success (EQ)
|
|
|
|
@pteg_full ; Try the secondary hashing function, if we haven't already
|
|
cmplw cr6, r28, r26 ; r26 is as set by PMDT interpretation, r28 = bit 26 of draft PTE r31
|
|
subi r29, r29, 64 + 16 ; Make r29 the actual PTEG ptr (PTE search code is very tight)
|
|
ble cr6, @both_ptegs_full ; Not sure why r26/r28 could force the sec hash to be skipped...
|
|
|
|
crnot cr0_eq, cr0_eq ; Flip everything (CR0.EQ means "secondary")
|
|
lwz r30, KDP.PTEGMask(r1)
|
|
xori r31, r31, 0x800 ; Flip PTE bit 20 to signify sec hash func (or back to primary if failing)
|
|
xor r29, r29, r30 ; Flip r29 into the sec PTEG ptr (or back to primary if failing)
|
|
beq @try_secondary_pteg ; Go back in with CR0.EQ set this time (or fall through...)
|
|
; On fallthru, r29 = prim PTEG ptr
|
|
|
|
@both_ptegs_full ; So choose a slot in this PTEG to overflow
|
|
lwz r26, KDP.HtabLastOverflow(r1) ; this could be zero
|
|
crclr cr6_eq ; cr6.eq means "hell, we're desperate"
|
|
rlwimi r26, r29, 0, 0xFFFFFFC0 ; r26 points to the PTE we should try to protext from overflow
|
|
addi r29, r26, 8 ; r29 points to the following PTE (gets clobbered straight away)
|
|
b @first_pte
|
|
@redo_search
|
|
bne cr6, @nomr
|
|
mr r26, r29
|
|
@nomr
|
|
@next_pte
|
|
cmpw cr6, r29, r26
|
|
addi r29, r29, 8
|
|
@first_pte
|
|
rlwimi r29, r26, 0, 0xFFFFFFC0
|
|
lwz r31, 4(r29)
|
|
lwz r30, 0(r29)
|
|
beq cr6, @got_pte
|
|
rlwinm r28, r31, 30, 25, 25
|
|
andc. r28, r28, r30 ; Protect if R && !H (i.e. page has been ref'd and primary-hash)
|
|
bne @next_pte ; But otherwise, or if we're desperate, then kick this PTE out!
|
|
@got_pte
|
|
|
|
; Left side: protect PP2=0, KDP and CB from overflow
|
|
clrlwi r28, r31, 30
|
|
cmpwi cr7, r28, 0
|
|
clrrwi r28, r31, 12
|
|
cmpw r28, r1
|
|
lwz r30, KDP.ContextPtr(r1)
|
|
beq cr7, @redo_search ; if PP1=0
|
|
addi r31, r30, CB.Size-1
|
|
beq @redo_search ; KDP
|
|
|
|
rlwinm r30, r30, 0, 0xFFFFF000
|
|
cmpwi cr7, r28, 30
|
|
lwz r30, 0(r29)
|
|
rlwinm r31, r31, 0, 0xFFFFF000
|
|
cmpwi r28, 31
|
|
rlwinm r31, r30, 0, 0x00000040 ; To do with below?
|
|
beq cr7, @redo_search
|
|
extlwi r28, r30, 4, 1
|
|
beq @redo_search
|
|
|
|
; Okay... now do the dirty job of actually overflowing a PTEG (the one at r29)
|
|
; (this may well mean tweaking a PLE or even a PMDT)
|
|
neg r31, r31 ; Inscrutable... extracting PMDT offset?
|
|
insrwi r28, r30, 6, 4
|
|
xor r31, r31, r29
|
|
rlwimi r28, r30, 5, 10, 19
|
|
rlwinm r31, r31, 6, 10, 19
|
|
xor r28, r28, r31
|
|
lwz r26, KDP.CurMap.SegMapPtr(r1)
|
|
rlwinm r30, r28, 7, 0x00000078
|
|
|
|
lwzx r26, r26, r30 ; Hell, get a segment pointer
|
|
|
|
@oflow_next_pmdt ; find the last non-blank PMDT in the segment
|
|
lhz r30, PMDT.PageIdx(r26)
|
|
rlwinm r31, r28, 20, 0x0000FFFF
|
|
subf r30, r30, r31
|
|
lhz r31, PMDT.PageCount(r26)
|
|
addi r26, r26, 8
|
|
cmplw cr7, r30, r31
|
|
lwz r31, PMDT.Word2 - 8(r26)
|
|
andi. r31, r31, EveryPattr
|
|
cmpwi r31, PMDT_Available
|
|
bgt cr7, @oflow_next_pmdt ; addr not in this PMDT -> try other PMDT
|
|
beq @oflow_next_pmdt ; not PMDT_Available -> try other PMDT
|
|
|
|
lwz r26, PMDT.Word2 - PMDT.Size(r26) ; If PMDT_Paged then we must wang the PLE pre-return
|
|
slwi r30, r30, 2 ; (r30 = PLE offset relative to first PLE in segment)
|
|
extrwi r31, r26, 2, 20
|
|
cmpwi cr7, r31, PMDT_Paged >> 10 ; (save that little tidbit in cr7)
|
|
|
|
lwz r31, KDP.NKInfo.HashTableOverflowCount(r1)
|
|
stw r29, KDP.HtabLastOverflow(r1)
|
|
addi r31, r31, 1
|
|
stw r31, KDP.NKInfo.HashTableOverflowCount(r1)
|
|
lwz r31, KDP.NKInfo.HashTableDeleteCount(r1)
|
|
stw r30, 0(r29) ; Very clever: save an "invalid" value in PTE then redo search
|
|
addi r31, r31, 1
|
|
stw r31, KDP.NKInfo.HashTableDeleteCount(r1)
|
|
|
|
sync ; Clear the page from TLB because it could get moved
|
|
tlbie r28
|
|
sync
|
|
|
|
_clrNCBCache scr=r28 ; Also clobber NCB cache if page could get moved
|
|
|
|
bne cr7, PutPTE ; Is this page in a paged area, with a 68k Page Descriptor?
|
|
rlwinm r26, r26, 22, 0xFFFFFFFC ; r26 = RPN * 4
|
|
lwzux r28, r26, r30 ; (the 68k-PD to edit)
|
|
lwz r31, 4(r29) ; (extract some info from the lower PTE before discarding)
|
|
andi. r30, r28, M68pdInHTAB ; Crash if this PLE wasn't marked as HTAB'd!
|
|
rlwinm r30, r28, 32-9, 0x007FFFF8
|
|
xor r30, r30, r29 ; Crash if this 68k-PD's pointer didn't match this PTE!
|
|
beq CrashPageTable
|
|
andi. r30, r30, 0xffff
|
|
xori r28, r28, M68pdInHTAB ; Edit the 68k-PD's HTAB flag, physical ptr, and "usage" flags
|
|
bne CrashPageTable
|
|
rlwimi r28, r31, 0, 0xFFFFF000
|
|
_mvbit r28, bM68pdModified, r31, bLpteChange
|
|
_mvbit r28, bM68pdUsed, r31, bLpteReference
|
|
stw r28, 0(r26) ; Save edited 68k-PD
|
|
|
|
b PutPTE ; PTEG overflow complete. Redo PutPTE!
|
|
|
|
########################################################################
|
|
|
|
SetMap ; MemMap r29
|
|
lwz r28, MemMap.SegMapPtr(r29)
|
|
stw r28, KDP.CurMap.SegMapPtr(r1)
|
|
addi r28, r28, 16*8 + 4
|
|
lis r31, 0
|
|
|
|
@next_seg ; SEGMENT REGISTERS
|
|
lwzu r30, -8(r28)
|
|
subis r31, r31, 0x1000
|
|
mr. r31, r31
|
|
mtsrin r30, r31
|
|
bne @next_seg
|
|
|
|
mfpvr r31
|
|
lwz r28, MemMap.BatMap(r29)
|
|
andis. r31, r31, 0xFFFE
|
|
addi r29, r1, 0
|
|
stw r28, KDP.CurMap.BatMap(r1)
|
|
beq @601
|
|
|
|
rlwimi r29, r28, 7, 0x00000078 ; BATS, non-601
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
mtspr ibat0u, r30
|
|
mtspr ibat0l, r31
|
|
stw r30, KDP.CurIBAT0.U(r1)
|
|
stw r31, KDP.CurIBAT0.L(r1)
|
|
|
|
rlwimi r29, r28, 11, 0x00000078
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
mtspr ibat1u, r30
|
|
mtspr ibat1l, r31
|
|
stw r30, KDP.CurIBAT1.U(r1)
|
|
stw r31, KDP.CurIBAT1.L(r1)
|
|
|
|
rlwimi r29, r28, 15, 0x00000078
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
mtspr ibat2u, r30
|
|
mtspr ibat2l, r31
|
|
stw r30, KDP.CurIBAT2.U(r1)
|
|
stw r31, KDP.CurIBAT2.L(r1)
|
|
|
|
rlwimi r29, r28, 19, 0x00000078
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
mtspr ibat3u, r30
|
|
mtspr ibat3l, r31
|
|
stw r30, KDP.CurIBAT3.U(r1)
|
|
stw r31, KDP.CurIBAT3.L(r1)
|
|
|
|
rlwimi r29, r28, 23, 0x00000078
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
mtspr dbat0u, r30
|
|
mtspr dbat0l, r31
|
|
stw r30, KDP.CurDBAT0.U(r1)
|
|
stw r31, KDP.CurDBAT0.L(r1)
|
|
|
|
rlwimi r29, r28, 27, 0x00000078
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
mtspr dbat1u, r30
|
|
mtspr dbat1l, r31
|
|
stw r30, KDP.CurDBAT1.U(r1)
|
|
stw r31, KDP.CurDBAT1.L(r1)
|
|
|
|
rlwimi r29, r28, 31, 0x00000078
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
mtspr dbat2u, r30
|
|
mtspr dbat2l, r31
|
|
stw r30, KDP.CurDBAT2.U(r1)
|
|
stw r31, KDP.CurDBAT2.L(r1)
|
|
|
|
rlwimi r29, r28, 3, 0x00000078
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
mtspr dbat3u, r30
|
|
mtspr dbat3l, r31
|
|
stw r30, KDP.CurDBAT3.U(r1)
|
|
stw r31, KDP.CurDBAT3.L(r1)
|
|
|
|
cmpw r29, r29
|
|
blr
|
|
|
|
@601
|
|
rlwimi r29, r28, 7, 25, 28
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
stw r30, 0x0300(r1)
|
|
stw r31, 0x0304(r1)
|
|
stw r30, 0x0320(r1)
|
|
stw r31, 0x0324(r1)
|
|
rlwimi r30, r31, 0, 25, 31
|
|
mtspr ibat0u, r30
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
rlwimi r31, r30, 30, 26, 31
|
|
rlwimi r31, r30, 6, 25, 25
|
|
mtspr ibat0l, r31
|
|
rlwimi r29, r28, 11, 25, 28
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
stw r30, 0x0308(r1)
|
|
stw r31, 0x030c(r1)
|
|
stw r30, 0x0328(r1)
|
|
stw r31, 0x032c(r1)
|
|
rlwimi r30, r31, 0, 25, 31
|
|
mtspr ibat1u, r30
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
rlwimi r31, r30, 30, 26, 31
|
|
rlwimi r31, r30, 6, 25, 25
|
|
mtspr ibat1l, r31
|
|
rlwimi r29, r28, 15, 25, 28
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
stw r30, 0x0310(r1)
|
|
stw r31, 0x0314(r1)
|
|
stw r30, 0x0330(r1)
|
|
stw r31, 0x0334(r1)
|
|
rlwimi r30, r31, 0, 25, 31
|
|
mtspr ibat2u, r30
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
rlwimi r31, r30, 30, 26, 31
|
|
rlwimi r31, r30, 6, 25, 25
|
|
mtspr ibat2l, r31
|
|
rlwimi r29, r28, 19, 25, 28
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
lwz r31, KDP.BATs + 4(r29)
|
|
stw r30, 0x0318(r1)
|
|
stw r31, 0x031c(r1)
|
|
stw r30, 0x0338(r1)
|
|
stw r31, 0x033c(r1)
|
|
rlwimi r30, r31, 0, 25, 31
|
|
mtspr ibat3u, r30
|
|
lwz r30, KDP.BATs + 0(r29)
|
|
rlwimi r31, r30, 30, 26, 31
|
|
rlwimi r31, r30, 6, 25, 25
|
|
mtspr ibat3l, r31
|
|
cmpw r29, r29
|
|
blr
|
|
|
|
########################################################################
|
|
|
|
GetPhysical ; EA r27, batPtr r29 // PA r31, EQ=Fail
|
|
lwz r30, 0(r29)
|
|
li r28, -1
|
|
rlwimi r28, r30, 15, 0, 14
|
|
xor r31, r27, r30
|
|
andc. r31, r31, r28
|
|
beq @_54
|
|
lwzu r30, 8(r29)
|
|
rlwimi r28, r30, 15, 0, 14
|
|
xor r31, r27, r30
|
|
andc. r31, r31, r28
|
|
beq @_54
|
|
lwzu r30, 8(r29)
|
|
rlwimi r28, r30, 15, 0, 14
|
|
xor r31, r27, r30
|
|
andc. r31, r31, r28
|
|
beq @_54
|
|
lwzu r30, 8(r29)
|
|
rlwimi r28, r30, 15, 0, 14
|
|
xor r31, r27, r30
|
|
andc. r31, r31, r28
|
|
bne GetPhysicalFromHTAB
|
|
|
|
@_54
|
|
andi. r31, r30, 1
|
|
rlwinm r28, r28, 0, 8, 19
|
|
lwzu r31, 4(r29)
|
|
and r28, r27, r28
|
|
or r31, r31, r28
|
|
bnelr
|
|
|
|
GetPhysicalFromHTAB ; EA r27 // PA r31, EQ=Fail
|
|
mfsrin r31, r27
|
|
rlwinm r30, r27, 10, 26, 31
|
|
rlwimi r30, r31, 7, 1, 24
|
|
rlwinm r28, r27, 26, 10, 25
|
|
oris r30, r30, 0x8000
|
|
rlwinm r31, r31, 6, 7, 25
|
|
xor r28, r28, r31
|
|
lwz r31, KDP.PTEGMask(r1)
|
|
lwz r29, KDP.HTABORG(r1)
|
|
and r28, r28, r31
|
|
or. r29, r29, r28
|
|
|
|
@_2c
|
|
lwz r31, 0(r29)
|
|
lwz r28, 8(r29)
|
|
cmpw cr6, r30, r31
|
|
lwz r31, 16(r29)
|
|
cmpw cr7, r30, r28
|
|
lwzu r28, 24(r29)
|
|
bne cr6, @_50
|
|
|
|
@_48
|
|
lwzu r31, -0x0014(r29)
|
|
blr
|
|
|
|
@_50
|
|
cmpw cr6, r30, r31
|
|
lwzu r31, 8(r29)
|
|
beq cr7, @_48
|
|
cmpw cr7, r30, r28
|
|
lwzu r28, 8(r29)
|
|
beq cr6, @_48
|
|
cmpw cr6, r30, r31
|
|
lwzu r31, 8(r29)
|
|
beq cr7, @_48
|
|
cmpw cr7, r30, r28
|
|
lwzu r28, 8(r29)
|
|
beq cr6, @_48
|
|
cmpw cr6, r30, r31
|
|
lwzu r31, -0x000c(r29)
|
|
beqlr cr7
|
|
cmpw cr7, r30, r28
|
|
lwzu r31, 8(r29)
|
|
beqlr cr6
|
|
lwzu r31, 8(r29)
|
|
beqlr cr7
|
|
lwz r31, KDP.PTEGMask(r1)
|
|
xori r30, r30, 0x40
|
|
andi. r28, r30, 0x40
|
|
addi r29, r29, -0x3c
|
|
xor r29, r29, r31
|
|
bne @_2c
|
|
blr
|
|
|
|
########################################################################
|
|
|
|
FlushTLB
|
|
lhz r29, KDP.ProcInfo.TransCacheTotalSize(r1)
|
|
slwi r29, r29, 11
|
|
@loop
|
|
subi r29, r29, 4096
|
|
cmpwi r29, 0
|
|
tlbie r29
|
|
bgt @loop
|
|
sync
|
|
blr
|