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:
parent
7952271d61
commit
550ea2116e
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,15 +136,19 @@ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
||||
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 == 6)
|
||||
{
|
||||
char buf[6];
|
||||
u64 total;
|
||||
|
||||
ret = IFile_Read(&file, &total, buf, 6);
|
||||
IFile_Close(&file);
|
||||
|
||||
if(!R_SUCCEEDED(ret) || total < 6) return -1;
|
||||
|
||||
if(R_SUCCEEDED(ret))
|
||||
{
|
||||
for(u32 i = 0; i < 7; ++i)
|
||||
{
|
||||
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
|
||||
@ -134,6 +171,11 @@ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
u16 customVerString[19] = {0};
|
||||
if(R_SUCCEEDED(loadCustomVerString(customVerString, &verStringSize))) verString = customVerString;
|
||||
else
|
||||
{
|
||||
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 ";
|
||||
|
||||
static const u16 *verString;
|
||||
switch(currentNand)
|
||||
{
|
||||
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";
|
||||
{
|
||||
if(matchingFirm)
|
||||
{
|
||||
verStringEmu[3] = '0' + currentNand;
|
||||
verString = verStringEmu;
|
||||
}
|
||||
else
|
||||
{
|
||||
verStringEmuSys[2] = '0' + currentNand;
|
||||
verString = verStringEmuSys;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
verString = matchingFirm ? u" Sys" : u"SysE";
|
||||
break;
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user