From f86dc2ceba76dda8743369c8883332980b11020f Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 15 Apr 2020 19:43:19 -0700 Subject: [PATCH] pgl: implement full api --- nx/include/switch/services/pgl.h | 44 +++++++++++++ nx/source/services/pgl.c | 110 ++++++++++++++++++++++++++++++- 2 files changed, 151 insertions(+), 3 deletions(-) diff --git a/nx/include/switch/services/pgl.h b/nx/include/switch/services/pgl.h index a6d375ed..c3525f56 100644 --- a/nx/include/switch/services/pgl.h +++ b/nx/include/switch/services/pgl.h @@ -7,6 +7,35 @@ #pragma once #include "../types.h" #include "../sf/service.h" +#include "../services/ncm_types.h" +#include "../services/pm.h" + +/// LaunchFlag +typedef enum { + PglLaunchFlag_None = 0, + PglLaunchFlag_EnableDetailedCrashReport = BIT(0), + PglLaunchFlag_EnableCrashReportScreenShotForProduction = BIT(1), + PglLaunchFlag_EnableCrashReportScreenShotForDevelop = BIT(2), +} PglLaunchFlag; + +/// SnapShotDumpType +typedef enum { + PglSnapShotDumpType_None = 0, + PglSnapShotDumpType_Auto = 1, + PglSnapShotDumpType_Full = 2, +} PglSnapShotDumpType; + +typedef struct { + u64 id; ///< Program Id + u32 version; ///< Version + u8 content_type; ///< NcmContentType + u8 id_offset; ///< Id Offset + u8 reserved_0E[2]; ///< Padding +} PglContentMetaInfo; + +typedef struct { + Service s; +} PglEventObserver; /// Initialize pgl. Result pglInitialize(void); @@ -17,4 +46,19 @@ void pglExit(void); /// Gets the Service object for the actual pgl service session. Service* pglGetServiceSession(void); +Result pglLaunchProgram(u64 *out_pid, const NcmProgramLocation *loc, u32 pm_launch_flags, u8 pgl_launch_flags); Result pglTerminateProcess(u64 pid); +Result pglLaunchProgramFromHost(u64 *out_pid, const char *content_path, u32 pm_launch_flags); +Result pglGetHostContentMetaInfo(PglContentMetaInfo *out, const char *content_path); +Result pglGetApplicationProcessId(u64 *out); +Result pglBoostSystemMemoryResourceLimit(u64 size); +Result pglIsProcessTracked(bool *out, u64 pid); +Result pglEnableApplicationCrashReport(bool en); +Result pglIsApplicationCrashReportEnabled(bool *out); +Result pglEnableApplicationAllThreadDumpOnCrash(bool en); +Result pglTriggerApplicationSnapShotDumper(PglSnapShotDumpType dump_type, const char *arg); +Result pglGetEventObserver(PglEventObserver *out); + +Result pglEventObserverGetProcessEvent(PglEventObserver *observer, Event *out); +Result pglEventObserverGetProcessEventInfo(PglEventObserver *observer, PmProcessEventInfo *out); +void pglEventObserverClose(PglEventObserver *observer); diff --git a/nx/source/services/pgl.c b/nx/source/services/pgl.c index f3896623..4d08c2b0 100644 --- a/nx/source/services/pgl.c +++ b/nx/source/services/pgl.c @@ -1,4 +1,5 @@ #define NX_SERVICE_ASSUME_NON_DOMAIN +#include #include "service_guard.h" #include "services/pgl.h" #include "runtime/hosversion.h" @@ -21,10 +22,113 @@ Service* pglGetServiceSession(void) { return &g_pglSrv; } -static Result _pglCmdInU64(Service* srv, u32 cmd_id, u64 inval) { +static Result _pglCmdInBool(Service* srv, bool inval, u32 cmd_id) { + const u8 in = inval; + return serviceDispatchIn(srv, cmd_id, in); +} + +static Result _pglCmdOutBool(Service* srv, bool *out, u32 cmd_id) { + u8 outval = 0; + Result rc = serviceDispatchOut(srv, cmd_id, outval); + if (R_SUCCEEDED(rc)) { + if (out) *out = outval & 1; + } + return rc; +} + +static Result _pglCmdInU64(Service* srv, u64 inval, u32 cmd_id) { return serviceDispatchIn(srv, cmd_id, inval); } -Result pglTerminateProcess(u64 pid) { - return _pglCmdInU64(&g_pglSrv, 1, pid); +Result pglLaunchProgram(u64 *out_pid, const NcmProgramLocation *loc, u32 pm_launch_flags, u8 pgl_launch_flags) { + const struct { + u8 pgl_flags; + u32 pm_flags; + NcmProgramLocation loc; + } in = { pgl_launch_flags, pm_launch_flags, *loc }; + return serviceDispatchInOut(&g_pglSrv, 0, in, *out_pid); +} + +Result pglTerminateProcess(u64 pid) { + return _pglCmdInU64(&g_pglSrv, pid, 1); +} + +Result pglLaunchProgramFromHost(u64 *out_pid, const char *content_path, u32 pm_launch_flags) { + return serviceDispatchInOut(&g_pglSrv, 2, pm_launch_flags, *out_pid, + .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias }, + .buffers = { { content_path, strlen(content_path) + 1 } }, + ); +} + +Result pglGetHostContentMetaInfo(PglContentMetaInfo *out, const char *content_path) { + return serviceDispatchOut(&g_pglSrv, 4, *out, + .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias }, + .buffers = { { content_path, strlen(content_path) + 1 } }, + ); +} + +Result pglGetApplicationProcessId(u64 *out) { + return serviceDispatchOut(&g_pglSrv, 5, *out); +} + +Result pglBoostSystemMemoryResourceLimit(u64 size) { + return _pglCmdInU64(&g_pglSrv, size, 6); +} + +Result pglIsProcessTracked(bool *out, u64 pid) { + u8 outval = 0; + Result rc = serviceDispatchInOut(&g_pglSrv, 7, pid, outval); + if (R_SUCCEEDED(rc)) { + if (out) *out = outval & 1; + } + return rc; +} + +Result pglEnableApplicationCrashReport(bool en) { + return _pglCmdInBool(&g_pglSrv, en, 8); +} + +Result pglIsApplicationCrashReportEnabled(bool *out) { + return _pglCmdOutBool(&g_pglSrv, out, 9); +} + +Result pglEnableApplicationAllThreadDumpOnCrash(bool en) { + return _pglCmdInBool(&g_pglSrv, en, 10); +} + +Result pglTriggerApplicationSnapShotDumper(PglSnapShotDumpType dump_type, const char *arg) { + _Static_assert(sizeof(dump_type) == sizeof(u32), "PglSnapShotDumpType"); + return serviceDispatchIn(&g_pglSrv, 12, dump_type, + .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias }, + .buffers = { { arg, strlen(arg) + 1 } }, + ); +} + +Result pglGetEventObserver(PglEventObserver *out) { + return serviceDispatch(&g_pglSrv, 20, + .out_num_objects = 1, + .out_objects = &out->s, + ); +} + +Result pglEventObserverGetProcessEvent(PglEventObserver *observer, Event *out) { + Handle evt_handle; + Result rc = serviceDispatch(&observer->s, 0, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &evt_handle, + ); + + if (R_SUCCEEDED(rc)) { + eventLoadRemote(out, evt_handle, true); + } + + return rc; +} + +Result pglEventObserverGetProcessEventInfo(PglEventObserver *observer, PmProcessEventInfo *out) { + return serviceDispatchOut(&observer->s, 1, *out); +} + +void pglEventObserverClose(PglEventObserver *observer) { + serviceClose(&observer->s); }