Fix long-standing bug affecting hbldr TID change option

This was a long-standing bug since Luma3DS v8.0.

If you changed the homebrew title and didn't immediately reboot, then
the ExHeader during termination would not match the ExHeader that was
was used for loading the process, and thus sysmodule process refcounts
would get all messed up.

The obvious solution to this is to ensure no application is running
while changing the hbldr titleID (hence the changes in custom PM).

This was quite possibly one of the cause of homebrew failing to load
when using N3DS H&S.
This commit is contained in:
TuxSH 2023-02-08 16:14:59 +00:00
parent 1888e17b22
commit 1d7cca25d1
9 changed files with 72 additions and 23 deletions

View File

@ -18,10 +18,11 @@
#include <3ds/types.h> #include <3ds/types.h>
/// Luma shared config type. /// Luma shared config type (private!).
typedef struct LumaSharedConfig { typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading. u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading (current).
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (reset to true). u64 selected_hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading (to be moved to "current" when the current app closes).
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (reset to true).
} LumaSharedConfig; } LumaSharedConfig;
/// Luma shared config. /// Luma shared config.

View File

@ -66,7 +66,9 @@ static inline void loadCFWInfo(void)
isSdMode = true; isSdMode = true;
} }
Luma_SharedConfig->hbldr_3dsx_tid = hbldrTid == 0 ? HBLDR_DEFAULT_3DSX_TID : hbldrTid; hbldrTid = hbldrTid == 0 ? HBLDR_DEFAULT_3DSX_TID : hbldrTid;
Luma_SharedConfig->hbldr_3dsx_tid = hbldrTid;
Luma_SharedConfig->selected_hbldr_3dsx_tid = hbldrTid;
Luma_SharedConfig->use_hbldr = true; Luma_SharedConfig->use_hbldr = true;
} }

View File

@ -25,7 +25,7 @@ AccessControlInfo:
DisableDebug : false DisableDebug : false
EnableForceDebug : false EnableForceDebug : false
CanWriteSharedPage : false CanWriteSharedPage : true # changed
CanUsePrivilegedPriority : false CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : false CanUseNonAlphabetAndNumber : false
PermitMainFunctionArgument : false PermitMainFunctionArgument : false

View File

@ -0,0 +1,29 @@
/* This paricular file is licensed under the following terms: */
/*
* This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable
* for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it
* and redistribute it freely, subject to the following restrictions:
*
* The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
*
* Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
* This notice may not be removed or altered from any source distribution.
*/
#pragma once
#include <3ds/types.h>
/// Luma shared config type (private!).
typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading (current).
u64 selected_hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading (to be moved to "current" when the current app closes).
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (reset to true).
} LumaSharedConfig;
/// Luma shared config.
#define Luma_SharedConfig ((volatile LumaSharedConfig *)(OS_SHAREDCFG_VADDR + 0x800))

View File

