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;
}
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
);
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}
}
}

View File

@ -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);

View File

@ -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);
}