From d3e62df769d95ac817f4c78a3481b834c327c17f Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Sun, 10 May 2020 02:58:21 +0100 Subject: [PATCH] rosalina: implement dirty hb chainload --- sysmodules/pm/source/info.c | 13 +++++++--- sysmodules/pm/source/info.h | 2 +- sysmodules/pm/source/launch.c | 7 ++++++ sysmodules/pm/source/launch.h | 5 ++++ sysmodules/pm/source/main.c | 2 +- sysmodules/pm/source/manager.c | 24 ++++++++++++++++++ sysmodules/pm/source/manager.h | 1 + sysmodules/pm/source/pmdbg.c | 22 +++++++++------- sysmodules/pm/source/process_data.h | 2 ++ sysmodules/rosalina/include/hbloader.h | 1 + sysmodules/rosalina/include/pmdbgext.h | 8 +++++- sysmodules/rosalina/source/hbloader.c | 25 +++++++++++++++++++ sysmodules/rosalina/source/main.c | 9 ++++++- sysmodules/rosalina/source/menus/cheats.c | 6 ++++- .../rosalina/source/menus/miscellaneous.c | 7 +++--- sysmodules/rosalina/source/pmdbgext.c | 20 ++++++++++++--- 16 files changed, 130 insertions(+), 24 deletions(-) diff --git a/sysmodules/pm/source/info.c b/sysmodules/pm/source/info.c index ed43edf..d8b5a16 100644 --- a/sysmodules/pm/source/info.c +++ b/sysmodules/pm/source/info.c @@ -129,16 +129,21 @@ Result GetTitleExHeaderFlags(ExHeader_Arm11CoreInfo *outCoreInfo, ExHeader_Syste return res; } -Result GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid) +Result GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags) { ProcessList_Lock(&g_manager.processList); Result res; + + memset(outProgramInfo, 0, sizeof(FS_ProgramInfo)); if (g_manager.runningApplicationData != NULL) { - *outTitleId = g_manager.runningApplicationData->titleId; - *outPid = g_manager.runningApplicationData->pid; + ProcessData *app = g_manager.runningApplicationData; + outProgramInfo->programId = app->titleId; + outProgramInfo->mediaType = app->mediaType; + *outPid = app->pid; + *outLaunchFlags = app->launchFlags; res = 0; } else { - *outTitleId = 0; + *outPid = 0; res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100); } ProcessList_Unlock(&g_manager.processList); diff --git a/sysmodules/pm/source/info.h b/sysmodules/pm/source/info.h index 214af62..bc91ae7 100644 --- a/sysmodules/pm/source/info.h +++ b/sysmodules/pm/source/info.h @@ -12,4 +12,4 @@ Result listMergeUniqueDependencies(ProcessData **procs, u64 *dependencies, u32 * Result GetTitleExHeaderFlags(ExHeader_Arm11CoreInfo *outCoreInfo, ExHeader_SystemInfoFlags *outSiFlags, const FS_ProgramInfo *programInfo); // Custom -Result GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid); +Result GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags); diff --git a/sysmodules/pm/source/launch.c b/sysmodules/pm/source/launch.c index 514d7ec..e5720e9 100644 --- a/sysmodules/pm/source/launch.c +++ b/sysmodules/pm/source/launch.c @@ -56,10 +56,12 @@ static Result loadWithoutDependencies(Handle *outDebug, ProcessData **outProcess process->pid = pid; process->titleId = exheaderInfo->aci.local_caps.title_id;; process->programHandle = programHandle; + process->launchFlags = launchFlags; // not in official PM process->flags = 0; // will be filled later process->terminatedNotificationVariation = (launchFlags & 0xF0) >> 4; process->terminationStatus = TERMSTATUS_RUNNING; process->refcount = 1; + process->mediaType = programInfo->mediaType; // not in official PM ProcessList_Unlock(&g_manager.processList); svcSignalEvent(g_manager.newProcessEvent); @@ -135,6 +137,11 @@ static Result loadWithDependencies(Handle *outDebug, ProcessData **outProcessDat process->flags |= PROCESSFLAG_DEPENDENCIES_LOADED; } + if (launchFlags & PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING) { + // See no evil + numUnique = 0; + } + /* Official pm does this: for each dependency: diff --git a/sysmodules/pm/source/launch.h b/sysmodules/pm/source/launch.h index add0abb..e0ff125 100644 --- a/sysmodules/pm/source/launch.h +++ b/sysmodules/pm/source/launch.h @@ -4,6 +4,11 @@ #include <3ds/services/fs.h> #include "process_data.h" +/// Custom launch flags for PM launch commands. +enum { + PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING = BIT(24), +}; + Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFlags); Result LaunchTitleUpdate(const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags); Result LaunchApp(const FS_ProgramInfo *programInfo, u32 launchFlags); diff --git a/sysmodules/pm/source/main.c b/sysmodules/pm/source/main.c index 37fbb00..187d7ca 100644 --- a/sysmodules/pm/source/main.c +++ b/sysmodules/pm/source/main.c @@ -52,7 +52,7 @@ void initSystem() } static const ServiceManagerServiceEntry services[] = { - { "pm:app", 3, pmAppHandleCommands, false }, + { "pm:app", 4, pmAppHandleCommands, false }, { "pm:dbg", 2, pmDbgHandleCommands, false }, { NULL }, }; diff --git a/sysmodules/pm/source/manager.c b/sysmodules/pm/source/manager.c index ebcebd2..bd698af 100644 --- a/sysmodules/pm/source/manager.c +++ b/sysmodules/pm/source/manager.c @@ -69,3 +69,27 @@ Result UnregisterProcess(u64 titleId) ProcessList_Unlock(&g_manager.processList); return 0; } + +Result PrepareToChainloadHomebrew(u64 titleId) +{ + // Note: I'm allowing this command to be called for non-applications, maybe that'll be useful + // in the future... + + ProcessData *foundProcess = NULL; + Result res; + ProcessList_Lock(&g_manager.processList); + foundProcess = ProcessList_FindProcessByTitleId(&g_manager.processList, titleId & ~N3DS_TID_MASK); + if (foundProcess != NULL) { + // Clear the "notify on termination, don't cleanup" flag, so that for ex. APT isn't notified & no need for UnregisterProcess, + // and the "dependencies loaded" flag, so that the dependencies aren't killed (for ex. when + // booting hbmenu instead of Home Menu, in which case the same title is going to be launched...) + + foundProcess->flags &= ~(PROCESSFLAG_DEPENDENCIES_LOADED | PROCESSFLAG_NOTIFY_TERMINATION); + res = 0; + } else { + res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100); + } + + ProcessList_Unlock(&g_manager.processList); + return res; +} diff --git a/sysmodules/pm/source/manager.h b/sysmodules/pm/source/manager.h index 82346dd..ca71db4 100644 --- a/sysmodules/pm/source/manager.h +++ b/sysmodules/pm/source/manager.h @@ -21,3 +21,4 @@ extern Manager g_manager; void Manager_Init(void *procBuf, size_t numProc); void Manager_RegisterKips(void); Result UnregisterProcess(u64 titleId); +Result PrepareToChainloadHomebrew(u64 titleId); diff --git a/sysmodules/pm/source/pmdbg.c b/sysmodules/pm/source/pmdbg.c index fc49a23..6e88ded 100644 --- a/sysmodules/pm/source/pmdbg.c +++ b/sysmodules/pm/source/pmdbg.c @@ -3,6 +3,7 @@ #include "launch.h" #include "info.h" #include "util.h" +#include "manager.h" void pmDbgHandleCommands(void *ctx) { @@ -11,10 +12,10 @@ void pmDbgHandleCommands(void *ctx) u32 cmdhdr = cmdbuf[0]; FS_ProgramInfo programInfo; - Handle debug; - u64 titleId; + Handle debug; u32 pid; + u32 launchFlags; switch (cmdhdr >> 16) { case 1: @@ -40,12 +41,11 @@ void pmDbgHandleCommands(void *ctx) // Custom case 0x100: - titleId = 0; - pid = 0xFFFFFFFF; - cmdbuf[1] = GetCurrentAppTitleIdAndPid(&titleId, &pid); - cmdbuf[0] = IPC_MakeHeader(0x100, 4, 0); - memcpy(cmdbuf + 2, &titleId, 8); - cmdbuf[4] = pid; + cmdbuf[1] = GetCurrentAppInfo(&programInfo, &pid, &launchFlags); + cmdbuf[0] = IPC_MakeHeader(0x100, 7, 0); + memcpy(cmdbuf + 2, &programInfo, sizeof(FS_ProgramInfo)); + cmdbuf[6] = pid; + cmdbuf[7] = launchFlags; break; case 0x101: cmdbuf[1] = DebugNextApplicationByForce(cmdbuf[1] != 0); @@ -59,7 +59,11 @@ void pmDbgHandleCommands(void *ctx) cmdbuf[2] = IPC_Desc_MoveHandles(1); cmdbuf[3] = debug; break; - + case 0x103: + memcpy(&titleId, cmdbuf + 1, 8); + cmdbuf[1] = PrepareToChainloadHomebrew(titleId); + cmdbuf[0] = IPC_MakeHeader(0x103, 1, 0); + break; default: cmdbuf[0] = IPC_MakeHeader(0, 1, 0); cmdbuf[1] = 0xD900182F; diff --git a/sysmodules/pm/source/process_data.h b/sysmodules/pm/source/process_data.h index e13dd4f..933c71b 100644 --- a/sysmodules/pm/source/process_data.h +++ b/sysmodules/pm/source/process_data.h @@ -29,10 +29,12 @@ typedef struct ProcessData { u32 pid; u64 titleId; u64 programHandle; + u32 launchFlags; u8 flags; u8 terminatedNotificationVariation; TerminationStatus terminationStatus; u8 refcount; + FS_MediaType mediaType; } ProcessData; typedef struct ProcessList { diff --git a/sysmodules/rosalina/include/hbloader.h b/sysmodules/rosalina/include/hbloader.h index 4f2c0d5..a6fb94d 100644 --- a/sysmodules/rosalina/include/hbloader.h +++ b/sysmodules/rosalina/include/hbloader.h @@ -33,4 +33,5 @@ #define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL #define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100) +void HBLDR_RestartHbApplication(void *p); void HBLDR_HandleCommands(void *ctx); diff --git a/sysmodules/rosalina/include/pmdbgext.h b/sysmodules/rosalina/include/pmdbgext.h index 8a593f5..64491e8 100644 --- a/sysmodules/rosalina/include/pmdbgext.h +++ b/sysmodules/rosalina/include/pmdbgext.h @@ -6,6 +6,12 @@ #include <3ds/services/pmapp.h> #include <3ds/services/pmdbg.h> -Result PMDBG_GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid); +/// Custom launch flags for PM launch commands. +enum { + PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING = BIT(24), +}; + +Result PMDBG_GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags); Result PMDBG_DebugNextApplicationByForce(bool debug); Result PMDBG_LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags); +Result PMDBG_PrepareToChainloadHomebrew(u64 titleId); diff --git a/sysmodules/rosalina/source/hbloader.c b/sysmodules/rosalina/source/hbloader.c index 0841013..8dcb4e7 100644 --- a/sysmodules/rosalina/source/hbloader.c +++ b/sysmodules/rosalina/source/hbloader.c @@ -178,6 +178,31 @@ static u16 *u16_strncpy(u16 *dest, const u16 *src, u32 size) return dest; } +void HBLDR_RestartHbApplication(void *p) +{ + (void)p; + // Don't crash if we fail + + FS_ProgramInfo programInfo; + u32 pid; + u32 launchFlags; + + Result res = PMDBG_GetCurrentAppInfo(&programInfo, &pid, &launchFlags); + if (R_FAILED(res)) return; + res = PMDBG_PrepareToChainloadHomebrew(programInfo.programId); + if (R_FAILED(res)) return; + res = PMAPP_TerminateCurrentApplication(3 * 1000 * 1000 *1000LL); // 3s, like what NS uses + if (R_FAILED(res)) return; + if (R_SUCCEEDED(res)) + { + do + { + svcSleepThread(100 * 1000 * 1000LL); + res = PMAPP_LaunchTitle(&programInfo, PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING | launchFlags); + } while (res == (Result)0xC8A05BF0); + } +} + void HBLDR_HandleCommands(void *ctx) { (void)ctx; diff --git a/sysmodules/rosalina/source/main.c b/sysmodules/rosalina/source/main.c index 496005c..0e8c552 100644 --- a/sysmodules/rosalina/source/main.c +++ b/sysmodules/rosalina/source/main.c @@ -135,7 +135,7 @@ void initSystem(void) if (R_FAILED(stealFsReg()) || R_FAILED(fsRegSetupPermissions()) || R_FAILED(fsInit())) svcBreak(USERBREAK_PANIC); - if (R_FAILED(pmDbgInit())) + if (R_FAILED(pmAppInit()) || R_FAILED(pmDbgInit())) svcBreak(USERBREAK_PANIC); // **** DO NOT init services that don't come from KIPs here **** @@ -192,6 +192,12 @@ static void handleNextApplicationDebuggedByForce(u32 notificationId) TaskRunner_RunTask(debuggerFetchAndSetNextApplicationDebugHandleTask, NULL, 0); } +static void handleRestartHbAppNotification(u32 notificationId) +{ + (void)notificationId; + TaskRunner_RunTask(HBLDR_RestartHbApplication, NULL, 0); +} + static const ServiceManagerServiceEntry services[] = { { "hb:ldr", 2, HBLDR_HandleCommands, true }, { NULL }, @@ -202,6 +208,7 @@ static const ServiceManagerNotificationEntry notifications[] = { //{ 0x103 , relinquishConnectionSessions }, // Sleep mode entry <=== causes issues { 0x1000, handleNextApplicationDebuggedByForce }, { 0x2000, relinquishConnectionSessions }, + { 0x3000, handleRestartHbAppNotification }, { 0x000, NULL }, }; diff --git a/sysmodules/rosalina/source/menus/cheats.c b/sysmodules/rosalina/source/menus/cheats.c index e7641be..0531b77 100644 --- a/sysmodules/rosalina/source/menus/cheats.c +++ b/sysmodules/rosalina/source/menus/cheats.c @@ -1860,12 +1860,16 @@ static void Cheat_LoadCheatsIntoMemory(u64 titleId) static u32 Cheat_GetCurrentProcessAndTitleId(u64* titleId) { + FS_ProgramInfo programInfo; u32 pid; - Result res = PMDBG_GetCurrentAppTitleIdAndPid(titleId, &pid); + u32 launchFlags; + Result res = PMDBG_GetCurrentAppInfo(&programInfo, &pid, &launchFlags); if (R_FAILED(res)) { *titleId = 0; return 0xFFFFFFFF; } + + *titleId = programInfo.programId; return pid; } diff --git a/sysmodules/rosalina/source/menus/miscellaneous.c b/sysmodules/rosalina/source/menus/miscellaneous.c index 45940e1..e7b5503 100644 --- a/sysmodules/rosalina/source/menus/miscellaneous.c +++ b/sysmodules/rosalina/source/menus/miscellaneous.c @@ -52,16 +52,17 @@ Menu miscellaneousMenu = { void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void) { Result res; - u64 titleId = 0; char failureReason[64]; if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID) { + FS_ProgramInfo progInfo; u32 pid; - res = PMDBG_GetCurrentAppTitleIdAndPid(&titleId, &pid); + u32 launchFlags; + res = PMDBG_GetCurrentAppInfo(&progInfo, &pid, &launchFlags); if(R_SUCCEEDED(res)) { - HBLDR_3DSX_TID = titleId; + HBLDR_3DSX_TID = progInfo.programId; miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader"; } else diff --git a/sysmodules/rosalina/source/pmdbgext.c b/sysmodules/rosalina/source/pmdbgext.c index 0461a7f..48af096 100644 --- a/sysmodules/rosalina/source/pmdbgext.c +++ b/sysmodules/rosalina/source/pmdbgext.c @@ -10,15 +10,16 @@ #include <3ds/services/pmdbg.h> #include <3ds/ipc.h> -Result PMDBG_GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid) +Result PMDBG_GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x100, 0, 0); if(R_FAILED(ret = svcSendSyncRequest(*pmDbgGetSessionHandle()))) return ret; - memcpy(outTitleId, cmdbuf + 2, 8); - *outPid = cmdbuf[4]; + memcpy(outProgramInfo, cmdbuf + 2, sizeof(FS_ProgramInfo)); + *outPid = cmdbuf[6]; + *outLaunchFlags = cmdbuf[7]; return cmdbuf[1]; } @@ -47,3 +48,16 @@ Result PMDBG_LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInf *outDebug = cmdbuf[3]; return (Result)cmdbuf[1]; } + +Result PMDBG_PrepareToChainloadHomebrew(u64 titleId) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x103, 2, 0); + memcpy(&cmdbuf[1], &titleId, 8); + + if(R_FAILED(ret = svcSendSyncRequest(*pmDbgGetSessionHandle()))) return ret; + + return (Result)cmdbuf[1]; +}