diff --git a/source/common/chainload.h b/source/common/chainload.h new file mode 100644 index 0000000..7b2dc1d --- /dev/null +++ b/source/common/chainload.h @@ -0,0 +1,7 @@ +#pragma once + +#include "common.h" + +#define PAYLOAD_MAX_SIZE 0xFFFE0 + +void Chainload(u8 *source, size_t size); diff --git a/source/common/chainload.s b/source/common/chainload.s new file mode 100644 index 0000000..426ec2a --- /dev/null +++ b/source/common/chainload.s @@ -0,0 +1,52 @@ +@ Wolfvak - 25/01/2017 + +@ TODO: ELF launcher +@ void Chainload(u8 *source, size_t size) +@ Wrapper around chainload_itcm + +.arm +.global Chainload +.type Chainload, %function +Chainload: + ldr r2, =0x1FF8100 @ ITCM + 0x100 bytes + mov r3, r2 + ldr r4, =chainload_itcm + ldr r5, =chainload_itcm_end + +.copy_chainloader: + cmp r4, r5 + ldrlt r6, [r4], #4 + strlt r6, [r3], #4 + blt .copy_chainloader + + bx r2 @ Branch to the real chainloader in ITCM + + +@ void chainload_itcm(void) +@ Note: Uses unprotected bootrom functions +.arm +.type chainload_itcm, %function +.align 4 +chainload_itcm: + mov r2, r1 + ldr r1, =0x23F00000 + + mov r4, r1 @ memcpy256 and clean_flush_cache mess with the registers + + ldr r3, =0xFFFF03F0 @ memcpy256(u32 *src, u32 *ddest, size_t size) + blx r3 + + ldr r3, =0xFFFF0830 @ void clean_flush_cache(void) + blx r3 + + mov r3, r4 + + mov r0, #0 @ Clear argc + mov r1, #0 @ Same for argv + mov r2, #0 + mov lr, #0 + bx r3 + +.pool + +chainload_itcm_end: diff --git a/source/fs/filetype.c b/source/fs/filetype.c index f94c78d..f448d44 100644 --- a/source/fs/filetype.c +++ b/source/fs/filetype.c @@ -2,6 +2,7 @@ #include "fsutil.h" #include "fatmbr.h" #include "game.h" +#include "chainload.h" u32 IdentifyFileType(const char* path) { const u8 romfs_magic[] = { ROMFS_MAGIC }; @@ -9,9 +10,9 @@ u32 IdentifyFileType(const char* path) { u8 header[0x200] __attribute__((aligned(32))); // minimum required size size_t fsize = FileGetSize(path); char* fname = strrchr(path, '/'); - if (fname == NULL) return 0; // not a proper path - fname++; - if (FileGetData(path, header, 0x200, 0) < fsize) return 0; + char* ext = (fname) ? strrchr(++fname, '.') : NULL; + if (ext) ext++; + if (FileGetData(path, header, 0x200, 0) < ((fsize > 0x200) ? 0x200 : fsize)) return 0; if (fsize >= 0x200) { if ((getbe32(header + 0x100) == 0x4E435344) && (getbe64(header + 0x110) == (u64) 0x0104030301000000) && @@ -51,8 +52,12 @@ u32 IdentifyFileType(const char* path) { } if ((fsize > sizeof(NcchInfoHeader)) && (GetNcchInfoVersion((NcchInfoHeader*) (void*) header)) && - (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) { - return MISC_NINFO; // ncchinfo.bin file + fname && (strncasecmp(fname, NCCHINFO_NAME, 32) == 0)) { + return BIN_NCCHNFO; // ncchinfo.bin file + #if PAYLOAD_MAX_SIZE <= TEMP_BUFFER_SIZE + } else if ((fsize <= PAYLOAD_MAX_SIZE) && (strncasecmp(ext, "bin", 4) == 0)) { + return BIN_LAUNCH; // assume it's an ARM9 payload + #endif } return 0; diff --git a/source/fs/filetype.h b/source/fs/filetype.h index d04de1c..5b7bb6c 100644 --- a/source/fs/filetype.h +++ b/source/fs/filetype.h @@ -2,19 +2,17 @@ #include "common.h" -#define IMG_FAT (1<<0) -#define IMG_NAND (1<<1) - -#define GAME_CIA (1<<2) -#define GAME_NCSD (1<<3) -#define GAME_NCCH (1<<4) -#define GAME_TMD (1<<5) -#define GAME_EXEFS (1<<6) -#define GAME_ROMFS (1<<7) - -#define SYS_FIRM (1<<8) - -#define MISC_NINFO (1<<9) +#define IMG_FAT (1<<0) +#define IMG_NAND (1<<1) +#define GAME_CIA (1<<2) +#define GAME_NCSD (1<<3) +#define GAME_NCCH (1<<4) +#define GAME_TMD (1<<5) +#define GAME_EXEFS (1<<6) +#define GAME_ROMFS (1<<7) +#define SYS_FIRM (1<<8) +#define BIN_NCCHNFO (1<<9) +#define BIN_LAUNCH (1<<10) #define FTYPE_MOUNTABLE (IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS|SYS_FIRM) #define FYTPE_VERIFICABLE (IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD|SYS_FIRM) @@ -22,6 +20,7 @@ #define FTYPE_BUILDABLE (GAME_NCSD|GAME_NCCH|GAME_TMD) #define FTYPE_BUILDABLE_L (FTYPE_BUILDABLE&(GAME_TMD)) #define FTYPE_RESTORABLE (IMG_NAND) -#define FTYPE_XORPAD (MISC_NINFO) +#define FTYPE_XORPAD (BIN_NCCHNFO) +#define FTYPE_PAYLOAD (BIN_LAUNCH) u32 IdentifyFileType(const char* path); diff --git a/source/godmode.c b/source/godmode.c index 4464c93..6d80e7f 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -14,6 +14,7 @@ #include "vcart.h" #include "ncchinfo.h" #include "image.h" +#include "chainload.h" #define N_PANES 2 @@ -589,8 +590,9 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur bool buildable_legit = (filetype & FTYPE_BUILDABLE_L); bool restorable = (CheckA9lh() && (filetype & FTYPE_RESTORABLE) && !(drvtype & DRV_SYSNAND)); bool xorpadable = (filetype & FTYPE_XORPAD); + bool launchable = ((filetype & FTYPE_PAYLOAD) && (drvtype & DRV_FAT)); bool special_opt = mountable || verificable || decryptable || decryptable_inplace || - buildable || buildable_legit || restorable || xorpadable; + buildable || buildable_legit || restorable || xorpadable || launchable; char pathstr[32 + 1]; TruncateString(pathstr, curr_entry->path, 32, 8); @@ -623,7 +625,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur (filetype == GAME_ROMFS) ? "Mount as ROMFS image" : (filetype == GAME_TMD) ? "TMD file options..." : (filetype == SYS_FIRM) ? "FIRM image options..." : - (filetype == MISC_NINFO) ? "NCCHinfo options..." : "???"; + (filetype == BIN_NCCHNFO) ? "NCCHinfo options..." : + (filetype == BIN_LAUNCH) ? "Launch as arm9 payload" : "???"; optionstr[hexviewer-1] = "Show in Hexeditor"; optionstr[calcsha-1] = "Calculate SHA-256"; if (copystd > 0) optionstr[copystd-1] = "Copy to " OUTPUT_PATH; @@ -698,6 +701,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur int verify = (verificable) ? ++n_opt : -1; int xorpad = (xorpadable) ? ++n_opt : -1; int xorpad_inplace = (xorpadable) ? ++n_opt : -1; + int launch = (launchable) ? ++n_opt : -1; if (mount > 0) optionstr[mount-1] = "Mount image to drive"; if (restore > 0) optionstr[restore-1] = "Restore SysNAND (safe)"; if (decrypt > 0) optionstr[decrypt-1] = "Decrypt file (SD output)"; @@ -707,6 +711,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur if (verify > 0) optionstr[verify-1] = "Verify file"; if (xorpad > 0) optionstr[xorpad-1] = "Build XORpads (SD output)"; if (xorpad_inplace > 0) optionstr[xorpad_inplace-1] = "Build XORpads (inplace)"; + if (launch > 0) optionstr[launch-1] = "Launch as ARM9 payload"; // auto select when there is only one option user_select = (n_opt > 1) ? (int) ShowSelectPrompt(n_opt, optionstr, pathstr) : n_opt; @@ -858,6 +863,14 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, DirStruct* cur *scroll = 0; *cursor = 1; } + } else if ((user_select == launch)) { + size_t payload_size = FileGetSize(curr_entry->path); + if (ShowPrompt(true, "%s (%dkB)\nLaunch as arm9 payload?", pathstr, payload_size / 1024)) { + if (FileGetData(curr_entry->path, TEMP_BUFFER, payload_size, 0) == payload_size) { + Chainload(TEMP_BUFFER, payload_size); + while(1); + } // failed load is basically impossible here + } } return 1;