@ -6,6 +6,7 @@
#include "reslimit.h" #include "reslimit.h"
#include "manager.h" #include "manager.h"
#include "util.h" #include "util.h"
#include "luma_shared_config.h"
static void cleanupProcess(ProcessData *process) static void cleanupProcess(ProcessData *process)
{ {
@ -33,6 +34,11 @@ static void cleanupProcess(ProcessData *process)
assertSuccess(resetAppMemLimit()); assertSuccess(resetAppMemLimit());
} }
g_manager.runningApplicationData = NULL; g_manager.runningApplicationData = NULL;
// We need to do this here to ensure that the ExHeader at init matches the ExHeader
// at termination at all times, otherwise the process refcounts of sysmodules
// get all messed up.
Luma_SharedConfig->hbldr_3dsx_tid = Luma_SharedConfig->selected_hbldr_3dsx_tid;
} }
if (g_manager.debugData != NULL && process->handle == g_manager.debugData->handle) { if (g_manager.debugData != NULL && process->handle == g_manager.debugData->handle) {

View File

@ -18,10 +18,11 @@
#include <3ds/types.h> #include <3ds/types.h>
/// Luma shared config type. /// Luma shared config type (private!).
typedef struct LumaSharedConfig { typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading. u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading (current).
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (reset to true). u64 selected_hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading (to be moved to "current" when the current app closes).
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (reset to true).
} LumaSharedConfig; } LumaSharedConfig;
/// Luma shared config. /// Luma shared config.

View File

@ -220,7 +220,7 @@ Result LumaConfig_SaveSettings(void)
configData.multiConfig = multiConfig; configData.multiConfig = multiConfig;
configData.bootConfig = bootConfig; configData.bootConfig = bootConfig;
configData.splashDurationMsec = splashDurationMsec; configData.splashDurationMsec = splashDurationMsec;
configData.hbldr3dsxTitleId = Luma_SharedConfig->hbldr_3dsx_tid; configData.hbldr3dsxTitleId = Luma_SharedConfig->selected_hbldr_3dsx_tid;
configData.rosalinaMenuCombo = menuCombo; configData.rosalinaMenuCombo = menuCombo;
configData.ntpTzOffetMinutes = (s16)lastNtpTzOffset; configData.ntpTzOffetMinutes = (s16)lastNtpTzOffset;
configData.topScreenFilter = topScreenFilter; configData.topScreenFilter = topScreenFilter;

View File

@ -87,10 +87,6 @@ void initSystem(void)
svcGetSystemInfo(&out, 0x10000, 0x103); svcGetSystemInfo(&out, 0x10000, 0x103);
lastNtpTzOffset = (s16)out; lastNtpTzOffset = (s16)out;
miscellaneousMenu.items[0].title = Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID ?
"Switch the hb. title to the current app." :
"Switch the hb. title to " HBLDR_DEFAULT_3DSX_TITLE_NAME;
for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL)) for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL))
{ {
res = srvInit(); res = srvInit();
@ -107,6 +103,10 @@ void initSystem(void)
if (R_FAILED(FSUSER_SetPriority(-16))) if (R_FAILED(FSUSER_SetPriority(-16)))
svcBreak(USERBREAK_PANIC); svcBreak(USERBREAK_PANIC);
miscellaneousMenu.items[0].title = Luma_SharedConfig->selected_hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID ?
"Switch the hb. title to the current app." :
"Switch the hb. title to " HBLDR_DEFAULT_3DSX_TITLE_NAME;
// **** DO NOT init services that don't come from KIPs here **** // **** DO NOT init services that don't come from KIPs here ****
// Instead, init the service only where it's actually init (then deinit it). // Instead, init the service only where it's actually init (then deinit it).

View File

@ -88,20 +88,19 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
{ {
Result res; Result res;
char failureReason[64]; char failureReason[64];
u64 currentTid = Luma_SharedConfig->hbldr_3dsx_tid; u64 currentTid = Luma_SharedConfig->selected_hbldr_3dsx_tid;
u64 newTid = currentTid; u64 newTid = currentTid;
FS_ProgramInfo progInfo;
u32 pid;
u32 launchFlags;
res = PMDBG_GetCurrentAppInfo(&progInfo, &pid, &launchFlags);
bool appRunning = R_SUCCEEDED(res);
if(compareTids(currentTid, HBLDR_DEFAULT_3DSX_TID)) if(compareTids(currentTid, HBLDR_DEFAULT_3DSX_TID))
{ {
FS_ProgramInfo progInfo; if(appRunning)
u32 pid;
u32 launchFlags;
res = PMDBG_GetCurrentAppInfo(&progInfo, &pid, &launchFlags);
if(R_SUCCEEDED(res))
{
newTid = progInfo.programId; newTid = progInfo.programId;
Luma_SharedConfig->hbldr_3dsx_tid = progInfo.programId;
}
else else
{ {
res = -1; res = -1;
@ -114,7 +113,18 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
newTid = HBLDR_DEFAULT_3DSX_TID; newTid = HBLDR_DEFAULT_3DSX_TID;
} }
Luma_SharedConfig->hbldr_3dsx_tid = newTid; Luma_SharedConfig->selected_hbldr_3dsx_tid = newTid;
// Move "selected" field to "current" if no app is currently running.
// Otherwise, PM will do it on app exit.
// There's a small possibility of race condition but it shouldn't matter
// here.
// We need to do that to ensure that the ExHeader at init matches the ExHeader
// at termination at all times, otherwise the process refcounts of sysmodules
// get all messed up.
if (!appRunning)
Luma_SharedConfig->hbldr_3dsx_tid = newTid;
if (compareTids(newTid, HBLDR_DEFAULT_3DSX_TID)) if (compareTids(newTid, HBLDR_DEFAULT_3DSX_TID))
miscellaneousMenu.items[0].title = "Switch the hb. title to the current app."; miscellaneousMenu.items[0].title = "Switch the hb. title to the current app.";
else else