#include #include #include #include #include #include #include #include #include "homebrew.h" #include "defines.h" #include "loader/sys.h" #include "banner/AnimatedBanner.h" #include "fileOps/fileOps.h" #include "gecko/gecko.hpp" static u8 *EXECUTE_ADDR = (u8*)0x92000000; static u8 *BOOTER_ADDR = (u8*)0x93300000; static entry BOOTER_ENTRY = (entry)BOOTER_ADDR; static __argv *ARGS_ADDR = (__argv*)0x93300800; //more than twice as much as the appbooter, just for safety static char *CMD_ADDR = (char*)ARGS_ADDR + sizeof(struct __argv); char *homebrew_ptr = NULL; u32 homebrew_size = 0; u8 *appbooter_ptr = NULL; u32 appbooter_size = 0; using namespace std; extern const u8 wfstub_bin[]; extern const u32 wfstub_bin_size; extern const u8 stub_bin[]; extern const u32 stub_bin_size; u8 valid = 0; static vector Arguments; static bool IsDollZ(u8 *buf) { u8 cmp1[] = {0x3C}; return memcmp(&buf[0x100], cmp1, sizeof(cmp1)) == 0; } static bool IsSpecialELF(u8 *buf) { u32 cmp1[] = {0x7F454C46}; u8 cmp2[] = {0x00}; return memcmp(buf, cmp1, sizeof(cmp1)) == 0 && memcmp(&buf[0x24], cmp2, sizeof(cmp2)) == 0; } void AddBootArgument(const char *argv) { string arg(argv); Arguments.push_back(arg); } void AddBootArgument(const char *argv, unsigned int size) { string arg(argv, size); Arguments.push_back(arg); } bool LoadAppBooter(const char *filepath) { u8 *tmp_ptr = fsop_ReadFile(filepath, &appbooter_size); if(appbooter_size == 0 || tmp_ptr == NULL) return false; appbooter_ptr = (u8*)MEM2_lo_alloc(appbooter_size); /* safety because upper mem2 is dol */ if(appbooter_ptr == NULL) { free(tmp_ptr); return false; } memcpy(appbooter_ptr, tmp_ptr, appbooter_size); DCFlushRange(appbooter_ptr, appbooter_size); free(tmp_ptr); return true; } bool LoadHomebrew(const char *filepath) { if(filepath == NULL) return false; u32 filesize = 0; fsop_GetFileSizeBytes(filepath, &filesize); if(filesize == 0) return false; if(filesize <= ((u32)BOOTER_ADDR - (u32)EXECUTE_ADDR)) { fsop_ReadFileLoc(filepath, filesize, EXECUTE_ADDR); DCFlushRange(EXECUTE_ADDR, filesize); homebrew_ptr = (char*)EXECUTE_ADDR; homebrew_size = filesize; return true; } return false; } char *GetHomebrew(unsigned int *size) { *size = homebrew_size; return homebrew_ptr; } static int SetupARGV() { __argv *args = ARGS_ADDR; memset(args, 0, sizeof(struct __argv)); args->argvMagic = ARGV_MAGIC; u32 position = 0; /** Count Arguments Size **/ u32 stringlength = 1; for(u32 i = 0; i < Arguments.size(); i++) stringlength += Arguments[i].size()+1; args->length = stringlength; /** Append Arguments **/ args->argc = Arguments.size(); args->commandLine = CMD_ADDR; for(int i = 0; i < args->argc; i++) { memcpy(&args->commandLine[position], Arguments[i].c_str(), Arguments[i].size() + 1); position += Arguments[i].size() + 1; } args->commandLine[args->length - 1] = '\0'; Arguments.clear(); return 0; } void writeStub() { /* Clear potential homebrew channel stub */ memset((void*)0x80001800, 0, 0x1800); /* Extract our stub */ u32 StubSize = 0; #ifdef APP_WIIFLOW u8 *Stub = DecompressCopy(wfstub_bin, wfstub_bin_size, &StubSize); #else u8 *Stub = DecompressCopy(stub_bin, stub_bin_size, &StubSize); #endif /* Copy our own stub into memory */ memcpy((void*)0x80001800, Stub, StubSize); DCFlushRange((void*)0x80001800, StubSize); /* And free the memory again */ #ifdef APP_WIIFLOW if(Stub != wfstub_bin) #else if(Stub != stub_bin) #endif free(Stub); } void BootHomebrew() { if(!IsDollZ(EXECUTE_ADDR) && !IsSpecialELF(EXECUTE_ADDR)) SetupARGV(); else gprintf("Homebrew Boot Arguments disabled\n"); memcpy(BOOTER_ADDR, appbooter_ptr, appbooter_size); DCFlushRange(BOOTER_ADDR, appbooter_size); free(appbooter_ptr); JumpToEntry(BOOTER_ENTRY); } extern "C" { extern void __exception_closeall(); } u32 AppEntrypoint = 0; void JumpToEntry(entry EntryPoint) { AppEntrypoint = (u32)EntryPoint; gprintf("Jumping to %08x\n", AppEntrypoint); u32 level = IRQ_Disable(); __IOS_ShutdownSubsystems(); __exception_closeall(); __lwp_thread_closeall(); //dont like it but whatever asm volatile ( "lis %r3, AppEntrypoint@h\n" "ori %r3, %r3, AppEntrypoint@l\n" "lwz %r3, 0(%r3)\n" "mtlr %r3\n" "blr\n" ); IRQ_Restore(level); }