diff --git a/arm9/data/config_template.ini b/arm9/data/config_template.ini
index 2960701..23dcf63 100644
Binary files a/arm9/data/config_template.ini and b/arm9/data/config_template.ini differ
diff --git a/arm9/source/config.c b/arm9/source/config.c
index cf5da84..0319f61 100644
--- a/arm9/source/config.c
+++ b/arm9/source/config.c
@@ -319,8 +319,14 @@ static int configIniHandler(void* user, const char* section, const char* name, c
} else {
CHECK_PARSE_OPTION(-1);
}
+ } else if (strcmp(name, "autoboot_mode") == 0) {
+ s64 opt;
+ CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 0, 2));
+ cfg->multiConfig |= (u32)opt << (2 * (u32)AUTOBOOTMODE);
+ return 1;
+ } else {
+ CHECK_PARSE_OPTION(-1);
}
- CHECK_PARSE_OPTION(-1);
} else if (strcmp(section, "rosalina") == 0) {
// Rosalina options
if (strcmp(name, "hbldr_3dsx_titleid") == 0) {
@@ -347,6 +353,20 @@ static int configIniHandler(void* user, const char* section, const char* name, c
else {
CHECK_PARSE_OPTION(-1);
}
+ } else if (strcmp(section, "autoboot") == 0) {
+ if (strcmp(name, "autoboot_dsi_titleid") == 0) {
+ u64 opt;
+ CHECK_PARSE_OPTION(parseHexIntOption(&opt, value, 0, 0xFFFFFFFFFFFFFFFFull));
+ cfg->autobootTwlTitleId = opt;
+ return 1;
+ } else if (strcmp(name, "autoboot_3ds_app_mem_type") == 0) {
+ s64 opt;
+ CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 0, 4));
+ cfg->autobootCtrAppmemtype = (u8)opt;
+ return 1;
+ } else {
+ CHECK_PARSE_OPTION(-1);
+ }
} else if (strcmp(section, "misc") == 0) {
for (size_t i = 0; i < sizeof(singleOptionIniNamesMisc)/sizeof(singleOptionIniNamesMisc[0]); i++) {
if (strcmp(name, singleOptionIniNamesMisc[i]) == 0) {
@@ -414,11 +434,13 @@ static size_t saveLumaIniConfigToStr(char *out)
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
splashPosStr, (unsigned int)cfg->splashDurationMsec,
- pinNumDigits, n3dsCpuStr,
+ pinNumDigits, n3dsCpuStr, (int)MULTICONFIG(AUTOBOOTMODE),
cfg->hbldr3dsxTitleId, rosalinaMenuComboStr,
(int)cfg->screenFiltersCct, (int)cfg->ntpTzOffetMinutes,
+ cfg->autobootTwlTitleId, (int)cfg->autobootCtrAppmemtype,
+
(int)CONFIG(PATCHUNITINFO), (int)CONFIG(DISABLEARM11EXCHANDLERS),
(int)CONFIG(ENABLESAFEFIRMROSALINA)
);
@@ -522,9 +544,10 @@ bool readConfig(void)
configData.formatVersionMinor = CONFIG_VERSIONMINOR;
configData.config |= 1u << PATCHVERSTRING;
configData.splashDurationMsec = 3000;
- configData.hbldr3dsxTitleId = 0x000400000D921E00ull;
+ configData.hbldr3dsxTitleId = HBLDR_DEFAULT_3DSX_TID;
configData.rosalinaMenuCombo = 1u << 9 | 1u << 7 | 1u << 2; // L+Start+Select
configData.screenFiltersCct = 6500; // default temp, no-op
+ configData.autobootTwlTitleId = AUTOBOOT_DEFAULT_TWL_TID;
ret = false;
}
else
@@ -566,6 +589,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"Splash: Off( ) Before( ) After( ) payloads",
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )",
+ "Homebrew autoboot: Off( ) 3DS( ) DSi( )",
};
static const char *singleOptionsText[] = { "( ) Autoboot EmuNAND",
@@ -607,6 +631,14 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
"'Clock+L2' can cause issues with some\n"
"games.",
+ "Enable autobooting into homebrew,\n"
+ "either into 3DS or DSi mode.\n\n"
+ "Autobooting into a gamecard title is\n"
+ "not supported.\n\n"
+ "Refer to the \"autoboot\" section in the\n"
+ "configuration file to configure\n"
+ "this feature.",
+
"If enabled, an EmuNAND\n"
"will be launched on boot.\n\n"
"Otherwise, SysNAND will.\n\n"
@@ -675,6 +707,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
{ .visible = true },
{ .visible = true },
{ .visible = ISN3DS },
+ { .visible = true },
};
struct singleOption {
diff --git a/arm9/source/config.h b/arm9/source/config.h
index 222fafc..cf64164 100644
--- a/arm9/source/config.h
+++ b/arm9/source/config.h
@@ -28,13 +28,16 @@
#include "types.h"
+#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ull
+#define AUTOBOOT_DEFAULT_TWL_TID 0x0003000448424C41ull
+
#define CONFIG(a) (((configData.config >> (a)) & 1) != 0)
#define MULTICONFIG(a) ((configData.multiConfig >> (2 * (a))) & 3)
#define BOOTCONFIG(a, b) ((configData.bootConfig >> (a)) & (b))
#define CONFIG_FILE "config.bin"
#define CONFIG_VERSIONMAJOR 3
-#define CONFIG_VERSIONMINOR 0
+#define CONFIG_VERSIONMINOR 1
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
@@ -47,7 +50,8 @@ enum multiOptions
BRIGHTNESS,
SPLASH,
PIN,
- NEWCPU
+ NEWCPU,
+ AUTOBOOTMODE,
};
enum singleOptions
diff --git a/arm9/source/deliver_arg.c b/arm9/source/deliver_arg.c
new file mode 100644
index 0000000..df8dccf
--- /dev/null
+++ b/arm9/source/deliver_arg.c
@@ -0,0 +1,209 @@
+/*
+* This file is part of Luma3DS
+* Copyright (C) 2022 Aurora Wright, TuxSH
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+*
+* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
+* * Requiring preservation of specified reasonable legal notices or
+* author attributions in that material or in the Appropriate Legal
+* Notices displayed by works containing it.
+* * Prohibiting misrepresentation of the origin of that material,
+* or requiring that modified versions of such material be marked in
+* reasonable ways as different from the original version.
+*/
+
+#include "deliver_arg.h"
+#include "utils.h"
+#include "memory.h"
+#include "config.h"
+
+u8 *loadDeliverArg(void)
+{
+ static u8 deliverArg[0x1000] = {0};
+ static bool deliverArgLoaded = false;
+
+ if (!deliverArgLoaded)
+ {
+ u32 bootenv = CFG_BOOTENV; // this register is preserved across reboots
+ if ((bootenv & 1) == 0) // true coldboot
+ {
+ memset(deliverArg, 0, 0x1000);
+ }
+ else
+ {
+ u32 mode = bootenv >> 1;
+ if (mode == 0) // CTR mode
+ {
+ memcpy(deliverArg, (const void *)0x20000000, 0x1000);
+
+ // Validate deliver arg
+ u32 testPattern = *(u32 *)(deliverArg + 0x438);
+ u32 crc = *(u32 *)(deliverArg + 0x43C);
+ u32 expectedCrc = crc32(deliverArg + 0x400, 0x140, 0xFFFFFFFF);
+ if (testPattern != 0xFFFF || crc != expectedCrc)
+ memset(deliverArg, 0, 0x1000);
+ }
+ else // Legacy modes
+ {
+ // Copy TWL deliver arg stuff as-is (0...0x300)
+ copyFromLegacyModeFcram(deliverArg, (const void *)0x20000000, 0x400);
+
+ // Validate TLNC (TWL launcher params) block
+ // Note: Nintendo doesn't do crcLen bound check
+ u8 *tlnc = deliverArg + 0x300;
+ bool hasMagic = memcmp(tlnc, "TLNC", 4) == 0;
+ u8 crcLen = tlnc[5];
+ u16 crc = *(u16 *)(tlnc + 6);
+ if (!hasMagic || crcLen <= 248 || crc != crc16(tlnc + 8, crcLen, 0xFFFF))
+ memset(tlnc, 0, 0x100);
+
+ memset(deliverArg + 0x400, 0, 0xC00);
+ }
+ }
+ deliverArgLoaded = true;
+ }
+
+ return deliverArg;
+}
+
+void commitDeliverArg(void)
+{
+ u8 *deliverArg = loadDeliverArg();
+ u32 bootenv = CFG_BOOTENV;
+
+ if ((bootenv & 1) == 0) // if true coldboot, set bootenv to "CTR mode reboot"
+ {
+ bootenv = 1;
+ CFG_BOOTENV = 1;
+ }
+
+ u32 mode = bootenv >> 1;
+ if (mode == 0) // CTR mode
+ {
+ *(u32 *)(deliverArg + 0x438) = 0xFFFF;
+ *(u32 *)(deliverArg + 0x43C) = crc32(deliverArg + 0x400, 0x140, 0xFFFFFFFF);
+ memcpy((void *)0x20000000, deliverArg, 0x1000);
+ }
+ else // Legacy modes (just TWL mode, really)
+ {
+ copyToLegacyModeFcram((void *)0x20000000, deliverArg, 0x400);
+ }
+}
+
+bool hasValidTlncAutobootParams(void)
+{
+ u8 *tlnc = loadDeliverArg() + 0x300; // loadDeliverArg clears invalid TLNC blocks
+ return memcmp(tlnc, "TLNC", 4) == 0 && (*(u16 *)(tlnc + 0x18) & 1) != 0;
+}
+
+bool isTwlToCtrLaunch(void)
+{
+ // assumes TLNC block is valid
+ u8 *tlnc = loadDeliverArg() + 0x300; // loadDeliverArg clears invalid TLNC blocks
+ u64 twlTid = *(u64 *)(tlnc + 0x10);
+
+ switch (twlTid & ~0xFFull)
+ {
+ case 0x0000000000000000ull: // TWL Launcher -> Home menu (note: NS checks full TID)
+ case 0x00030015484E4200ull: // TWL System Settings -> CTR System Settings (mset)
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool configureHomebrewAutobootCtr(u8 *deliverArg)
+{
+ static const u8 appmemtypesO3ds[] = { 0, 2, 3, 4, 5 };
+ static const u8 appmemtypesN3ds[] = { 6, 7, 7, 7, 7 };
+
+ u64 hbldrTid = configData.hbldr3dsxTitleId;
+ hbldrTid = hbldrTid == 0 ? HBLDR_DEFAULT_3DSX_TID : hbldrTid; // replicate Loader's behavior
+ if ((hbldrTid >> 46) != 0x10) // Not a CTR titleId. Bail out
+ return false;
+
+ u8 memtype = configData.autobootCtrAppmemtype;
+ deliverArg[0x400] = ISN3DS ? appmemtypesN3ds[memtype] : appmemtypesO3ds[memtype];
+
+ // Determine whether to load from the SD card or from NAND. We don't support gamecards for this
+ u32 category = (hbldrTid >> 32) & 0xFFFF;
+ bool isSdApp = (category & 0x10) == 0 && category != 1; // not a system app nor a DLP child
+ *(u64 *)(deliverArg + 0x440) = hbldrTid;
+ *(u64 *)(deliverArg + 0x448) = isSdApp ? 1 : 0;
+
+ // Tell NS to run the title, and that it's not a title jump from legacy mode
+ *(u32 *)(deliverArg + 0x460) = (0 << 1) | (1 << 0);
+
+ CFG_BOOTENV = 1;
+
+ return true;
+}
+
+static bool configureHomebrewAutobootTwl(u8 *deliverArg)
+{
+ // Here, we pretend to be a TWL app rebooting into another TWL app.
+ // We get NS to do all the heavy lifting (starting NWM and AM, etc.) this way.
+
+ memset(deliverArg + 0x000, 0, 0x300); // zero TWL deliver arg params
+
+ // Now onto TLNC (launcher params):
+ u8 *tlnc = deliverArg + 0x300;
+ memset(tlnc, 0, 0x100);
+ memcpy(tlnc, "TLNC", 4);
+ tlnc[4] = 1; // version
+ tlnc[5] = 0x18; // length of data to calculate CRC over
+
+ *(u64 *)(tlnc + 8) = 0; // old title ID
+ *(u64 *)(tlnc + 0x10) = configData.autobootTwlTitleId; // new title ID
+ // bit4: "skip logo" ; bits2:1: NAND boot ; bit0: valid
+ *(u16 *)(tlnc + 0x18) = (1 << 4) | (3 << 1) | (1 << 0);
+
+ *(u16 *)(tlnc + 6) = crc16(tlnc + 8, 0x18, 0xFFFF);
+
+ CFG_BOOTENV = 3;
+
+ return true;
+}
+
+bool configureHomebrewAutoboot(void)
+{
+ bool ret;
+ u8 *deliverArg = loadDeliverArg();
+
+ u32 bootenv = CFG_BOOTENV;
+ u32 mode = bootenv >> 1;
+
+ u32 testPattern = *(u32 *)(deliverArg + 0x438);
+ if (mode != 0 || testPattern == 0xFFFF)
+ return false; // bail out if this isn't a coldboot/plain reboot
+
+ switch (MULTICONFIG(AUTOBOOTMODE))
+ {
+ case 1:
+ ret = configureHomebrewAutobootCtr(deliverArg);
+ break;
+ case 2:
+ ret = configureHomebrewAutobootTwl(deliverArg);
+ break;
+ case 0:
+ default:
+ ret = false;
+ break;
+ }
+
+ if (ret)
+ commitDeliverArg();
+ return ret;
+}
diff --git a/arm9/source/deliver_arg.h b/arm9/source/deliver_arg.h
new file mode 100644
index 0000000..02c1d84
--- /dev/null
+++ b/arm9/source/deliver_arg.h
@@ -0,0 +1,37 @@
+/*
+* This file is part of Luma3DS
+* Copyright (C) 2022 Aurora Wright, TuxSH
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+*
+* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
+* * Requiring preservation of specified reasonable legal notices or
+* author attributions in that material or in the Appropriate Legal
+* Notices displayed by works containing it.
+* * Prohibiting misrepresentation of the origin of that material,
+* or requiring that modified versions of such material be marked in
+* reasonable ways as different from the original version.
+*/
+
+#pragma once
+
+#include "types.h"
+
+u8 *loadDeliverArg(void);
+void commitDeliverArg(void);
+
+bool hasValidTlncAutobootParams(void);
+bool isTwlToCtrLaunch(void); // assumes TLNC block is valid
+
+bool configureHomebrewAutoboot(void);
diff --git a/arm9/source/main.c b/arm9/source/main.c
index bc0ec08..e9232dd 100644
--- a/arm9/source/main.c
+++ b/arm9/source/main.c
@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
-* Copyright (C) 2016-2020 Aurora Wright, TuxSH
+* Copyright (C) 2016-2022 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@
#include "pin.h"
#include "crypto.h"
#include "memory.h"
+#include "deliver_arg.h"
#include "screen.h"
#include "i2c.h"
#include "fmt.h"
@@ -216,8 +217,15 @@ void main(int argc, char **argv, u32 magicWord)
//If it's a MCU reboot, try to force boot options
if(CFG_BOOTENV && needConfig != CREATE_CONFIGURATION)
{
- //Always force a SysNAND boot when quitting AGB_FIRM
- if(CFG_BOOTENV == 7)
+ u32 bootenv = CFG_BOOTENV;
+ bool validTlnc = bootenv == 3 && hasValidTlncAutobootParams();
+ bool twlIntoCtr = validTlnc && isTwlToCtrLaunch();
+
+ if (validTlnc)
+ needToInitSd = true;
+
+ //Always force a SysNAND boot when quitting AGB_FIRM, or when doing a TWL -> (ns ->) TWL reboot
+ if(bootenv == 7 || (validTlnc && !twlIntoCtr))
{
nandType = FIRMWARE_SYSNAND;
firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
@@ -228,16 +236,9 @@ void main(int argc, char **argv, u32 magicWord)
goto boot;
}
- //Account for DSiWare soft resets if exiting TWL_FIRM
- if(CFG_BOOTENV == 3)
- {
- static const u8 TLNC[] = {0x54, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x43};
- if(memcmp((void *)0x20000C00, TLNC, 10) == 0) needToInitSd = true;
- }
-
- /* Force the last used boot options if autobooting a TWL title, or unless a button is pressed
+ /* Force the last used boot options if doing TWL->CTR, or unless a button is pressed
or the no-forcing flag is set */
- if(needToInitSd || memcmp((void *)0x20000300, "TLNC", 4) == 0 || (!pressed && !BOOTCFG_NOFORCEFLAG))
+ if(twlIntoCtr || !(pressed || BOOTCFG_NOFORCEFLAG))
{
nandType = (FirmwareSource)BOOTCFG_NAND;
firmSource = (FirmwareSource)BOOTCFG_FIRM;
@@ -309,6 +310,17 @@ void main(int argc, char **argv, u32 magicWord)
goto boot;
}
+ // Set-up autoboot, and if we're booting into TWL mode, always use SysNAND
+ if (MULTICONFIG(AUTOBOOTMODE) != 0)
+ {
+ bool ok = configureHomebrewAutoboot();
+ if (ok && MULTICONFIG(AUTOBOOTMODE) == 2)
+ {
+ nandType = FIRMWARE_SYSNAND;
+ firmSource = FIRMWARE_SYSNAND;
+ }
+ }
+
//If booting from CTRNAND, always use SysNAND
if(!isSdMode) nandType = FIRMWARE_SYSNAND;
@@ -387,8 +399,10 @@ boot:
switch(firmType)
{
case NATIVE_FIRM:
+ {
res = patchNativeFirm(firmVersion, nandType, loadFromStorage, isFirmProtEnabled, needToInitSd, doUnitinfoPatch);
break;
+ }
case TWL_FIRM:
res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
break;
diff --git a/arm9/source/memory.c b/arm9/source/memory.c
index ae4aee6..3b169a4 100644
--- a/arm9/source/memory.c
+++ b/arm9/source/memory.c
@@ -54,3 +54,27 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
return NULL;
}
+
+void *copyFromLegacyModeFcram(void *dst, const void *src, size_t size)
+{
+ // Copy 2 bytes with a stride of 8
+ const u16 *src16 = (const u16 *)src;
+ u16 *dst16 = (u16 *)dst;
+
+ for (size_t i = 0; i < size / 2; i++)
+ dst16[i] = src16[4 * i];
+
+ return dst;
+}
+
+void *copyToLegacyModeFcram(void *dst, const void *src, size_t size)
+{
+ // Copy 2 bytes with a stride of 8
+ const u16 *src16 = (const u16 *)src;
+ u16 *dst16 = (u16 *)dst;
+
+ for (size_t i = 0; i < size / 2; i++)
+ dst16[4 * i] = src16[i];
+
+ return dst;
+}
diff --git a/arm9/source/memory.h b/arm9/source/memory.h
index 37813b0..4d05f0e 100644
--- a/arm9/source/memory.h
+++ b/arm9/source/memory.h
@@ -34,3 +34,5 @@
#include "types.h"
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
+void *copyFromLegacyModeFcram(void *dst, const void *src, size_t size);
+void *copyToLegacyModeFcram(void *dst, const void *src, size_t size);
diff --git a/arm9/source/patches.c b/arm9/source/patches.c
index e4c3799..65916b8 100644
--- a/arm9/source/patches.c
+++ b/arm9/source/patches.c
@@ -134,6 +134,8 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
u32 rosalinaMenuCombo;
u16 screenFiltersCct;
s16 ntpTzOffetMinutes;
+ u64 autobootTwlTitleId;
+ u8 autobootCtrAppmemtype;
} info;
};
@@ -209,6 +211,8 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
info->rosalinaMenuCombo = configData.rosalinaMenuCombo;
info->screenFiltersCct = configData.screenFiltersCct;
info->ntpTzOffetMinutes = configData.ntpTzOffetMinutes;
+ info->autobootTwlTitleId = configData.autobootTwlTitleId;
+ info->autobootCtrAppmemtype = configData.autobootCtrAppmemtype;
info->versionMajor = VERSION_MAJOR;
info->versionMinor = VERSION_MINOR;
info->versionBuild = VERSION_BUILD;
diff --git a/arm9/source/types.h b/arm9/source/types.h
index 2a59e3d..c6406b9 100644
--- a/arm9/source/types.h
+++ b/arm9/source/types.h
@@ -71,6 +71,9 @@ typedef struct {
u32 rosalinaMenuCombo;
u16 screenFiltersCct;
s16 ntpTzOffetMinutes;
+
+ u64 autobootTwlTitleId;
+ u8 autobootCtrAppmemtype;
} CfgData;
typedef struct
diff --git a/arm9/source/utils.c b/arm9/source/utils.c
index 2bbf835..e97bc29 100644
--- a/arm9/source/utils.c
+++ b/arm9/source/utils.c
@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
-* Copyright (C) 2016-2020 Aurora Wright, TuxSH
+* Copyright (C) 2016-2022 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -154,3 +154,55 @@ void error(const char *fmt, ...)
mcuPowerOff();
}
+
+u16 crc16(const void *data, size_t size, u16 initialValue)
+{
+ static u16 lut[256] = {0};
+ static bool lutInitialized = false;
+
+ if (!lutInitialized)
+ {
+ static const u16 poly = 0xA001;
+ for (u32 i = 0; i < 256; i++)
+ {
+ u16 r = i;
+ for (u32 j = 0; j < 8; j++)
+ r = (r >> 1) ^ ((r & 1) != 0 ? poly : 0);
+ lut[i] = r;
+ }
+ lutInitialized = true;
+ }
+
+ u16 r = initialValue;
+ const u8 *data8 = (const u8 *)data;
+ for (size_t i = 0; i < size; i++)
+ r = (r >> 8) ^ lut[(r ^ data8[i]) & 0xFF];
+
+ return r;
+}
+
+u32 crc32(const void *data, size_t size, u32 initialValue)
+{
+ static u32 lut[256] = {0};
+ static bool lutInitialized = false;
+
+ if (!lutInitialized)
+ {
+ static const u32 poly = 0xEDB88320;
+ for (u32 i = 0; i < 256; i++)
+ {
+ u32 r = i;
+ for (u32 j = 0; j < 8; j++)
+ r = (r >> 1) ^ ((r & 1) != 0 ? poly : 0);
+ lut[i] = r;
+ }
+ lutInitialized = true;
+ }
+
+ u32 r = initialValue;
+ const u8 *data8 = (const u8 *)data;
+ for (size_t i = 0; i < size; i++)
+ r = (r >> 8) ^ lut[(r ^ data8[i]) & 0xFF];
+
+ return ~r;
+}
diff --git a/arm9/source/utils.h b/arm9/source/utils.h
index a1678b9..99b32c0 100644
--- a/arm9/source/utils.h
+++ b/arm9/source/utils.h
@@ -1,6 +1,6 @@
/*
* This file is part of Luma3DS
-* Copyright (C) 2016-2020 Aurora Wright, TuxSH
+* Copyright (C) 2016-2022 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -46,3 +46,6 @@ u32 waitInput(bool isMenu);
void mcuPowerOff(void);
void wait(u64 amount);
void error(const char *fmt, ...);
+
+u16 crc16(const void *data, size_t size, u16 initialValue);
+u32 crc32(const void *data, size_t size, u32 initialValue);
diff --git a/k11_extension/include/config.h b/k11_extension/include/config.h
index a482de0..26ee057 100644
--- a/k11_extension/include/config.h
+++ b/k11_extension/include/config.h
@@ -20,7 +20,8 @@ enum multiOptions
BRIGHTNESS,
SPLASH,
PIN,
- NEWCPU
+ NEWCPU,
+ AUTOBOOTMODE,
};
enum singleOptions
diff --git a/k11_extension/include/globals.h b/k11_extension/include/globals.h
index 5272d04..94e37a0 100644
--- a/k11_extension/include/globals.h
+++ b/k11_extension/include/globals.h
@@ -132,6 +132,8 @@ typedef struct CfwInfo
u32 rosalinaMenuCombo;
u16 screenFiltersCct;
s16 ntpTzOffetMinutes;
+ u64 autobootTwlTitleId;
+ u8 autobootCtrAppmemtype;
} CfwInfo;
extern CfwInfo cfwInfo;
diff --git a/k11_extension/source/svc/GetSystemInfo.c b/k11_extension/source/svc/GetSystemInfo.c
index f5f6bbf..72f22ee 100644
--- a/k11_extension/source/svc/GetSystemInfo.c
+++ b/k11_extension/source/svc/GetSystemInfo.c
@@ -61,6 +61,13 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
*out = cfwInfo.splashDurationMsec;
break;
+ case 0x10:
+ *out = (s64)cfwInfo.autobootTwlTitleId;
+ break;
+ case 0x11:
+ *out = cfwInfo.autobootCtrAppmemtype;
+ break;
+
case 0x100:
*out = (s64)cfwInfo.hbldr3dsxTitleId;
break;
diff --git a/sysmodules/loader/source/patcher.h b/sysmodules/loader/source/patcher.h
index ac6c3bf..9f14345 100644
--- a/sysmodules/loader/source/patcher.h
+++ b/sysmodules/loader/source/patcher.h
@@ -22,7 +22,8 @@ enum multiOptions
BRIGHTNESS,
SPLASH,
PIN,
- NEWCPU
+ NEWCPU,
+ AUTOBOOTMODE,
};
enum singleOptions
diff --git a/sysmodules/rosalina/data/config_template.ini b/sysmodules/rosalina/data/config_template.ini
index 2960701..23dcf63 100644
Binary files a/sysmodules/rosalina/data/config_template.ini and b/sysmodules/rosalina/data/config_template.ini differ
diff --git a/sysmodules/rosalina/source/menus.c b/sysmodules/rosalina/source/menus.c
index 999cfe2..2833f4d 100644
--- a/sysmodules/rosalina/source/menus.c
+++ b/sysmodules/rosalina/source/menus.c
@@ -88,13 +88,6 @@ void RosalinaMenu_ShowDebugInfo(void)
u32 kernelVer = osGetKernelVersion();
FS_SdMmcSpeedInfo speedInfo;
- Handle hm = 0;
- OpenProcessByName("menu", &hm);
- s64 out = 0;
- svcGetHandleInfo(&out, hm, 0);
- svcCloseHandle(hm);
- u64 timeToBootHm = 1000u * out / SYSCLOCK_ARM11;
-
do
{
Draw_Lock();
@@ -130,11 +123,10 @@ void RosalinaMenu_ShowDebugInfo(void)
(int)speedInfo.highSpeedModeEnabled, SYSCLOCK_SDMMC / (1000 * clkDiv)
);
}
- if (timeToBootHm != 0)
{
posY = Draw_DrawFormattedString(
- 10, posY, COLOR_WHITE, "Time to boot to Home Menu: %llums\n",
- timeToBootHm
+ 10, posY, COLOR_WHITE, "APPMEMTYPE: %lu\n",
+ OS_KernelConfig->app_memtype
);
}
Draw_FlushFramebuffer();
diff --git a/sysmodules/rosalina/source/menus/miscellaneous.c b/sysmodules/rosalina/source/menus/miscellaneous.c
index 9dc055c..bf76139 100644
--- a/sysmodules/rosalina/source/menus/miscellaneous.c
+++ b/sysmodules/rosalina/source/menus/miscellaneous.c
@@ -62,7 +62,8 @@ enum multiOptions
BRIGHTNESS,
SPLASH,
PIN,
- NEWCPU
+ NEWCPU,
+ AUTOBOOTMODE,
};
typedef struct DspFirmSegmentHeader {
u32 offset;
@@ -99,6 +100,9 @@ typedef struct CfgData {
u32 rosalinaMenuCombo;
u16 screenFiltersCct;
s16 ntpTzOffetMinutes;
+
+ u64 autobootTwlTitleId;
+ u8 autobootCtrAppmemtype;
} CfgData;
Menu miscellaneousMenu = {
@@ -291,11 +295,13 @@ static size_t saveLumaIniConfigToStr(char *out, const CfgData *cfg)
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
splashPosStr, (unsigned int)cfg->splashDurationMsec,
- pinNumDigits, n3dsCpuStr,
+ pinNumDigits, n3dsCpuStr, (int)MULTICONFIG(AUTOBOOTMODE),
cfg->hbldr3dsxTitleId, rosalinaMenuComboStr,
(int)cfg->screenFiltersCct, (int)cfg->ntpTzOffetMinutes,
+ cfg->autobootTwlTitleId, (int)cfg->autobootCtrAppmemtype,
+
(int)CONFIG(PATCHUNITINFO), (int)CONFIG(DISABLEARM11EXCHANDLERS),
(int)CONFIG(ENABLESAFEFIRMROSALINA)
);
@@ -318,8 +324,12 @@ void MiscellaneousMenu_SaveSettings(void)
u32 config, multiConfig, bootConfig;
u32 splashDurationMsec;
+ u8 autobootCtrAppmemtype;
+ u64 autobootTwlTitleId;
+
s64 out;
bool isSdMode;
+
svcGetSystemInfo(&out, 0x10000, 2);
formatVersion = (u32)out;
svcGetSystemInfo(&out, 0x10000, 3);
@@ -330,6 +340,12 @@ void MiscellaneousMenu_SaveSettings(void)
bootConfig = (u32)out;
svcGetSystemInfo(&out, 0x10000, 6);
splashDurationMsec = (u32)out;
+
+ svcGetSystemInfo(&out, 0x10000, 0x10);
+ autobootTwlTitleId = (u64)out;
+ svcGetSystemInfo(&out, 0x10000, 0x11);
+ autobootCtrAppmemtype = (u8)out;
+
svcGetSystemInfo(&out, 0x10000, 0x203);
isSdMode = (bool)out;
@@ -343,6 +359,8 @@ void MiscellaneousMenu_SaveSettings(void)
configData.rosalinaMenuCombo = menuCombo;
configData.screenFiltersCct = (u16)screenFiltersCurrentTemperature;
configData.ntpTzOffetMinutes = (s16)lastNtpTzOffset;
+ configData.autobootTwlTitleId = autobootTwlTitleId;
+ configData.autobootCtrAppmemtype = autobootCtrAppmemtype;
size_t n = saveLumaIniConfigToStr(inibuf, &configData);
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;