Add client code for new custom pm commands, use them, fix pm race conditions

This commit is contained in:
TuxSH 2019-03-30 18:12:54 +01:00
parent 43b998d37d
commit 22ec031495
8 changed files with 100 additions and 26 deletions

View File

@ -128,11 +128,16 @@ Result GetTitleExHeaderFlags(ExHeader_Arm11CoreInfo *outCoreInfo, ExHeader_Syste
Result GetCurrentAppTitleId(u64 *outTitleId) Result GetCurrentAppTitleId(u64 *outTitleId)
{ {
ProcessList_Lock(&g_manager.processList);
Result res;
if (g_manager.runningApplicationData != NULL) { if (g_manager.runningApplicationData != NULL) {
*outTitleId = g_manager.runningApplicationData->titleId; *outTitleId = g_manager.runningApplicationData->titleId;
return 0; res = 0;
} else { } else {
*outTitleId = 0; *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;
} }

View File

@ -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 // 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; ProcessData *process = *outProcessData;
if (launchFlags & PMLAUNCHFLAG_QUEUE_DEBUG_APPLICATION) { if (launchFlags & PMLAUNCHFLAG_QUEUE_DEBUG_APPLICATION) {
// saved field is different in official pm // 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; process->flags |= (launchFlags & PMLAUNCHFLAG_NOTIFY_TERMINATION) ? PROCESSFLAG_NOTIFY_TERMINATION : 0;
} }
ProcessList_Unlock(&g_manager.processList);
return res; return res;
} }
@ -323,11 +325,12 @@ Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFla
panic(4); panic(4);
} }
ProcessList_Lock(&g_manager.processList);
if (g_manager.runningApplicationData != NULL && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) { if (g_manager.runningApplicationData != NULL && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) {
ProcessList_Unlock(&g_manager.processList);
return 0xC8A05BF0; return 0xC8A05BF0;
} }
ProcessList_Lock(&g_manager.processList);
FOREACH_PROCESS(&g_manager.processList, process) { FOREACH_PROCESS(&g_manager.processList, process) {
if ((process->titleId & ~0xFFULL) == (programInfo->programId & ~0xFFULL)) { if ((process->titleId & ~0xFFULL) == (programInfo->programId & ~0xFFULL)) {
foundProcess = process; 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) Result LaunchTitleUpdate(const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags)
{ {
ProcessList_Lock(&g_manager.processList);
if (g_manager.preparingForReboot) { if (g_manager.preparingForReboot) {
return 0xC8A05801; return 0xC8A05801;
} }
if (g_manager.runningApplicationData != NULL) { if (g_manager.runningApplicationData != NULL) {
ProcessList_Unlock(&g_manager.processList);
return 0xC8A05BF0; return 0xC8A05BF0;
} }
if (!(launchFlags & ~PMLAUNCHFLAG_NORMAL_APPLICATION)) { if (!(launchFlags & ~PMLAUNCHFLAG_NORMAL_APPLICATION)) {
return 0xD8E05802; return 0xD8E05802;
} }
ProcessList_Unlock(&g_manager.processList);
bool originallyDebugged = launchFlags & PMLAUNCHFLAG_QUEUE_DEBUG_APPLICATION; 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) Result LaunchApp(const FS_ProgramInfo *programInfo, u32 launchFlags)
{ {
ProcessList_Lock(&g_manager.processList);
if (g_manager.runningApplicationData != NULL) { if (g_manager.runningApplicationData != NULL) {
ProcessList_Unlock(&g_manager.processList);
return 0xC8A05BF0; return 0xC8A05BF0;
} }
assertSuccess(setAppCpuTimeLimit(0)); assertSuccess(setAppCpuTimeLimit(0));
ProcessList_Unlock(&g_manager.processList);
return LaunchTitle(NULL, programInfo, launchFlags | PMLAUNCHFLAG_LOAD_DEPENDENCIES | PMLAUNCHFLAG_NORMAL_APPLICATION); return LaunchTitle(NULL, programInfo, launchFlags | PMLAUNCHFLAG_LOAD_DEPENDENCIES | PMLAUNCHFLAG_NORMAL_APPLICATION);
} }
@ -421,10 +431,13 @@ Result RunQueuedProcess(Handle *outDebug)
Result res = 0; Result res = 0;
StartupInfo si = {0}; StartupInfo si = {0};
ProcessList_Lock(&g_manager.processList);
if (g_manager.debugData == NULL) { if (g_manager.debugData == NULL) {
ProcessList_Unlock(&g_manager.processList);
return 0xD8A05804; return 0xD8A05804;
} else if ((g_manager.debugData->flags & PROCESSFLAG_NORMAL_APPLICATION) && g_manager.runningApplicationData != NULL) { } else if ((g_manager.debugData->flags & PROCESSFLAG_NORMAL_APPLICATION) && g_manager.runningApplicationData != NULL) {
// Not in official PM // Not in official PM
ProcessList_Unlock(&g_manager.processList);
return 0xC8A05BF0; return 0xC8A05BF0;
} }
@ -455,17 +468,21 @@ Result RunQueuedProcess(Handle *outDebug)
} }
ExHeaderInfoHeap_Delete(exheaderInfo); ExHeaderInfoHeap_Delete(exheaderInfo);
ProcessList_Unlock(&g_manager.processList);
return res; return res;
} }
Result LaunchAppDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags) Result LaunchAppDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags)
{ {
ProcessList_Lock(&g_manager.processList);
if (g_manager.debugData != NULL) { if (g_manager.debugData != NULL) {
ProcessList_Unlock(&g_manager.processList);
return RunQueuedProcess(outDebug); return RunQueuedProcess(outDebug);
} }
if (g_manager.runningApplicationData != NULL) { if (g_manager.runningApplicationData != NULL) {
ProcessList_Unlock(&g_manager.processList);
return 0xC8A05BF0; return 0xC8A05BF0;
} }
@ -473,6 +490,8 @@ Result LaunchAppDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 l
g_debugNextApplication = false; g_debugNextApplication = false;
assertSuccess(setAppCpuTimeLimit(0)); assertSuccess(setAppCpuTimeLimit(0));
ProcessList_Unlock(&g_manager.processList);
Result res = launchTitleImplWrapper(outDebug, NULL, programInfo, programInfo, Result res = launchTitleImplWrapper(outDebug, NULL, programInfo, programInfo,
(launchFlags & ~PMLAUNCHFLAG_USE_UPDATE_TITLE) | PMLAUNCHFLAG_NORMAL_APPLICATION); (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); return LaunchAppDebug(outDebug, programInfo, launchFlags);
} }
ProcessList_Lock(&g_manager.processList);
if (g_manager.debugData != NULL) { if (g_manager.debugData != NULL) {
ProcessList_Unlock(&g_manager.processList);
return RunQueuedProcess(outDebug); return RunQueuedProcess(outDebug);
} }
ProcessList_Unlock(&g_manager.processList);
return launchTitleImplWrapper(outDebug, NULL, programInfo, programInfo, launchFlags & ~PMLAUNCHFLAG_USE_UPDATE_TITLE); return launchTitleImplWrapper(outDebug, NULL, programInfo, programInfo, launchFlags & ~PMLAUNCHFLAG_USE_UPDATE_TITLE);
} }

