From 550ea2116e95077f6bdf000358b8b99c39f62a2e Mon Sep 17 00:00:00 2001 From: Aurora Date: Tue, 13 Sep 2016 23:01:38 +0200 Subject: [PATCH] Implement custom "Ver." string, must be in a textfile named "customversion.txt" in /luma, with base format Ver. %d.%d.%d-%d%ls, implemented descriptions for the options on the bottom screen, you can now boot SysNAND with an EmuNAND FIRM other than the first one, cleanup --- injector/source/patcher.c | 158 +++++++++++++++++++++++++++----------- injector/source/patcher.h | 12 +-- source/config.c | 96 +++++++++++++++++++++-- source/config.h | 14 ++-- source/firm.c | 25 +++--- source/fs.c | 3 +- source/pin.c | 2 - 7 files changed, 233 insertions(+), 77 deletions(-) diff --git a/injector/source/patcher.c b/injector/source/patcher.c index ae00636..02f9e3e 100644 --- a/injector/source/patcher.c +++ b/injector/source/patcher.c @@ -67,6 +67,38 @@ static bool secureInfoExists(void) return exists; } +static int loadCustomVerString(u16 *out, u32 *verStringSize) +{ + static const char path[] = "/luma/customversion.txt"; + + IFile file; + Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ); + if(R_SUCCEEDED(ret)) + { + u64 fileSize; + ret = IFile_GetSize(&file, &fileSize); + + if(R_SUCCEEDED(ret) && fileSize <= 19) + { + *verStringSize = (u32)fileSize; + u8 buf[19]; + u64 total; + + ret = IFile_Read(&file, &total, buf, *verStringSize); + + for(u32 i = 0; i < *verStringSize; i++) + ((u8 *)out)[2 * i] = buf[i]; + + *verStringSize *= 2; + } + else ret = -1; + + IFile_Close(&file); + } + + return ret; +} + static void loadTitleCodeSection(u64 progId, u8 *code, u32 size) { /* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin" @@ -87,8 +119,9 @@ static void loadTitleCodeSection(u64 progId, u8 *code, u32 size) { u64 total; ret = IFile_Read(&file, &total, code, fileSize); - IFile_Close(&file); } + + IFile_Close(&file); } } @@ -104,35 +137,44 @@ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ); if(R_SUCCEEDED(ret)) { - char buf[6]; - u64 total; + u64 fileSize; + ret = IFile_GetSize(&file, &fileSize); - ret = IFile_Read(&file, &total, buf, 6); - IFile_Close(&file); - - if(!R_SUCCEEDED(ret) || total < 6) return -1; - - for(u32 i = 0; i < 7; ++i) + if(R_SUCCEEDED(ret) && fileSize == 6) { - static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"}; + char buf[6]; + u64 total; - if(memcmp(buf, regions[i], 3) == 0) + ret = IFile_Read(&file, &total, buf, 6); + + if(R_SUCCEEDED(ret)) { - *regionId = (u8)i; - break; - } - } + for(u32 i = 0; i < 7; ++i) + { + static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"}; + + if(memcmp(buf, regions[i], 3) == 0) + { + *regionId = (u8)i; + break; + } + } - for(u32 i = 0; i < 12; ++i) - { - static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"}; + for(u32 i = 0; i < 12; ++i) + { + static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"}; - if(memcmp(buf + 4, languages[i], 2) == 0) - { - *languageId = (u8)i; - break; + if(memcmp(buf + 4, languages[i], 2) == 0) + { + *languageId = (u8)i; + break; + } + } } } + else ret = -1; + + IFile_Close(&file); } return ret; @@ -325,7 +367,7 @@ void patchCode(u64 progId, u8 *code, u32 size) 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01 }; - u8 mostRecentFpdVer = 0x06; + u8 mostRecentFpdVer = 0x07; u8 *fpdVer = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern)); @@ -342,30 +384,58 @@ void patchCode(u64 progId, u8 *code, u32 size) case 0x0004001000027000LL: // KOR MSET case 0x0004001000028000LL: // TWN MSET { - if(CONFIG(SHOWNAND)) + if(CONFIG(PATCHVERSTRING)) { static const u16 verPattern[] = u"Ver."; - const u32 currentNand = BOOTCFG_NAND; - const u32 matchingFirm = BOOTCFG_FIRM == (currentNand != 0); + static u16 *verString; + u32 verStringSize; - static const u16 *verString; - switch(currentNand) + u16 customVerString[19] = {0}; + if(R_SUCCEEDED(loadCustomVerString(customVerString, &verStringSize))) verString = customVerString; + else { - case 1: - verString = matchingFirm ? u" Emu" : u"EmuS"; - break; - case 2: - verString = matchingFirm ? u"Emu2" : u"Em2S"; - break; - case 3: - verString = matchingFirm ? u"Emu3" : u"Em3S"; - break; - case 4: - verString = matchingFirm ? u"Emu4" : u"Em4S"; - break; - default: - verString = matchingFirm ? u" Sys" : u"SysE"; - break; + verStringSize = 8; + u32 currentNand = BOOTCFG_NAND, + currentFirm = BOOTCFG_FIRM; + bool matchingFirm = (currentFirm != 0) == (currentNand != 0); + + static u16 verStringEmu[] = u"Emu ", + verStringEmuSys[] = u"Em S", + verStringSysEmu[] = u"SyE "; + + switch(currentNand) + { + case 1: + verString = matchingFirm ? u" Emu" : u"EmuS"; + break; + case 2: + case 3: + case 4: + { + if(matchingFirm) + { + verStringEmu[3] = '0' + currentNand; + verString = verStringEmu; + } + else + { + verStringEmuSys[2] = '0' + currentNand; + verString = verStringEmuSys; + } + break; + } + default: + if(matchingFirm) verString = u" Sys"; + else + { + if(currentFirm == 1) verString = u"SysE"; + else + { + verStringSysEmu[3] = '0' + currentFirm; + verString = verStringSysEmu; + } + } + } } //Patch Ver. string @@ -373,7 +443,7 @@ void patchCode(u64 progId, u8 *code, u32 size) verPattern, sizeof(verPattern) - sizeof(u16), 0, verString, - sizeof(verPattern) - sizeof(u16), 1 + verStringSize, 1 ); } diff --git a/injector/source/patcher.h b/injector/source/patcher.h index 68e23c6..eea63a0 100644 --- a/injector/source/patcher.h +++ b/injector/source/patcher.h @@ -3,14 +3,14 @@ #include <3ds/types.h> #define CONFIG(a) (((info.config >> (a + 21)) & 1) != 0) -#define MULTICONFIG(a) ((info.config >> (a * 2 + 7)) & 3) +#define MULTICONFIG(a) ((info.config >> (a * 2 + 9)) & 3) #define BOOTCONFIG(a, b) ((info.config >> a) & b) #define BOOTCFG_NAND BOOTCONFIG(0, 7) -#define BOOTCFG_FIRM BOOTCONFIG(3, 1) -#define BOOTCFG_A9LH BOOTCONFIG(4, 1) -#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(5, 1) -#define BOOTCFG_SAFEMODE BOOTCONFIG(6, 1) +#define BOOTCFG_FIRM BOOTCONFIG(3, 7) +#define BOOTCFG_A9LH BOOTCONFIG(6, 1) +#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1) +#define BOOTCFG_SAFEMODE BOOTCONFIG(8, 1) enum multiOptions { @@ -28,7 +28,7 @@ enum singleOptions AUTOBOOTSYS = 0, USESYSFIRM, USELANGEMUANDCODE, - SHOWNAND, + PATCHVERSTRING, SHOWGBABOOT, PAYLOADSPLASH #ifdef DEV diff --git a/source/config.c b/source/config.c index a056447..28bee96 100644 --- a/source/config.c +++ b/source/config.c @@ -47,7 +47,7 @@ void writeConfig(ConfigurationStatus needConfig, u32 configTemp) { /* If the configuration is different from previously, overwrite it. Just the no-forcing flag being set is not enough */ - if(needConfig == CREATE_CONFIGURATION || (configTemp & 0xFFFFFFDF) != configData.config) + if(needConfig == CREATE_CONFIGURATION || (configTemp & 0xFFFFFF7F) != configData.config) { if(needConfig == CREATE_CONFIGURATION) { @@ -57,7 +57,7 @@ void writeConfig(ConfigurationStatus needConfig, u32 configTemp) } //Merge the new options and new boot configuration - configData.config = (configData.config & 0xFFFFFF80) | (configTemp & 0x7F); + configData.config = (configData.config & 0xFFFFFE00) | (configTemp & 0x1FF); if(!fileWrite(&configData, CONFIG_PATH, sizeof(CfgData))) error("Error writing the configuration file"); @@ -71,14 +71,14 @@ void configMenu(bool oldPinStatus) "PIN lock: Off( ) 4( ) 6( ) 8( ) digits", "New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" #ifdef DEV - , "Dev. features: ErrDisp( ) UNITINFO( ) None( )" + , "Dev. features: ErrDisp( ) UNITINFO( ) Off( )" #endif }; const char *singleOptionsText[] = { "( ) Autoboot SysNAND", "( ) Use SysNAND FIRM if booting with R (A9LH)", "( ) Enable region/language emu. and ext. .code", - "( ) Show current NAND in System Settings", + "( ) Show NAND or user string in System Settings", "( ) Show GBA boot screen in patched AGB_FIRM", "( ) Display splash screen before payloads" #ifdef DEV @@ -86,6 +86,83 @@ void configMenu(bool oldPinStatus) #endif }; + const char *optionsDescription[] = { "Select the default EmuNAND.\n" + "It will booted with no directional pad\n" + "buttons pressed", + + "Select the screen brightness", + + "Activate a PIN lock.\n" + "The PIN will be asked each time\n" + "Luma3DS boots.\n" + "4, 6 or 8 digits can be selected.\n" + "The ABXY buttons and the directional\n" + "pad can be used as keys", + + "Select the New 3DS CPU mode.\n" + "It will be always enabled.\n" + "'Clock+L2' can cause issues with some\n" + "games", +#ifdef DEV + "Select the developer features.\n" + "'ErrDisp' displays debug information\n" + "on the 'An error has occurred' screen.\n" + "'UNITINFO' makes the console be always\n" + "detected as a development unit (which\n" + "breaks online features and allows\n" + "booting some developer software).\n" + "'None' disables exception handlers\n" + "in FIRM", +#endif + "If enabled SysNAND will be launched on\n" + "boot. Otherwise, an EmuNAND will.\n" + "Hold L on boot to switch NAND.\n" + "To use a different EmuNAND from the\n" + "default, hold a directional pad button\n" + "(Up/Right/Down/Left equal EmuNANDs\n" + "1/2/3/4)", + + "If enabled, when holding R on boot\n" + "EmuNAND will be booted with the\n" + "SysNAND FIRM. Otherwise, SysNAND will\n" + "be booted with an EmuNAND FIRM.\n" + "To use a different EmuNAND from the\n" + "default, hold a directional pad button\n" + "(Up/Right/Down/Left equal EmuNANDs\n" + "1/2/3/4)", + + "Enable overriding the region and\n" + "language configuration and the usage\n" + "of patched code binaries for specific\n" + "games.\n" + "Also makes certain DLCs for\n" + "out-of-region games work.\n" + "Refer to the wiki for instructions", + + "Show the currently booted NAND in\n" + "System Settings (Sys = SysNAND,\n" + "Emu = EmuNAND 1, EmuX = EmuNAND X,\n" + "SysE = SysNAND with EmuNAND 1 FIRM,\n" + "SyEX = SysNAND with EmuNAND X FIRM,\n" + "EmXS = EmuNAND X with SysNAND FIRM)\n" + "or an user-defined custom string\n" + "(refer to the wiki for instructions)", + + "Show the GBA boot screen when\n" + "launching GBA games", + + "If enabled, the splash screen will be\n" + "displayed before launching payloads,\n" + "otherwise it will be displayed\n" + "afterwards.\n" + "Intended for splash screens that\n" + "display button hints" +#ifdef DEV + , "Disable SVC, service, archive and ARM9\n" + "exheader access checks" +#endif + }; + struct multiOption { u32 posXs[4]; u32 posY; @@ -150,6 +227,8 @@ void configMenu(bool oldPinStatus) color = COLOR_WHITE; } + drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE); + u32 pressed = 0; //Boring configuration menu @@ -208,6 +287,9 @@ void configMenu(bool oldPinStatus) u32 singleSelected = selectedOption - multiOptionsAmount; drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED); } + + clearScreens(false, true); + drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE); } else { @@ -240,12 +322,12 @@ void configMenu(bool oldPinStatus) u32 oldPinLength = MULTICONFIG(PIN); - //Preserve the last-used boot options (last 12 bits) - configData.config &= 0x3F; + //Preserve the last-used boot options (first 9 bits) + configData.config &= 0x1FF; //Parse and write the new configuration for(u32 i = 0; i < multiOptionsAmount; i++) - configData.config |= multiOptions[i].enabled << (i * 2 + 7); + configData.config |= multiOptions[i].enabled << (i * 2 + 9); for(u32 i = 0; i < singleOptionsAmount; i++) configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 21); diff --git a/source/config.h b/source/config.h index 5a5524f..973dccb 100644 --- a/source/config.h +++ b/source/config.h @@ -25,18 +25,18 @@ #include "types.h" #define CONFIG(a) (((configData.config >> (a + 21)) & 1) != 0) -#define MULTICONFIG(a) ((configData.config >> (a * 2 + 7)) & 3) +#define MULTICONFIG(a) ((configData.config >> (a * 2 + 9)) & 3) #define BOOTCONFIG(a, b) ((configData.config >> a) & b) #define CONFIG_PATH "/luma/config.bin" #define CONFIG_VERSIONMAJOR 1 -#define CONFIG_VERSIONMINOR 3 +#define CONFIG_VERSIONMINOR 4 #define BOOTCFG_NAND BOOTCONFIG(0, 7) -#define BOOTCFG_FIRM BOOTCONFIG(3, 1) -#define BOOTCFG_A9LH BOOTCONFIG(4, 1) -#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(5, 1) -#define BOOTCFG_SAFEMODE BOOTCONFIG(6, 1) +#define BOOTCFG_FIRM BOOTCONFIG(3, 7) +#define BOOTCFG_A9LH BOOTCONFIG(6, 1) +#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1) +#define BOOTCFG_SAFEMODE BOOTCONFIG(8, 1) enum multiOptions { @@ -54,7 +54,7 @@ enum singleOptions AUTOBOOTSYS = 0, USESYSFIRM, USELANGEMUANDCODE, - SHOWNAND, + PATCHVERSTRING, SHOWGBABOOT, PAYLOADSPLASH #ifdef DEV diff --git a/source/firm.c b/source/firm.c index 0b08422..681d130 100755 --- a/source/firm.c +++ b/source/firm.c @@ -111,7 +111,7 @@ void main(void) u32 pressed = HID_PAD; //Save old options and begin saving the new boot configuration - configTemp = (configData.config & 0xFFFFFF80) | ((u32)isA9lh << 4); + configTemp = (configData.config & 0xFFFFFE00) | ((u32)isA9lh << 6); //If it's a MCU reboot, try to force boot options if(isA9lh && CFG_BOOTENV) @@ -124,7 +124,7 @@ void main(void) needConfig = DONT_CONFIGURE; //Flag to prevent multiple boot options-forcing - configTemp |= 1 << 5; + configTemp |= 1 << 7; } /* Else, force the last used boot options unless a button is pressed @@ -159,7 +159,7 @@ void main(void) firmSource = FIRMWARE_SYSNAND; //Flag to tell loader to init SD - configTemp |= 1 << 6; + configTemp |= 1 << 8; //If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo if(pinExists && !shouldLoadConfigMenu) @@ -199,25 +199,32 @@ void main(void) firmSource = nandType; } - //If we're booting EmuNAND, determine which one from the directional pad buttons, or otherwise from the config - if(nandType == FIRMWARE_EMUNAND) + //If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config + if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND) + { + FirmwareSource temp; switch(pressed & EMUNAND_BUTTONS) { case BUTTON_UP: + temp = FIRMWARE_EMUNAND; break; case BUTTON_RIGHT: - nandType = FIRMWARE_EMUNAND2; + temp = FIRMWARE_EMUNAND2; break; case BUTTON_DOWN: - nandType = FIRMWARE_EMUNAND3; + temp = FIRMWARE_EMUNAND3; break; case BUTTON_LEFT: - nandType = FIRMWARE_EMUNAND4; + temp = FIRMWARE_EMUNAND4; break; default: - nandType = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU)); + temp = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU)); break; } + + if(nandType == FIRMWARE_EMUNAND) nandType = temp; + else firmSource = temp; + } } } } diff --git a/source/fs.c b/source/fs.c index 74e6e21..3d27a93 100644 --- a/source/fs.c +++ b/source/fs.c @@ -77,11 +77,10 @@ bool fileWrite(const void *buffer, const char *path, u32 size) if(result == FR_NO_PATH) { - char folder[256]; - for(u32 i = 1; path[i] != 0; i++) if(path[i] == '/') { + char folder[i + 1]; memcpy(folder, path, i); folder[i] = 0; f_mkdir(folder); diff --git a/source/pin.c b/source/pin.c index 63b074b..89dd844 100644 --- a/source/pin.c +++ b/source/pin.c @@ -138,10 +138,8 @@ bool verifyPin(void) if(messageSize > 0 && messageSize < 800) { char message[messageSize + 1]; - fileRead(message, messagePath, 0); message[messageSize] = 0; - drawString(message, false, 10, 10, COLOR_WHITE); }