From 22ec0314956d2ea8a2692f9d2debe5ab7c66d38c Mon Sep 17 00:00:00 2001 From: TuxSH Date: Sat, 30 Mar 2019 18:12:54 +0100 Subject: [PATCH] Add client code for new custom pm commands, use them, fix pm race conditions --- sysmodules/pm/source/info.c | 9 +++- sysmodules/pm/source/launch.c | 24 +++++++++- sysmodules/pm/source/process_monitor.c | 6 ++- sysmodules/pm/source/termination.c | 4 +- sysmodules/rosalina/include/pmdbgext.h | 10 ++++ sysmodules/rosalina/source/main.c | 4 ++ .../rosalina/source/menus/miscellaneous.c | 22 +-------- sysmodules/rosalina/source/pmdbgext.c | 47 +++++++++++++++++++ 8 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 sysmodules/rosalina/include/pmdbgext.h create mode 100644 sysmodules/rosalina/source/pmdbgext.c diff --git a/sysmodules/pm/source/info.c b/sysmodules/pm/source/info.c index 9256a25..19c771f 100644 --- a/sysmodules/pm/source/info.c +++ b/sysmodules/pm/source/info.c @@ -128,11 +128,16 @@ Result GetTitleExHeaderFlags(ExHeader_Arm11CoreInfo *outCoreInfo, ExHeader_Syste Result GetCurrentAppTitleId(u64 *outTitleId) { + ProcessList_Lock(&g_manager.processList); + Result res; if (g_manager.runningApplicationData != NULL) { *outTitleId = g_manager.runningApplicationData->titleId; - return 0; + res = 0; } else { *outTitleId = 0; - return MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100); + res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100); } + ProcessList_Unlock(&g_manager.processList); + + return res; } diff --git a/sysmodules/pm/source/launch.c b/sysmodules/pm/source/launch.c index 17c80c4..ba0a022 100644 --- a/sysmodules/pm/source/launch.c +++ b/sysmodules/pm/source/launch.c @@ -243,6 +243,7 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const // note: official pm doesn't terminate the proc. if it fails here either, but will because of the svcCloseHandle and the svcRun codepath } + ProcessList_Lock(&g_manager.processList); ProcessData *process = *outProcessData; if (launchFlags & PMLAUNCHFLAG_QUEUE_DEBUG_APPLICATION) { // saved field is different in official pm @@ -271,6 +272,7 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const process->flags |= (launchFlags & PMLAUNCHFLAG_NOTIFY_TERMINATION) ? PROCESSFLAG_NOTIFY_TERMINATION : 0; } + ProcessList_Unlock(&g_manager.processList); return res; } @@ -323,11 +325,12 @@ Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFla panic(4); } + ProcessList_Lock(&g_manager.processList); if (g_manager.runningApplicationData != NULL && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) { + ProcessList_Unlock(&g_manager.processList); return 0xC8A05BF0; } - ProcessList_Lock(&g_manager.processList); FOREACH_PROCESS(&g_manager.processList, process) { if ((process->titleId & ~0xFFULL) == (programInfo->programId & ~0xFFULL)) { foundProcess = process; @@ -370,15 +373,18 @@ Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFla Result LaunchTitleUpdate(const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags) { + ProcessList_Lock(&g_manager.processList); if (g_manager.preparingForReboot) { return 0xC8A05801; } if (g_manager.runningApplicationData != NULL) { + ProcessList_Unlock(&g_manager.processList); return 0xC8A05BF0; } if (!(launchFlags & ~PMLAUNCHFLAG_NORMAL_APPLICATION)) { return 0xD8E05802; } + ProcessList_Unlock(&g_manager.processList); bool originallyDebugged = launchFlags & PMLAUNCHFLAG_QUEUE_DEBUG_APPLICATION; @@ -408,11 +414,15 @@ Result LaunchTitleUpdate(const FS_ProgramInfo *programInfo, const FS_ProgramInfo Result LaunchApp(const FS_ProgramInfo *programInfo, u32 launchFlags) { + ProcessList_Lock(&g_manager.processList); if (g_manager.runningApplicationData != NULL) { + ProcessList_Unlock(&g_manager.processList); return 0xC8A05BF0; } assertSuccess(setAppCpuTimeLimit(0)); + ProcessList_Unlock(&g_manager.processList); + return LaunchTitle(NULL, programInfo, launchFlags | PMLAUNCHFLAG_LOAD_DEPENDENCIES | PMLAUNCHFLAG_NORMAL_APPLICATION); } @@ -421,10 +431,13 @@ Result RunQueuedProcess(Handle *outDebug) Result res = 0; StartupInfo si = {0}; + ProcessList_Lock(&g_manager.processList); if (g_manager.debugData == NULL) { + ProcessList_Unlock(&g_manager.processList); return 0xD8A05804; } else if ((g_manager.debugData->flags & PROCESSFLAG_NORMAL_APPLICATION) && g_manager.runningApplicationData != NULL) { // Not in official PM + ProcessList_Unlock(&g_manager.processList); return 0xC8A05BF0; } @@ -455,17 +468,21 @@ Result RunQueuedProcess(Handle *outDebug) } ExHeaderInfoHeap_Delete(exheaderInfo); + ProcessList_Unlock(&g_manager.processList); return res; } Result LaunchAppDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags) { + ProcessList_Lock(&g_manager.processList); if (g_manager.debugData != NULL) { + ProcessList_Unlock(&g_manager.processList); return RunQueuedProcess(outDebug); } if (g_manager.runningApplicationData != NULL) { + ProcessList_Unlock(&g_manager.processList); return 0xC8A05BF0; } @@ -473,6 +490,8 @@ Result LaunchAppDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 l g_debugNextApplication = false; assertSuccess(setAppCpuTimeLimit(0)); + ProcessList_Unlock(&g_manager.processList); + Result res = launchTitleImplWrapper(outDebug, NULL, programInfo, programInfo, (launchFlags & ~PMLAUNCHFLAG_USE_UPDATE_TITLE) | PMLAUNCHFLAG_NORMAL_APPLICATION); @@ -509,9 +528,12 @@ Result LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 return LaunchAppDebug(outDebug, programInfo, launchFlags); } + ProcessList_Lock(&g_manager.processList); if (g_manager.debugData != NULL) { + ProcessList_Unlock(&g_manager.processList); return RunQueuedProcess(outDebug); } + ProcessList_Unlock(&g_manager.processList); return launchTitleImplWrapper(outDebug, NULL, programInfo, programInfo, launchFlags & ~PMLAUNCHFLAG_USE_UPDATE_TITLE); } diff --git a/sysmodules/pm/source/process_monitor.c b/sysmodules/pm/source/process_monitor.c index dbc8968..cf65958 100644 --- a/sysmodules/pm/source/process_monitor.c +++ b/sysmodules/pm/source/process_monitor.c @@ -27,16 +27,18 @@ static void cleanupProcess(ProcessData *process) LOADER_UnregisterProgram(process->programHandle); } - if (process == g_manager.runningApplicationData) { + ProcessList_Lock(&g_manager.processList); + if (g_manager.runningApplicationData != NULL && process->handle == g_manager.runningApplicationData->handle) { if (IS_N3DS && APPMEMTYPE == 6) { assertSuccess(resetAppMemLimit()); } g_manager.runningApplicationData = NULL; } - if (process == g_manager.debugData) { + if (g_manager.debugData != NULL && process->handle == g_manager.debugData->handle) { g_manager.debugData = NULL; } + ProcessList_Unlock(&g_manager.processList); if (process->flags & PROCESSFLAG_NOTIFY_TERMINATION) { notifySubscribers(0x110 + process->terminatedNotificationVariation); diff --git a/sysmodules/pm/source/termination.c b/sysmodules/pm/source/termination.c index 9b724f4..6b9d027 100644 --- a/sysmodules/pm/source/termination.c +++ b/sysmodules/pm/source/termination.c @@ -215,9 +215,11 @@ Result TerminateApplication(s64 timeout) assertSuccess(svcClearEvent(g_manager.allNotifiedTerminationEvent)); g_manager.waitingForTermination = true; + ProcessList_Lock(&g_manager.processList); if (g_manager.runningApplicationData != NULL) { terminateProcessImpl(g_manager.runningApplicationData, exheaderInfo); } + ProcessList_Unlock(&g_manager.processList); res = commitPendingTerminations(timeout); @@ -266,6 +268,7 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout) ProcessList_Unlock(&g_manager.processList); } + ProcessList_Lock(&g_manager.processList); // Send notification 0x100 to the currently running application if (g_manager.runningApplicationData != NULL) { g_manager.runningApplicationData->flags &= ~PROCESSFLAG_DEPENDENCIES_LOADED; @@ -274,7 +277,6 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout) // Send notification 0x100 to anything but the caller deps or the caller; and *increase* the refcount of the latter if autoloaded // Ignore KIPs - ProcessList_Lock(&g_manager.processList); FOREACH_PROCESS(&g_manager.processList, process) { if (process->flags & PROCESSFLAG_KIP) { continue; diff --git a/sysmodules/rosalina/include/pmdbgext.h b/sysmodules/rosalina/include/pmdbgext.h new file mode 100644 index 0000000..19d1d67 --- /dev/null +++ b/sysmodules/rosalina/include/pmdbgext.h @@ -0,0 +1,10 @@ +// License for this file: ctrulib's license +// Copyright AuroraWright, TuxSH 2019 + +#pragma once + +#include <3ds/services/pmapp.h> + +Result PMDBG_GetCurrentAppTitleId(u64 *outTitleId); +Result PMDBG_DebugNextApplicationByForce(void); +Result PMDBG_LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags); diff --git a/sysmodules/rosalina/source/main.c b/sysmodules/rosalina/source/main.c index 32b6638..62aa311 100644 --- a/sysmodules/rosalina/source/main.c +++ b/sysmodules/rosalina/source/main.c @@ -84,11 +84,15 @@ void __appInit() if (R_FAILED(stealFsReg()) || R_FAILED(fsRegSetupPermissions()) || R_FAILED(fsInit())) svcBreak(USERBREAK_PANIC); + + if (R_FAILED(pmDbgInit())) + svcBreak(USERBREAK_PANIC); } // this is called after main exits void __appExit() { + pmDbgExit(); fsExit(); svcCloseHandle(*fsRegGetSessionHandle()); srvExit(); diff --git a/sysmodules/rosalina/source/menus/miscellaneous.c b/sysmodules/rosalina/source/menus/miscellaneous.c index 540ff46..90f6f3d 100644 --- a/sysmodules/rosalina/source/menus/miscellaneous.c +++ b/sysmodules/rosalina/source/menus/miscellaneous.c @@ -34,6 +34,7 @@ #include "utils.h" // for makeARMBranch #include "minisoc.h" #include "ifile.h" +#include "pmdbgext.h" Menu miscellaneousMenu = { "Miscellaneous options menu", @@ -54,31 +55,12 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void) if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID) { - u32 pidList[0x40]; - s32 processAmount; - - res = svcGetProcessList(&processAmount, pidList, 0x40); + res = PMDBG_GetCurrentAppTitleId(&titleId); if(R_SUCCEEDED(res)) - { - for(s32 i = 0; i < processAmount && (u32)(titleId >> 32) != 0x00040010 && (u32)(titleId >> 32) != 0x00040000; i++) - { - Handle processHandle; - Result res = svcOpenProcess(&processHandle, pidList[i]); - if(R_FAILED(res)) - continue; - - svcGetProcessInfo((s64 *)&titleId, processHandle, 0x10001); - svcCloseHandle(processHandle); - } - } - - if(R_SUCCEEDED(res) && ((u32)(titleId >> 32) == 0x00040010 || (u32)(titleId >> 32) == 0x00040000)) { HBLDR_3DSX_TID = titleId; miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader"; } - else if(R_FAILED(res)) - sprintf(failureReason, "%08lx", (u32)res); else { res = -1; diff --git a/sysmodules/rosalina/source/pmdbgext.c b/sysmodules/rosalina/source/pmdbgext.c new file mode 100644 index 0000000..4f69cdf --- /dev/null +++ b/sysmodules/rosalina/source/pmdbgext.c @@ -0,0 +1,47 @@ +// License for this file: ctrulib's license +// Copyright AuroraWright, TuxSH 2019 + +#include +#include <3ds/types.h> +#include <3ds/result.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/synchronization.h> +#include <3ds/services/pmdbg.h> +#include <3ds/ipc.h> + +Result PMDBG_GetCurrentAppTitleId(u64 *outTitleId) +{ + 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); + return cmdbuf[1]; +} + +Result PMDBG_DebugNextApplicationByForce(void) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x101, 0, 0); + + if(R_FAILED(ret = svcSendSyncRequest(*pmDbgGetSessionHandle()))) return ret; + return cmdbuf[1]; +} + +Result PMDBG_LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x102, 5, 0); + memcpy(&cmdbuf[1], programInfo, sizeof(FS_ProgramInfo)); + cmdbuf[5] = launchFlags; + + if(R_FAILED(ret = svcSendSyncRequest(*pmDbgGetSessionHandle()))) return ret; + + *outDebug = cmdbuf[3]; + return (Result)cmdbuf[1]; +}