View File

@ -27,16 +27,18 @@ static void cleanupProcess(ProcessData *process)
LOADER_UnregisterProgram(process->programHandle); 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) { if (IS_N3DS && APPMEMTYPE == 6) {
assertSuccess(resetAppMemLimit()); assertSuccess(resetAppMemLimit());
} }
g_manager.runningApplicationData = NULL; g_manager.runningApplicationData = NULL;
} }
if (process == g_manager.debugData) { if (g_manager.debugData != NULL && process->handle == g_manager.debugData->handle) {
g_manager.debugData = NULL; g_manager.debugData = NULL;
} }
ProcessList_Unlock(&g_manager.processList);
if (process->flags & PROCESSFLAG_NOTIFY_TERMINATION) { if (process->flags & PROCESSFLAG_NOTIFY_TERMINATION) {
notifySubscribers(0x110 + process->terminatedNotificationVariation); notifySubscribers(0x110 + process->terminatedNotificationVariation);

View File

@ -215,9 +215,11 @@ Result TerminateApplication(s64 timeout)
assertSuccess(svcClearEvent(g_manager.allNotifiedTerminationEvent)); assertSuccess(svcClearEvent(g_manager.allNotifiedTerminationEvent));
g_manager.waitingForTermination = true; g_manager.waitingForTermination = true;
ProcessList_Lock(&g_manager.processList);
if (g_manager.runningApplicationData != NULL) { if (g_manager.runningApplicationData != NULL) {
terminateProcessImpl(g_manager.runningApplicationData, exheaderInfo); terminateProcessImpl(g_manager.runningApplicationData, exheaderInfo);
} }
ProcessList_Unlock(&g_manager.processList);
res = commitPendingTerminations(timeout); res = commitPendingTerminations(timeout);
@ -266,6 +268,7 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout)
ProcessList_Unlock(&g_manager.processList); ProcessList_Unlock(&g_manager.processList);
} }
ProcessList_Lock(&g_manager.processList);
// Send notification 0x100 to the currently running application // Send notification 0x100 to the currently running application
if (g_manager.runningApplicationData != NULL) { if (g_manager.runningApplicationData != NULL) {
g_manager.runningApplicationData->flags &= ~PROCESSFLAG_DEPENDENCIES_LOADED; 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 // Send notification 0x100 to anything but the caller deps or the caller; and *increase* the refcount of the latter if autoloaded
// Ignore KIPs // Ignore KIPs
ProcessList_Lock(&g_manager.processList);
FOREACH_PROCESS(&g_manager.processList, process) { FOREACH_PROCESS(&g_manager.processList, process) {
if (process->flags & PROCESSFLAG_KIP) { if (process->flags & PROCESSFLAG_KIP) {
continue; continue;

View File

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

View File

@ -84,11 +84,15 @@ void __appInit()
if (R_FAILED(stealFsReg()) || R_FAILED(fsRegSetupPermissions()) || R_FAILED(fsInit())) if (R_FAILED(stealFsReg()) || R_FAILED(fsRegSetupPermissions()) || R_FAILED(fsInit()))
svcBreak(USERBREAK_PANIC); svcBreak(USERBREAK_PANIC);
if (R_FAILED(pmDbgInit()))
svcBreak(USERBREAK_PANIC);
} }
// this is called after main exits // this is called after main exits
void __appExit() void __appExit()
{ {
pmDbgExit();
fsExit(); fsExit();
svcCloseHandle(*fsRegGetSessionHandle()); svcCloseHandle(*fsRegGetSessionHandle());
srvExit(); srvExit();

View File

@ -34,6 +34,7 @@
#include "utils.h" // for makeARMBranch #include "utils.h" // for makeARMBranch
#include "minisoc.h" #include "minisoc.h"
#include "ifile.h" #include "ifile.h"
#include "pmdbgext.h"
Menu miscellaneousMenu = { Menu miscellaneousMenu = {
"Miscellaneous options menu", "Miscellaneous options menu",
@ -54,31 +55,12 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID) if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID)
{ {
u32 pidList[0x40]; res = PMDBG_GetCurrentAppTitleId(&titleId);
s32 processAmount;
res = svcGetProcessList(&processAmount, pidList, 0x40);
if(R_SUCCEEDED(res)) 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; HBLDR_3DSX_TID = titleId;
miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader"; miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader";
} }
else if(R_FAILED(res))
sprintf(failureReason, "%08lx", (u32)res);
else else
{ {
res = -1; res = -1;

View File

@ -0,0 +1,47 @@
// License for this file: ctrulib's license
// Copyright AuroraWright, TuxSH 2019
#include <string.h>
#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];
}