Luma3DS/arm9/source/emunand_patch.s

194 lines
5.2 KiB
ArmAsm

.section .emunand_patch, "aw", %progbits
.arm
.align 4
@ Code originally by Normmatt
.global emunandPatch
emunandPatch:
@ Original code that still needs to be executed
mov r4, r0
mov r5, r1
mov r7, r2
mov r6, r3
@ End
@ If we're already trying to access the SD, return
ldr r2, [r0, #4]
ldr r1, emunandPatchSdmmcStructPtr
cmp r2, r1
beq out
str r1, [r0, #4] @ Set object to be SD
ldr r2, [r0, #8] @ Get sector to read
cmp r2, #0 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0)
ldr r3, emunandPatchNandOffset
add r2, r3 @ Add the offset to the NAND in the SD
ldreq r3, emunandPatchNcsdHeaderOffset
addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector
str r2, [r0, #8] @ Store sector to read
out:
@ Restore registers.
mov r1, r5
mov r2, r7
mov r3, r6
@ Return 4 bytes behind where we got called,
@ due to the offset of this function being stored there
mov r0, lr
add r0, #4
bx r0
.pool
_emunandPatchEnd:
.global emunandProtoPatch
emunandProtoPatch:
@ Save registers
push {r0-r3}
@ If we're already trying to access the SD, return
ldr r2, [r0, #4]
ldr r1, emunandPatchSdmmcStructPtr
cmp r2, r1
beq _out
ldrb r2, [r1, #0xc] @ Get sdmc->m_isInitialised
cmp r2, #0 @ Is initialised?
beq _pastSdmc @ if not, use "NAND" object, patched elsewhere to access SD
str r1, [r0, #4] @ Set object to be SD
_pastSdmc:
ldr r2, [r0, #8] @ Get sector to read
cmp r2, #0 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0)
ldr r3, emunandPatchNandOffset
add r2, r3 @ Add the offset to the NAND in the SD
ldreq r3, emunandPatchNcsdHeaderOffset
addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector
str r2, [r0, #8] @ Store sector to read
_out:
@ Restore registers
pop {r0-r3}
@ Execute original code that got patched.
cmp r1, #3
mov r12, r2
add r0, r0, #4
movne r1, #0
moveq r1, #1
@ r2 about to be overwritten, so it's free to use here.
@ Save off our return address and restore lr.
mov r2, lr
pop {lr}
@ r2+0 is return address (patched movne r1, #0)
@ r2+4 is moveq r1, #1
@ r2+8 is the following instruction (mov r2, r3)
add r2, #8
bx r2
.global emunandProtoCidPatch
emunandProtoCidPatch:
@ If we're already trying to access the SD, return
ldr r4, emunandPatchSdmmcStructPtr
cmp r0, r4
beq _cid_return
@ Trying to access nand, so copy the NAND cid into r1
adr r4, emunandPatchNandCid
ldr r2, [r4, #0]
ldr r3, [r4, #4]
ldr r5, [r4, #8]
ldr r6, [r4, #0xc]
str r2, [r1, #0]
str r3, [r1, #4]
str r5, [r1, #8]
str r6, [r1, #0xc]
@ And return from whence we came
mov r0, #0
pop {r4-r6, pc}
_cid_return:
@ Execute original code that got patched.
mov r4, r0
ldr r0, [r0]
mov r5, r1
@ lr+0 is return address (patched mov r5, r1)
@ lr+4 is following instruction (ldr r1, [r0,#8])
add lr, #4
bx lr
.global emunandProtoPatch238
emunandProtoPatch238:
@ Save registers
push {r0-r3}
@ If we're already trying to access the SD, return
ldr r2, [r4, #4]
ldr r1, emunandPatchSdmmcStructPtr
cmp r2, r1
beq _out238
ldr r2, [r1, #0x24] @ Get sdmc->m_someObjInitedLater
cmp r2, #0 @ Is initialised?
beq _pastSdmc238 @ if not, use "NAND" object, patched elsewhere to access SD
str r1, [r4, #4] @ Set object to be SD
_pastSdmc238:
ldr r2, [r4, #8] @ Get sector to read
cmp r2, #0 @ For GW compatibility, see if we're trying to read the ncsd header (sector 0)
ldr r3, emunandPatchNandOffset
add r2, r3 @ Add the offset to the NAND in the SD
ldreq r3, emunandPatchNcsdHeaderOffset
addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector
str r2, [r4, #8] @ Store sector to read
_out238:
@ Restore registers
pop {r0-r3}
@ Execute original code that got patched.
cmp r0, #3
movne r0, #0
moveq r0, #1
@ r1 about to be overwritten, so it's free to use here.
@ Save off our return address.
mov r1, lr
@ r1+0 is return address (patched moveq r1, #1)
@ r1+4 is tst r0, #0xff or sub sp, sp, #0xc
add r1, #4
bx r1
.pool
.global emunandPatchSdmmcStructPtr
.global emunandPatchNandOffset
.global emunandPatchNcsdHeaderOffset
.global emunandPatchNandCid
_emunandPatchBssStart:
emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct
emunandPatchNandOffset: .word 0 @ For rednand this should be 1
emunandPatchNcsdHeaderOffset: .word 0 @ Depends on nand manufacturer + emunand type (GW/RED)
emunandPatchNandCid: @ Store emmc cid here, to override "sdmc's" when trying to read emmc's
.word 0,0,0,0
_emunandPatchBssEnd:
.pool
.balign 4
.global emunandPatchSize
emunandPatchSize:
.word _emunandPatchEnd - emunandPatch
.global emunandPatchBssSize
emunandPatchBssSize:
.word _emunandPatchBssEnd - _emunandPatchBssStart