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

This commit is contained in:
Aurora 2016-09-13 23:01:38 +02:00
parent 7952271d61
commit 550ea2116e
7 changed files with 233 additions and 77 deletions

View File

@ -67,6 +67,38 @@ static bool secureInfoExists(void)
return exists; 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) static void loadTitleCodeSection(u64 progId, u8 *code, u32 size)
{ {
/* Here we look for "/luma/code_sections/[u64 titleID in hex, uppercase].bin" /* 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; u64 total;
ret = IFile_Read(&file, &total, code, fileSize); 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); Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
if(R_SUCCEEDED(ret)) if(R_SUCCEEDED(ret))
{ {
char buf[6]; u64 fileSize;
u64 total; ret = IFile_GetSize(&file, &fileSize);
ret = IFile_Read(&file, &total, buf, 6); if(R_SUCCEEDED(ret) && fileSize == 6)
IFile_Close(&file);
if(!R_SUCCEEDED(ret) || total < 6) return -1;
for(u32 i = 0; i < 7; ++i)
{ {
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; for(u32 i = 0; i < 7; ++i)
break; {
} 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) for(u32 i = 0; i < 12; ++i)
{ {
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"}; static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
if(memcmp(buf + 4, languages[i], 2) == 0) if(memcmp(buf + 4, languages[i], 2) == 0)
{ {
*languageId = (u8)i; *languageId = (u8)i;
break; break;
}
}
} }
} }
else ret = -1;
IFile_Close(&file);
} }
return ret; return ret;
@ -325,7 +367,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01
}; };
u8 mostRecentFpdVer = 0x06; u8 mostRecentFpdVer = 0x07;
u8 *fpdVer = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern)); 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 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET case 0x0004001000028000LL: // TWN MSET
{ {
if(CONFIG(SHOWNAND)) if(CONFIG(PATCHVERSTRING))
{ {
static const u16 verPattern[] = u"Ver."; static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCFG_NAND; static u16 *verString;
const u32 matchingFirm = BOOTCFG_FIRM == (currentNand != 0); u32 verStringSize;
static const u16 *verString; u16 customVerString[19] = {0};
switch(currentNand) if(R_SUCCEEDED(loadCustomVerString(customVerString, &verStringSize))) verString = customVerString;
else
{ {
case 1: verStringSize = 8;
verString = matchingFirm ? u" Emu" : u"EmuS"; u32 currentNand = BOOTCFG_NAND,
break; currentFirm = BOOTCFG_FIRM;
case 2: bool matchingFirm = (currentFirm != 0) == (currentNand != 0);
verString = matchingFirm ? u"Emu2" : u"Em2S";
break; static u16 verStringEmu[] = u"Emu ",
case 3: verStringEmuSys[] = u"Em S",
verString = matchingFirm ? u"Emu3" : u"Em3S"; verStringSysEmu[] = u"SyE ";
break;
case 4: switch(currentNand)
verString = matchingFirm ? u"Emu4" : u"Em4S"; {
break; case 1:
default: verString = matchingFirm ? u" Emu" : u"EmuS";
verString = matchingFirm ? u" Sys" : u"SysE"; break;
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 //Patch Ver. string
@ -373,7 +443,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
verPattern, verPattern,
sizeof(verPattern) - sizeof(u16), 0, sizeof(verPattern) - sizeof(u16), 0,
verString, verString,
sizeof(verPattern) - sizeof(u16), 1 verStringSize, 1
); );
} }

View File

@ -3,14 +3,14 @@
#include <3ds/types.h> #include <3ds/types.h>
#define CONFIG(a) (((info.config >> (a + 21)) & 1) != 0) #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 BOOTCONFIG(a, b) ((info.config >> a) & b)
#define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 1) #define BOOTCFG_FIRM BOOTCONFIG(3, 7)
#define BOOTCFG_A9LH BOOTCONFIG(4, 1) #define BOOTCFG_A9LH BOOTCONFIG(6, 1)
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(5, 1) #define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1)
#define BOOTCFG_SAFEMODE BOOTCONFIG(6, 1) #define BOOTCFG_SAFEMODE BOOTCONFIG(8, 1)
enum multiOptions enum multiOptions
{ {
@ -28,7 +28,7 @@ enum singleOptions
AUTOBOOTSYS = 0, AUTOBOOTSYS = 0,
USESYSFIRM, USESYSFIRM,
USELANGEMUANDCODE, USELANGEMUANDCODE,
SHOWNAND, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PAYLOADSPLASH PAYLOADSPLASH
#ifdef DEV #ifdef DEV

View File

@ -47,7 +47,7 @@ void writeConfig(ConfigurationStatus needConfig, u32 configTemp)
{ {
/* If the configuration is different from previously, overwrite it. /* If the configuration is different from previously, overwrite it.
Just the no-forcing flag being set is not enough */ 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) if(needConfig == CREATE_CONFIGURATION)
{ {
@ -57,7 +57,7 @@ void writeConfig(ConfigurationStatus needConfig, u32 configTemp)
} }
//Merge the new options and new boot configuration //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))) if(!fileWrite(&configData, CONFIG_PATH, sizeof(CfgData)))
error("Error writing the configuration file"); error("Error writing the configuration file");
@ -71,14 +71,14 @@ void configMenu(bool oldPinStatus)
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits", "PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" "New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )"
#ifdef DEV #ifdef DEV
, "Dev. features: ErrDisp( ) UNITINFO( ) None( )" , "Dev. features: ErrDisp( ) UNITINFO( ) Off( )"
#endif #endif
}; };
const char *singleOptionsText[] = { "( ) Autoboot SysNAND", const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
"( ) Use SysNAND FIRM if booting with R (A9LH)", "( ) Use SysNAND FIRM if booting with R (A9LH)",
"( ) Enable region/language emu. and ext. .code", "( ) 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", "( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Display splash screen before payloads" "( ) Display splash screen before payloads"
#ifdef DEV #ifdef DEV
@ -86,6 +86,83 @@ void configMenu(bool oldPinStatus)
#endif #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 { struct multiOption {
u32 posXs[4]; u32 posXs[4];
u32 posY; u32 posY;
@ -150,6 +227,8 @@ void configMenu(bool oldPinStatus)
color = COLOR_WHITE; color = COLOR_WHITE;
} }
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
u32 pressed = 0; u32 pressed = 0;
//Boring configuration menu //Boring configuration menu
@ -208,6 +287,9 @@ void configMenu(bool oldPinStatus)
u32 singleSelected = selectedOption - multiOptionsAmount; u32 singleSelected = selectedOption - multiOptionsAmount;
drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED); drawString(singleOptionsText[singleSelected], true, 10, singleOptions[singleSelected].posY, COLOR_RED);
} }
clearScreens(false, true);
drawString(optionsDescription[selectedOption], false, 10, 10, COLOR_WHITE);
} }
else else
{ {
@ -240,12 +322,12 @@ void configMenu(bool oldPinStatus)
u32 oldPinLength = MULTICONFIG(PIN); u32 oldPinLength = MULTICONFIG(PIN);
//Preserve the last-used boot options (last 12 bits) //Preserve the last-used boot options (first 9 bits)
configData.config &= 0x3F; configData.config &= 0x1FF;
//Parse and write the new configuration //Parse and write the new configuration
for(u32 i = 0; i < multiOptionsAmount; i++) 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++) for(u32 i = 0; i < singleOptionsAmount; i++)
configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 21); configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 21);

