.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 emunandProtoCidPatch1200
emunandProtoCidPatch1200:
    @ If we're already trying to access the SD, return
    ldr r4, emunandPatchSdmmcStructPtr
    cmp r0, r4
    beq _cid_return1200
    
    @ 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 where we came
    mov r0, #0
    pop {r4-r6, pc}
    
    _cid_return1200:
        @ Execute original code that got patched.
        mov r4, r0
        ldr r0, [r0]
        mov r6, 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

.global emunandProtoPatch1200
emunandProtoPatch1200:
    push {r0-r3}	
    
    @ If we're already trying to access the SD, return
    ldr r2, [r4]
    ldr r1, emunandPatchSdmmcStructPtr
    cmp r1, r2
    beq _out1200
    
    ldr r2, [r1, #0x24] @ Get sdmc->m_someObjInitedLater
    cmp r2, #0 @ Is initialised?
    beq _pastSdmc1200 @ if not, use "NAND" object, patched elsewhere to access SD
    str r1, [r4] @ Set object to be SD
    _pastSdmc1200:

    ldr r2, [r4, #4] @ 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, #4] @ Store sector to read
    
    _out1200:
    @ Restore registers
    pop {r0-r3}
    cmp r0, #3
    sub sp, sp, #0x14
    mov r7, #0

    @ 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 the point after our patching
    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