.section .large_patch.emunand, "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 .global emunandPatchSdmmcStructPtr .global emunandPatchNandOffset .global emunandPatchNcsdHeaderOffset 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) .pool .balign 4 _emunandPatchEnd: .global emunandPatchSize emunandPatchSize: .word _emunandPatchEnd - emunandPatch @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ Code originally from delebile and mid-kid .section .large_patch.reboot, "aw", %progbits .arm .align 4 #define copy_launch_stub_stack_top 0x01FFB800 #define copy_launch_stub_stack_bottom 0x01FFA800 #define copy_launch_stub_addr 0x01FF9000 #define argv_addr (copy_launch_stub_stack_bottom - 0x100) #define fname_addr (copy_launch_stub_stack_bottom - 0x200) #define low_tid_addr (copy_launch_stub_stack_bottom - 0x300) #define firm_addr 0x20001000 #define firm_maxsize 0x07FFF000 .global rebootPatch rebootPatch: @ Interesting registers and locations to keep in mind, set just before this code is ran: @ - r1: FIRM path in exefs. @ - r7 (or r8): pointer to file object @ - *r7: vtable @ - *(vtable + 0x28): fread function @ - *(r7 + 8): file handle sub r7, r0, #8 mov r8, r1 pxi_wait_recv: ldr r2, =0x44846 ldr r0, =0x10008000 readPxiLoop1: ldrh r1, [r0, #4] lsls r1, #0x17 bmi readPxiLoop1 ldr r0, [r0, #0xC] cmp r0, r2 bne pxi_wait_recv @ Open file add r0, r7, #8 adr r1, rebootPatchFileName mov r2, #1 adr r6, rebootPatchFopenPtr ldr r6, [r6] orr r6, #1 blx r6 cmp r0, #0 bne panic @ Read file mov r0, r7 adr r1, bytes_read ldr r2, =firm_addr ldr r3, =firm_maxsize ldr r6, [r7] ldr r6, [r6, #0x28] blx r6 @ Copy the low TID (in UTF-16) of the wanted firm ldr r0, =low_tid_addr add r1, r8, #0x1A mov r2, #0x10 bl memcpy16 @ Copy argv[0] ldr r0, =fname_addr adr r1, rebootPatchFileName mov r2, #82 bl memcpy16 ldr r0, =argv_addr ldr r1, =fname_addr ldr r2, =low_tid_addr stmia r0, {r1, r2} @ Set kernel state mov r0, #0 mov r1, #0 mov r2, #0 mov r3, #0 svc 0x7C goto_reboot: @ Jump to reboot code ldr r0, kernel_func_displ add r0, pc @ pc is two instructions ahead of the instruction being executed (12 = 2*4 + 4) svc 0x7B die: b die memcpy16: cmp r2, #0 bxeq lr add r2, r0, r2 copy_loop16: ldrh r3, [r1], #2 strh r3, [r0], #2 cmp r0, r2 blo copy_loop16 bx lr panic: mov r1, r0 @ unused register mov r0, #0 svc 0x3C @ svcBreak(USERBREAK_PANIC) b die kernel_func_displ: .word kernelcode_start - goto_reboot - 12 bytes_read: .word 0 .global rebootPatchFopenPtr rebootPatchFopenPtr: .word 0 .pool .global rebootPatchFileName rebootPatchFileName: .skip 2*(80+1) .balign 4 kernelcode_start: msr cpsr_cxsf, #0xD3 @ disable interrupts and clear flags ldr sp, =copy_launch_stub_stack_top ldr r0, =copy_launch_stub_addr adr r1, copy_launch_stub mov r2, #(copy_launch_stub_end - copy_launch_stub) bl memcpy32 @ Disable MPU ldr r0, =0x42078 @ alt vector select, enable itcm mcr p15, 0, r0, c1, c0, 0 bl flushCaches ldr r0, =copy_launch_stub_addr bx r0 copy_launch_stub: ldr r4, =firm_addr mov r5, #0 load_section_loop: @ Such checks. Very ghetto. Wow. add r3, r4, #0x40 add r3, r5,lsl #5 add r3, r5,lsl #4 ldmia r3, {r6-r8} cmp r8, #0 movne r0, r7 addne r1, r4, r6 movne r2, r8 blne memcpy32 add r5, #1 cmp r5, #4 blo load_section_loop mov r0, #2 @ argc ldr r1, =argv_addr @ argv ldr r2, =0xBABE @ magic word mov r5, #0x20000000 ldr r6, [r4, #0x08] str r6, [r5, #-4] @ store arm11 entrypoint ldr lr, [r4, #0x0c] bx lr memcpy32: add r2, r0, r2 copy_loop32: ldr r3, [r1], #4 str r3, [r0], #4 cmp r0, r2 blo copy_loop32 bx lr .pool copy_launch_stub_end: flushCaches: @ Clean and flush data cache mov r1, #0 @ segment counter outer_loop: mov r0, #0 @ line counter inner_loop: orr r2, r1, r0 @ generate segment and line address mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line add r0, #0x20 @ increment to next line cmp r0, #0x400 bne inner_loop add r1, #0x40000000 cmp r1, #0 bne outer_loop @ Drain write buffer mcr p15, 0, r1, c7, c10, 4 @ Flush instruction cache mcr p15, 0, r1, c7, c5, 0 bx lr .pool .balign 4 _rebootPatchEnd: .global rebootPatchSize rebootPatchSize: .word _rebootPatchEnd - rebootPatch