From 0fad4244dad15e3a6e03a8bb7e68de612ebf4db8 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sun, 9 Dec 2018 04:02:46 -0800 Subject: [PATCH] Add ro:dmnt, ldr:ro. --- nx/include/switch.h | 1 + nx/include/switch/services/ldr.h | 4 +- nx/include/switch/services/ro.h | 23 +++ nx/source/services/ldr.c | 4 +- nx/source/services/ro.c | 284 +++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+), 4 deletions(-) create mode 100644 nx/include/switch/services/ro.h create mode 100644 nx/source/services/ro.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 33f25f84..7eea2ca9 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -71,6 +71,7 @@ extern "C" { #include "switch/services/nifm.h" #include "switch/services/ns.h" #include "switch/services/ldr.h" +#include "switch/services/ro.h" #include "switch/services/pm.h" #include "switch/services/set.h" #include "switch/services/lr.h" diff --git a/nx/include/switch/services/ldr.h b/nx/include/switch/services/ldr.h index e3df32f3..6d822af2 100644 --- a/nx/include/switch/services/ldr.h +++ b/nx/include/switch/services/ldr.h @@ -26,7 +26,7 @@ typedef struct { u64 base_address; u64 size; u8 build_id[0x20]; -} LoaderNsoInfo; +} LoaderModuleInfo; Result ldrShellInitialize(void); void ldrShellExit(void); @@ -42,7 +42,7 @@ Result ldrShellClearLaunchQueue(void); Result ldrDmntAddTitleToLaunchQueue(u64 tid, const void *args, size_t args_size); Result ldrDmntClearLaunchQueue(void); -Result ldrDmntGetNsoInfos(u64 pid, LoaderNsoInfo *out_nso_infos, size_t out_size, u32 *num_out); +Result ldrDmntGetModuleInfos(u64 pid, LoaderModuleInfo *out_module_infos, size_t out_size, u32 *num_out); Result ldrPmCreateProcess(u64 flags, u64 launch_index, Handle reslimit_h, Handle *out_process_h); Result ldrPmGetProgramInfo(u64 title_id, FsStorageId storage_id, LoaderProgramInfo *out_program_info); diff --git a/nx/include/switch/services/ro.h b/nx/include/switch/services/ro.h new file mode 100644 index 00000000..26543931 --- /dev/null +++ b/nx/include/switch/services/ro.h @@ -0,0 +1,23 @@ +/** + * @file ro.h + * @brief Relocatable Objects (ro) service IPC wrapper. + * @author SciresM + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../services/sm.h" +#include "../services/ldr.h" + +Result ldrRoInitialize(void); +void ldrRoExit(void); + +Result roDmntInitialize(void); +void roDmntExit(void); + +Result ldrRoLoadNro(u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size); +Result ldrRoUnloadNro(u64 nro_address); +Result ldrRoLoadNrr(u64 nrr_address, u64 nrr_size); +Result ldrRoUnloadNrr(u64 nrr_address); + +Result roDmntGetModuleInfos(u64 pid, LoaderModuleInfo *out_module_infos, size_t out_size, u32 *num_out); diff --git a/nx/source/services/ldr.c b/nx/source/services/ldr.c index 6b891607..7c0634b0 100644 --- a/nx/source/services/ldr.c +++ b/nx/source/services/ldr.c @@ -132,11 +132,11 @@ Result ldrDmntClearLaunchQueue(void) { return _ldrClearLaunchQueue(&g_dmntSrv); } -Result ldrDmntGetNsoInfos(u64 pid, LoaderNsoInfo *out_nso_infos, size_t out_size, u32 *num_out) { +Result ldrDmntGetModuleInfos(u64 pid, LoaderModuleInfo *out_module_infos, size_t out_size, u32 *num_out) { IpcCommand c; ipcInitialize(&c); - ipcAddRecvStatic(&c, out_nso_infos, out_size, 0); + ipcAddRecvStatic(&c, out_module_infos, out_size, 0); struct { u64 magic; diff --git a/nx/source/services/ro.c b/nx/source/services/ro.c new file mode 100644 index 00000000..d4e530b8 --- /dev/null +++ b/nx/source/services/ro.c @@ -0,0 +1,284 @@ +// Copyright 2018 SciresM +#include +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/detect.h" +#include "services/ro.h" +#include "services/sm.h" + +static Service g_roSrv, g_dmntSrv; +static u64 g_roRefCnt, g_dmntRefCnt; + +static Result _ldrRoInitialize(void); + +Result ldrRoInitialize(void) { + atomicIncrement64(&g_roRefCnt); + + if (serviceIsActive(&g_roSrv)) + return 0; + + Result rc = smGetService(&g_roSrv, "ldr:ro"); + + if (R_SUCCEEDED(rc)) { + rc = _ldrRoInitialize(); + } + + return rc; +} + +void ldrRoExit(void) { + if (atomicDecrement64(&g_roRefCnt) == 0) + serviceClose(&g_roSrv); +} + +Result roDmntInitialize(void) { + if (!kernelAbove300()) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + atomicIncrement64(&g_dmntRefCnt); + + if (serviceIsActive(&g_dmntSrv)) + return 0; + + return smGetService(&g_dmntSrv, "ro:dmnt"); +} + +void roDmntExit(void) { + if (atomicDecrement64(&g_dmntRefCnt) == 0) + serviceClose(&g_dmntSrv); +} + +Result ldrRoLoadNro(u64* out_address, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { + IpcCommand c; + ipcInitialize(&c); + ipcSendPid(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 pid; + u64 nro_address; + u64 nro_size; + u64 bss_address; + u64 bss_size; + } *raw; + + raw = serviceIpcPrepareHeader(&g_roSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + raw->pid = 0; + raw->nro_address = nro_address; + raw->nro_size = nro_size; + raw->bss_address = bss_address; + raw->bss_size = bss_size; + + Result rc = serviceIpcDispatch(&g_roSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 out_address; + } *resp; + + serviceIpcParse(&g_roSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + if (out_address) *out_address = resp->out_address; + } + } + + return rc; +} + +Result ldrRoUnloadNro(u64 nro_address) { + IpcCommand c; + ipcInitialize(&c); + ipcSendPid(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 pid; + u64 nro_address; + } *raw; + + raw = serviceIpcPrepareHeader(&g_roSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 1; + raw->pid = 0; + raw->nro_address = nro_address; + + Result rc = serviceIpcDispatch(&g_roSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_roSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result ldrRoLoadNrr(u64 nrr_address, u64 nrr_size) { + IpcCommand c; + ipcInitialize(&c); + ipcSendPid(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 pid; + u64 nrr_address; + u64 nrr_size; + } *raw; + + raw = serviceIpcPrepareHeader(&g_roSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2; + raw->pid = 0; + raw->nrr_address = nrr_address; + raw->nrr_size = nrr_size; + + Result rc = serviceIpcDispatch(&g_roSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_roSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result ldrRoUnloadNrr(u64 nrr_address) { + IpcCommand c; + ipcInitialize(&c); + ipcSendPid(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 pid; + u64 nrr_address; + } *raw; + + raw = serviceIpcPrepareHeader(&g_roSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 3; + raw->pid = 0; + raw->nrr_address = nrr_address; + + Result rc = serviceIpcDispatch(&g_roSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_roSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result _ldrRoInitialize(void) { + IpcCommand c; + ipcInitialize(&c); + ipcSendHandleCopy(&c, CUR_PROCESS_HANDLE); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_roSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 4; + + Result rc = serviceIpcDispatch(&g_roSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_roSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result roDmntGetModuleInfos(u64 pid, LoaderModuleInfo *out_module_infos, size_t out_size, u32 *num_out) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddRecvStatic(&c, out_module_infos, out_size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 pid; + } *raw; + + raw = serviceIpcPrepareHeader(&g_dmntSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + raw->pid = pid; + + Result rc = serviceIpcDispatch(&g_dmntSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u32 num_out; + } *resp; + + serviceIpcParse(&g_dmntSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc) && num_out != NULL) { + *num_out = resp->num_out; + } + } + + return rc; +}