diff --git a/include/arm11/firm.h b/include/arm11/firm.h new file mode 100644 index 0000000..4f40ef6 --- /dev/null +++ b/include/arm11/firm.h @@ -0,0 +1,7 @@ +#pragma once + +#include "types.h" + + + +noreturn void firm_launch(void); diff --git a/include/arm9/firm.h b/include/arm9/firm.h index 3f871d3..caf2f10 100644 --- a/include/arm9/firm.h +++ b/include/arm9/firm.h @@ -27,4 +27,4 @@ bool firm_size(size_t *size); bool firm_verify(u32 fwSize, bool skipHashCheck, bool printInfo); -noreturn void firm_launch(void); +noreturn void firm_launch(int argc, const char **argv); diff --git a/source/arm11/firm.c b/source/arm11/firm.c index 9445b13..e9e744c 100644 --- a/source/arm11/firm.c +++ b/source/arm11/firm.c @@ -6,29 +6,34 @@ void NAKED firmLaunchStub(void) { + *((vu32*)A11_FALLBACK_ENTRY) = 0; + // Answer ARM0 REG_PXI_SYNC11 = 0; // Disable all IRQs - *((vu32*)A11_FALLBACK_ENTRY) = 0; while(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL); REG_PXI_SEND11 = PXI_RPL_OK; // Wait for entry address while(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY); - intptr_t e = (intptr_t)REG_PXI_RECV11; + u32 entry = REG_PXI_RECV11; // Tell ARM9 we got the entry while(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL); REG_PXI_SEND11 = PXI_RPL_FIRM_LAUNCH_READY; REG_PXI_CNT11 = 0; // Disable PXI - if(!e) + if(!entry) { - while(!(e = (intptr_t)*((vu32*)A11_FALLBACK_ENTRY))); + while(!*((vu32*)A11_FALLBACK_ENTRY)); + entry = *((vu32*)A11_FALLBACK_ENTRY); } - ((void (*)(void))e)(); + ((void (*)(void))entry)(); + __builtin_unreachable(); } +extern void deinitCpu(void); + noreturn void firm_launch(void) { // Relocate ARM11 stub @@ -37,6 +42,8 @@ ((u32*)A11_STUB_ENTRY)[i] = ((u32*)firmLaunchStub)[i]; } + deinitCpu(); + ((void (*)(void))A11_STUB_ENTRY)(); while(1); } diff --git a/source/arm11/main.c b/source/arm11/main.c index cf48d9a..6594585 100644 --- a/source/arm11/main.c +++ b/source/arm11/main.c @@ -4,6 +4,7 @@ #include "arm11/i2c.h" #include "gfx.h" #include "pxi.h" +#include "arm11/firm.h" extern bool battery_ok(void); extern void power_off(void); @@ -85,5 +86,7 @@ start_firmlaunch: gfx_deinit(); // TODO: Let ARM9 decide when to deinit gfx + firm_launch(); + return 0; } diff --git a/source/arm11/start.s b/source/arm11/start.s index 5f6ed95..4995f4b 100644 --- a/source/arm11/start.s +++ b/source/arm11/start.s @@ -22,7 +22,6 @@ .extern setupMmu .extern __libc_init_array .extern main -.extern firm_launch .section ".crt0" @@ -94,10 +93,6 @@ mov r0, #0 @ argc mov r1, #0 @ argv blx main - cmp r0, #0 - bne fail_loop - bl deinitCpu - b firm_launch fail_loop: wfi b fail_loop diff --git a/source/arm9/firm.c b/source/arm9/firm.c index 9abfde0..e7eaf15 100644 --- a/source/arm9/firm.c +++ b/source/arm9/firm.c @@ -88,12 +88,11 @@ } // NOTE: Do not call any functions here! -void NAKED firmLaunchStub(void) +void NAKED firmLaunchStub(int argc, const char **argv) { firm_header *firm_hdr = (firm_header*)FIRM_LOAD_ADDR; - register u32 entry9 = firm_hdr->entrypointarm9; - register u32 ret = firm_hdr->entrypointarm9; - register u32 entry11 = firm_hdr->entrypointarm11; + void (*entry9)(int, const char**, u32) = (void (*)(int, const char**, u32))firm_hdr->entrypointarm9; + u32 entry11 = firm_hdr->entrypointarm11; for(u32 i = 0; i < 4; i++) @@ -133,7 +132,7 @@ // Tell ARM11 its entrypoint REG_PXI_SYNC9 = 0; // Disable all IRQs while(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL); - REG_PXI_SEND9 = (u32)entry11; + REG_PXI_SEND9 = entry11; // Wait for ARM11... while(1) @@ -142,11 +141,11 @@ if(REG_PXI_RECV9 == PXI_RPL_FIRM_LAUNCH_READY) break; } - REG_PXI_CNT9 = 0; // Disable PXI // go for it! - __asm__ __volatile__("mov lr, %0\n\tbx %1" : : "r" (ret), "r" (entry9) : "lr", "pc"); + entry9(argc, argv, 0xBEEFu); + __builtin_unreachable(); } bool firm_verify(u32 fwSize, bool skipHashCheck, bool printInfo) @@ -249,18 +248,22 @@ return retval; } -noreturn void firm_launch(void) +extern void deinitCpu(void); + +noreturn void firm_launch(int argc, const char **argv) { //printf("Sending PXI_CMD_FIRM_LAUNCH\n"); PXI_sendWord(PXI_CMD_FIRM_LAUNCH); //printf("Waiting for ARM11...\n"); while(PXI_recvWord() != PXI_RPL_OK); - + + deinitCpu(); + //printf("Relocating FIRM launch stub...\n"); NDMA_copy((u32*)A9_STUB_ENTRY, (u32*)firmLaunchStub, A9_STUB_SIZE); //printf("Starting firm launch...\n"); - ((void (*)(void))A9_STUB_ENTRY)(); + ((void (*)(int, const char**))A9_STUB_ENTRY)(argc, argv); while(1); } diff --git a/source/arm9/main.c b/source/arm9/main.c index 7f58e41..93b0e3f 100644 --- a/source/arm9/main.c +++ b/source/arm9/main.c @@ -121,6 +121,9 @@ hardwareDeinit(); + // TODO: Proper argc/v passing needs to be implemented. + firm_launch(1, (const char**)(ITCM_KERNEL_MIRROR + 0x7470)); + return 0; } diff --git a/source/arm9/start.s b/source/arm9/start.s index 56699b5..75e3cae 100644 --- a/source/arm9/start.s +++ b/source/arm9/start.s @@ -25,7 +25,6 @@ .extern fake_heap_end .extern __libc_init_array .extern main -.extern firm_launch .section ".crt0" @@ -91,10 +90,6 @@ mov r0, #0 @ argc mov r1, #0 @ argv blx main - cmp r0, #0 - bne fail_loop - bl deinitCpu - b firm_launch fail_loop: mov r0, #0 @ Wait for interrupt