View File

@ -25,18 +25,18 @@
#include "types.h" #include "types.h"
#define CONFIG(a) (((configData.config >> (a + 21)) & 1) != 0) #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 BOOTCONFIG(a, b) ((configData.config >> a) & b)
#define CONFIG_PATH "/luma/config.bin" #define CONFIG_PATH "/luma/config.bin"
#define CONFIG_VERSIONMAJOR 1 #define CONFIG_VERSIONMAJOR 1
#define CONFIG_VERSIONMINOR 3 #define CONFIG_VERSIONMINOR 4
#define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 1) #define BOOTCFG_FIRM BOOTCONFIG(3, 7)
#define BOOTCFG_A9LH BOOTCONFIG(4, 1) #define BOOTCFG_A9LH BOOTCONFIG(6, 1)
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(5, 1) #define BOOTCFG_NOFORCEFLAG BOOTCONFIG(7, 1)
#define BOOTCFG_SAFEMODE BOOTCONFIG(6, 1) #define BOOTCFG_SAFEMODE BOOTCONFIG(8, 1)
enum multiOptions enum multiOptions
{ {
@ -54,7 +54,7 @@ enum singleOptions
AUTOBOOTSYS = 0, AUTOBOOTSYS = 0,
USESYSFIRM, USESYSFIRM,
USELANGEMUANDCODE, USELANGEMUANDCODE,
SHOWNAND, PATCHVERSTRING,
SHOWGBABOOT, SHOWGBABOOT,
PAYLOADSPLASH PAYLOADSPLASH
#ifdef DEV #ifdef DEV

View File

@ -111,7 +111,7 @@ void main(void)
u32 pressed = HID_PAD; u32 pressed = HID_PAD;
//Save old options and begin saving the new boot configuration //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 it's a MCU reboot, try to force boot options
if(isA9lh && CFG_BOOTENV) if(isA9lh && CFG_BOOTENV)
@ -124,7 +124,7 @@ void main(void)
needConfig = DONT_CONFIGURE; needConfig = DONT_CONFIGURE;
//Flag to prevent multiple boot options-forcing //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 /* Else, force the last used boot options unless a button is pressed
@ -159,7 +159,7 @@ void main(void)
firmSource = FIRMWARE_SYSNAND; firmSource = FIRMWARE_SYSNAND;
//Flag to tell loader to init SD //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 the PIN has been verified, wait to make it easier to press the SAFE_MODE combo
if(pinExists && !shouldLoadConfigMenu) if(pinExists && !shouldLoadConfigMenu)
@ -199,25 +199,32 @@ void main(void)
firmSource = nandType; firmSource = nandType;
} }
//If we're booting EmuNAND, determine which one from the directional pad buttons, or otherwise from the config //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) if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
{
FirmwareSource temp;
switch(pressed & EMUNAND_BUTTONS) switch(pressed & EMUNAND_BUTTONS)
{ {
case BUTTON_UP: case BUTTON_UP:
temp = FIRMWARE_EMUNAND;
break; break;
case BUTTON_RIGHT: case BUTTON_RIGHT:
nandType = FIRMWARE_EMUNAND2; temp = FIRMWARE_EMUNAND2;
break; break;
case BUTTON_DOWN: case BUTTON_DOWN:
nandType = FIRMWARE_EMUNAND3; temp = FIRMWARE_EMUNAND3;
break; break;
case BUTTON_LEFT: case BUTTON_LEFT:
nandType = FIRMWARE_EMUNAND4; temp = FIRMWARE_EMUNAND4;
break; break;
default: default:
nandType = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU)); temp = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU));
break; break;
} }
if(nandType == FIRMWARE_EMUNAND) nandType = temp;
else firmSource = temp;
}
} }
} }
} }

View File

@ -77,11 +77,10 @@ bool fileWrite(const void *buffer, const char *path, u32 size)
if(result == FR_NO_PATH) if(result == FR_NO_PATH)
{ {
char folder[256];
for(u32 i = 1; path[i] != 0; i++) for(u32 i = 1; path[i] != 0; i++)
if(path[i] == '/') if(path[i] == '/')
{ {
char folder[i + 1];
memcpy(folder, path, i); memcpy(folder, path, i);
folder[i] = 0; folder[i] = 0;
f_mkdir(folder); f_mkdir(folder);

View File

@ -138,10 +138,8 @@ bool verifyPin(void)
if(messageSize > 0 && messageSize < 800) if(messageSize > 0 && messageSize < 800)
{ {
char message[messageSize + 1]; char message[messageSize + 1];
fileRead(message, messagePath, 0); fileRead(message, messagePath, 0);
message[messageSize] = 0; message[messageSize] = 0;
drawString(message, false, 10, 10, COLOR_WHITE); drawString(message, false, 10, 10, COLOR_WHITE);
} }