From 075a743cfb22847fb4930d578246c81f296d52c6 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Thu, 26 Sep 2019 17:07:26 -0400 Subject: [PATCH] Added support for nssu, and added the structs/enums for it. Added NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT. Moved cmd_id param in the ns helper funcs to the last param. Improved docs. --- nx/include/switch/services/ns.h | 381 ++++++++++++++++++++++++++- nx/source/services/ns.c | 439 ++++++++++++++++++++++++++++++-- 2 files changed, 789 insertions(+), 31 deletions(-) diff --git a/nx/include/switch/services/ns.h b/nx/include/switch/services/ns.h index e8f7190b..c3826f35 100644 --- a/nx/include/switch/services/ns.h +++ b/nx/include/switch/services/ns.h @@ -8,7 +8,39 @@ #include "../types.h" #include "../nacp.h" #include "../services/fs.h" +#include "../services/ncm.h" +#include "../services/async.h" #include "../kernel/event.h" +#include "../kernel/tmem.h" + +/// ShellEvent +typedef enum { + NsShellEvent_None = 0, ///< None + NsShellEvent_Exit = 1, ///< Exit + NsShellEvent_Start = 2, ///< Start + NsShellEvent_Crash = 3, ///< Crash + NsShellEvent_Debug = 4, ///< Debug +} NsShellEvent; + +/// BackgroundNetworkUpdateState +typedef enum { + NsBackgroundNetworkUpdateState_None = 0, ///< No sysupdate task exists. + NsBackgroundNetworkUpdateState_Downloading = 1, ///< Sysupdate download in progress. + NsBackgroundNetworkUpdateState_Ready = 2, ///< Sysupdate ready, pending install. +} NsBackgroundNetworkUpdateState; + +/// LatestSystemUpdate +typedef enum { + NsLatestSystemUpdate_Unknown0 = 0, ///< Unknown. + NsLatestSystemUpdate_Unknown1 = 1, ///< Unknown. + NsLatestSystemUpdate_Unknown2 = 2, ///< Unknown. +} NsLatestSystemUpdate; + +/// SystemUpdateControl +typedef struct { + Service s; ///< ISystemUpdateControl + TransferMemory tmem; ///< TransferMemory for SetupCardUpdate/SetupCardUpdateViaSystemUpdater. +} NsSystemUpdateControl; /// ApplicationControlData typedef struct { @@ -45,21 +77,39 @@ typedef struct { u8 is_application; ///< Whether this is an Application. } NsLaunchProperties; -/// ShellEvent -typedef enum { - NsShellEvent_None = 0, ///< None - NsShellEvent_Exit = 1, ///< Exit - NsShellEvent_Start = 2, ///< Start - NsShellEvent_Crash = 3, ///< Crash - NsShellEvent_Debug = 4, ///< Debug -} NsShellEvent; - /// ShellEventInfo typedef struct { NsShellEvent event; ///< \ref NsShellEvent u64 process_id; ///< processID. } NsShellEventInfo; +/// SystemUpdateProgress. Commands which have this as output will return 0 with the output cleared, when no task is available. +typedef struct { + u64 unk_x0; ///< Unknown. + u64 unk_x8; ///< Unknown. +} NsSystemUpdateProgress; + +/// EulaDataPath +typedef struct { + char path[0x100]; ///< Path. +} NsEulaDataPath; + +/// SystemDeliveryInfo +typedef struct { + u32 protocol_version; ///< Must be <= to and match a system-setting. + u8 unk_x4[0x8]; ///< Unknown. + u32 unk_xc; ///< Unknown. + u64 unk_x10; ///< Unknown. + u8 unk_x18[0xc8]; ///< Unknown. + u8 hmac[0x20]; ///< HMAC-SHA256 over the previous 0xe0-bytes. +} NsSystemDeliveryInfo; + +/// Default size for \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater. This is the size used by qlaunch for SetupCardUpdate. +#define NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT 0x100000 + +///@name ns +///@{ + Result nsInitialize(void); void nsExit(void); @@ -106,13 +156,22 @@ Result nsGetTotalSpaceSize(FsStorageId storage_id, u64 *size); */ Result nsGetFreeSpaceSize(FsStorageId storage_id, u64 *size); +///@} + +///@name ns:vm +///@{ + Result nsvmInitialize(void); void nsvmExit(void); Result nsvmNeedsUpdateVulnerability(bool *out); Result nsvmGetSafeSystemVersion(u16 *out); -/* ns:dev */ +///@} + +///@name ns:dev +///@{ + Result nsdevInitialize(void); void nsdevExit(void); @@ -128,3 +187,305 @@ Result nsdevLaunchApplicationWithStorageIdForDevelop(u64* out_pid, u64 app_title Result nsdevIsSystemMemoryResourceLimitBoosted(bool* out); ///< [6.0.0-8.1.0] Result nsdevGetRunningApplicationProcessIdForDevelop(u64* out_pid); ///< [6.0.0+] Result nsdevSetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop(bool can_be_active); ///< [6.0.0+] + +///@} + +///@name ns:su +///@{ + +Result nssuInitialize(void); +void nssuExit(void); + +/** + * @brief Gets the \ref NsBackgroundNetworkUpdateState. + * @note Internally this uses nim commands ListSystemUpdateTask and GetSystemUpdateTaskInfo to determine the output state. + * @param[out] out \ref NsBackgroundNetworkUpdateState + */ +Result nssuGetBackgroundNetworkUpdateState(NsBackgroundNetworkUpdateState *out); + +/** + * @brief Opens a \ref NsSystemUpdateControl. + * @note Only 1 \ref NsSystemUpdateControl can be open at a time. + * @param[out] c \ref NsSystemUpdateControl + */ +Result nssuOpenSystemUpdateControl(NsSystemUpdateControl *c); + +/** + * @brief Uses nim ListSystemUpdateTask, then uses the task with DestroySystemUpdateTask if it exists. Then this runs ExFat handling, updates state, and sets the same state flag as \ref nssuRequestBackgroundNetworkUpdate. + * @note Only usable when a \ref NsSystemUpdateControl isn't open. + */ +Result nssuNotifyExFatDriverRequired(void); + +/** + * @brief ClearExFatDriverStatusForDebug + */ +Result nssuClearExFatDriverStatusForDebug(void); + +/** + * @brief RequestBackgroundNetworkUpdate + * @note Only usable when a \ref NsSystemUpdateControl isn't open. + */ +Result nssuRequestBackgroundNetworkUpdate(void); + +/** + * @brief This checks whether a sysupdate is needed with the input \ref NcmContentMetaKey using NCM commands, if not this will just return 0. Otherwise, this will then run code which is identical to \ref nssuRequestBackgroundNetworkUpdate. + * @note Only usable when a \ref NsSystemUpdateControl isn't open. + * @param[in] key \ref NcmContentMetaKey + */ +Result nssuNotifyBackgroundNetworkUpdate(const NcmContentMetaKey *key); + +/** + * @brief NotifyExFatDriverDownloadedForDebug + */ +Result nssuNotifyExFatDriverDownloadedForDebug(void); + +/** + * @brief Gets an Event which can be signaled by \ref nssuNotifySystemUpdateForContentDelivery. + * @note The Event must be closed by the user once finished with it. + * @param[out] out_event Output Event with autoclear=false. + */ +Result nssuGetSystemUpdateNotificationEventForContentDelivery(Event* out_event); + +/** + * @brief Signals the event returned by \ref nssuGetSystemUpdateNotificationEventForContentDelivery. + */ +Result nssuNotifySystemUpdateForContentDelivery(void); + +/** + * @brief This does shutdown preparation. + * @note This is used by am-sysmodule, so generally there's no need to use this. + * @note Only available on [3.0.0+]. + */ +Result nssuPrepareShutdown(void); + +/** + * @brief This uses nim ListSystemUpdateTask, then when a task is returned uses it with DestroySystemUpdateTask. + * @note Only available on [4.0.0+]. + */ +Result nssuDestroySystemUpdateTask(void); + +/** + * @brief RequestSendSystemUpdate + * @note Only available on [4.0.0+]. + * @param[out] a \ref AsyncResult + * @param[in] inval0 Unknown input value. + * @param[in] inval1 Unknown input value. qlaunch uses value 0xD904 (55556). + * @param[in] info \ref NsSystemDeliveryInfo + */ +Result nssuRequestSendSystemUpdate(AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info); + +/** + * @brief GetSendSystemUpdateProgress + * @note Only available on [4.0.0+]. + * @param[out] out \ref NsSystemUpdateProgress + */ +Result nssuGetSendSystemUpdateProgress(NsSystemUpdateProgress *out); + +///@} + +///@name ISystemUpdateControl +///@{ + +/** + * @brief Close a \ref NsSystemUpdateControl. + * @param c \ref NsSystemUpdateControl + */ +void nssuControlClose(NsSystemUpdateControl *c); + +/** + * @brief Gets whether a network sysupdate was downloaded, with install pending. + * @param c \ref NsSystemUpdateControl + * @param[out] out Output flag. + */ +Result nssuControlHasDownloaded(NsSystemUpdateControl *c, bool* out); + +/** + * @brief RequestCheckLatestUpdate + * @param c \ref NsSystemUpdateControl + * @param[out] a \ref AsyncValue. The data that can be read from this is u8 \ref NsLatestSystemUpdate. + */ +Result nssuControlRequestCheckLatestUpdate(NsSystemUpdateControl *c, AsyncValue *a); + +/** + * @brief RequestDownloadLatestUpdate + * @param c \ref NsSystemUpdateControl + * @param[out] a \ref AsyncResult + */ +Result nssuControlRequestDownloadLatestUpdate(NsSystemUpdateControl *c, AsyncResult *a); + +/** + * @brief GetDownloadProgress + * @param c \ref NsSystemUpdateControl + * @param[out] out \ref NsSystemUpdateProgress + */ +Result nssuControlGetDownloadProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out); + +/** + * @brief ApplyDownloadedUpdate + * @param c \ref NsSystemUpdateControl + */ +Result nssuControlApplyDownloadedUpdate(NsSystemUpdateControl *c); + +/** + * @brief RequestPrepareCardUpdate + * @param c \ref NsSystemUpdateControl + * @param[out] a \ref AsyncResult + */ +Result nssuControlRequestPrepareCardUpdate(NsSystemUpdateControl *c, AsyncResult *a); + +/** + * @brief GetPrepareCardUpdateProgress + * @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this. + * @param c \ref NsSystemUpdateControl + * @param[out] out \ref NsSystemUpdateProgress + */ +Result nssuControlGetPrepareCardUpdateProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out); + +/** + * @brief HasPreparedCardUpdate + * @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this. + * @param c \ref NsSystemUpdateControl + * @param[out] out Output flag. + */ +Result nssuControlHasPreparedCardUpdate(NsSystemUpdateControl *c, bool* out); + +/** + * @brief ApplyCardUpdate + * @note \ref nssuControlSetupCardUpdate / \ref nssuControlSetupCardUpdateViaSystemUpdater must have been used at some point prior to using this. + * @param c \ref NsSystemUpdateControl + */ +Result nssuControlApplyCardUpdate(NsSystemUpdateControl *c); + +/** + * @brief Gets the filesize for the specified DownloadedEulaData. + * @note This mounts the Eula title, then uses the file ":/". + * @param c \ref NsSystemUpdateControl + * @param[in] path EulaData path. + * @param[out] filesize Output filesize. + */ +Result nssuControlGetDownloadedEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize); + +/** + * @brief Gets the specified DownloadedEulaData. + * @note See the note for \ref nssuControlGetDownloadedEulaDataSize. + * @param c \ref NsSystemUpdateControl + * @param[in] path EulaData path. + * @param[out] buffer Output buffer. + * @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetDownloadedEulaDataSize. + * @param[out] filesize Output filesize. + */ +Result nssuControlGetDownloadedEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize); + +/** + * @brief SetupCardUpdate + * @param c \ref NsSystemUpdateControl + * @param[in] path EulaData path. + * @param[in] buffer TransferMemory buffer, when NULL this is automatically allocated. + * @param[in] size TransferMemory buffer size, see \ref NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT. + */ +Result nssuControlSetupCardUpdate(NsSystemUpdateControl *c, void* buffer, size_t size); + +/** + * @brief Gets the filesize for the specified PreparedCardUpdateEulaData. + * @note See the note for \ref nssuControlGetDownloadedEulaDataSize. + * @param c \ref NsSystemUpdateControl + * @param[in] path EulaData path. + * @param[out] filesize Output filesize. + */ +Result nssuControlGetPreparedCardUpdateEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize); + +/** + * @brief Gets the specified PreparedCardUpdateEulaData. + * @note See the note for \ref nssuControlGetDownloadedEulaDataSize. + * @param c \ref NsSystemUpdateControl + * @param[in] path EulaData path. + * @param[out] buffer Output buffer. + * @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetPreparedCardUpdateEulaDataSize. + * @param[out] filesize Output filesize. + */ +Result nssuControlGetPreparedCardUpdateEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize); + +/** + * @brief SetupCardUpdateViaSystemUpdater + * @note Same as \ref nssuControlSetupCardUpdate, except this doesn't run the code for fs cmds GetGameCardHandle/GetGameCardUpdatePartitionInfo, and uses fs OpenRegisteredUpdatePartition instead of OpenGameCardFileSystem. + * @note Only available on [4.0.0+]. + * @param c \ref NsSystemUpdateControl + * @param[in] path EulaData path. + * @param[in] buffer TransferMemory buffer, when NULL this is automatically allocated. + * @param[in] size TransferMemory buffer size, see \ref NSSU_CARDUPDATE_TMEM_SIZE_DEFAULT. + */ +Result nssuControlSetupCardUpdateViaSystemUpdater(NsSystemUpdateControl *c, void* buffer, size_t size); + +/** + * @brief HasReceived + * @note Only available on [4.0.0+]. + * @param c \ref NsSystemUpdateControl + * @param[out] out Output flag. + */ +Result nssuControlHasReceived(NsSystemUpdateControl *c, bool* out); + +/** + * @brief RequestReceiveSystemUpdate + * @note Only available on [4.0.0+]. + * @param c \ref NsSystemUpdateControl + * @param[out] a \ref AsyncResult + * @param[in] inval0 Unknown input value. + * @param[in] inval1 Unknown input value. qlaunch uses value 0xD904 (55556). + * @param[in] info \ref NsSystemDeliveryInfo + */ +Result nssuControlRequestReceiveSystemUpdate(NsSystemUpdateControl *c, AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info); + +/** + * @brief GetReceiveProgress + * @note Only available on [4.0.0+]. + * @param c \ref NsSystemUpdateControl + * @param[out] out \ref NsSystemUpdateProgress + */ +Result nssuControlGetReceiveProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out); + +/** + * @brief ApplyReceivedUpdate + * @note Only available on [4.0.0+]. + * @param c \ref NsSystemUpdateControl + */ +Result nssuControlApplyReceivedUpdate(NsSystemUpdateControl *c); + +/** + * @brief Gets the filesize for the specified ReceivedEulaData. + * @note See the note for \ref nssuControlGetDownloadedEulaDataSize. + * @note Only available on [4.0.0+]. + * @param c \ref NsSystemUpdateControl + * @param[in] path EulaData path. + * @param[out] filesize Output filesize. + */ +Result nssuControlGetReceivedEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize); + +/** + * @brief Gets the specified ReceivedEulaData. + * @note See the note for \ref nssuControlGetDownloadedEulaDataSize. + * @note Only available on [4.0.0+]. + * @param c \ref NsSystemUpdateControl + * @param[in] path EulaData path. + * @param[out] buffer Output buffer. + * @param[in] size Size of the output buffer, must be at least the output size from \ref nssuControlGetReceivedEulaDataSize. + * @param[out] filesize Output filesize. + */ +Result nssuControlGetReceivedEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize); + +/** + * @brief Does setup for ReceiveSystemUpdate by using the same nim cmds as \ref nssuDestroySystemUpdateTask. + * @note Only available on [4.0.0+]. + * @param c \ref NsSystemUpdateControl + */ +Result nssuControlSetupToReceiveSystemUpdate(NsSystemUpdateControl *c); + +/** + * @brief RequestCheckLatestUpdateIncludesRebootlessUpdate + * @note Only available on [6.0.0+]. + * @param c \ref NsSystemUpdateControl + * @param[out] a \ref AsyncValue + */ +Result nssuControlRequestCheckLatestUpdateIncludesRebootlessUpdate(NsSystemUpdateControl *c, AsyncValue *a); + +///@} + diff --git a/nx/source/services/ns.c b/nx/source/services/ns.c index 0c507868..98fbdf59 100644 --- a/nx/source/services/ns.c +++ b/nx/source/services/ns.c @@ -1,11 +1,21 @@ #define NX_SERVICE_ASSUME_NON_DOMAIN +#include #include "service_guard.h" #include "runtime/hosversion.h" #include "services/ns.h" +#include "services/fs.h" +#include "services/ncm.h" +#include "services/async.h" +#include "kernel/tmem.h" -static Service g_nsAppManSrv, g_nsGetterSrv, g_nsvmSrv, g_nsdevSrv; +static Service g_nsAppManSrv, g_nsGetterSrv; +static Service g_nsvmSrv; +static Service g_nsdevSrv; +static Service g_nssuSrv; -static Result _nsGetInterface(Service* srv_out, u32 cmd_id); +static Result _nsGetSession(Service* srv, Service* srv_out, u32 cmd_id); + +// ns NX_GENERATE_SERVICE_GUARD(ns); @@ -19,7 +29,7 @@ Result _nsInitialize(void) rc = smGetService(&g_nsGetterSrv, "ns:am2");//TODO: Support the other services?(Only useful when ns:am2 isn't accessible) if (R_FAILED(rc)) return rc; - rc = _nsGetInterface(&g_nsAppManSrv, 7996); + rc = _nsGetSession(&g_nsGetterSrv, &g_nsAppManSrv, 7996); if (R_FAILED(rc)) serviceClose(&g_nsGetterSrv); @@ -34,14 +44,14 @@ void _nsCleanup(void) serviceClose(&g_nsGetterSrv); } -static Result _nsGetInterface(Service* srv_out, u32 cmd_id) { - return serviceDispatch(&g_nsGetterSrv, cmd_id, +static Result _nsGetSession(Service* srv, Service* srv_out, u32 cmd_id) { + return serviceDispatch(srv, cmd_id, .out_num_objects = 1, .out_objects = srv_out, ); } -static Result _appletGetEvent(Service* srv, u32 cmd_id, Event* out_event, bool autoclear) { +static Result _nsCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u32 cmd_id) { Handle event = INVALID_HANDLE; Result rc = serviceDispatch(srv, cmd_id, .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, @@ -54,35 +64,109 @@ static Result _appletGetEvent(Service* srv, u32 cmd_id, Event* out_event, bool a return rc; } +static Result _nsCmdInHandle64NoOut(Service* srv, Handle handle, u64 inval, u32 cmd_id) { + return serviceDispatchIn(srv, cmd_id, inval, + .in_num_handles = 1, + .in_handles = { handle }, + ); +} + +static Result _nsCmdInTmemNoOut(Service* srv, TransferMemory *tmem, u32 cmd_id) { + return _nsCmdInHandle64NoOut(srv, tmem->handle, tmem->size, cmd_id); +} + static Result _nsCmdNoIO(Service* srv, u32 cmd_id) { return serviceDispatch(srv, cmd_id); } -static Result _nsCmdInBool(Service* srv, u32 cmd_id, bool inval) { +static Result _nsCmdInBool(Service* srv, bool inval, u32 cmd_id) { u8 in = inval!=0; return serviceDispatchIn(srv, cmd_id, in); } -static Result _nsCmdInU64(Service* srv, u32 cmd_id, u64 inval) { +static Result _nsCmdInU64(Service* srv, u64 inval, u32 cmd_id) { return serviceDispatchIn(srv, cmd_id, inval); } -static Result _nsCmdInU64OutU64(Service* srv, u32 cmd_id, u64 inval, u64 *out) { +static Result _nsCmdInU64OutU64(Service* srv, u64 inval, u64 *out, u32 cmd_id) { return serviceDispatchInOut(srv, cmd_id, inval, *out); } -static Result _nsCmdNoInOutBool(Service* srv, u32 cmd_id, bool *out) { +static Result _nsCmdNoInOutU8(Service* srv, u8 *out, u32 cmd_id) { + return serviceDispatchOut(srv, cmd_id, *out); +} + +static Result _nsCmdNoInOutBool(Service* srv, bool *out, u32 cmd_id) { u8 tmpout=0; - Result rc = serviceDispatchOut(srv, cmd_id, tmpout); + Result rc = _nsCmdNoInOutU8(srv, &tmpout, cmd_id); if (R_SUCCEEDED(rc) && out) *out = tmpout!=0; return rc; } -static Result _nsCmdNoInOutU64(Service* srv, u32 cmd_id, u64 *out) { +static Result _nsCmdNoInOutU64(Service* srv, u64 *out, u32 cmd_id) { return serviceDispatchOut(srv, cmd_id, *out); } +static Result _nsCmdNoInOutSystemUpdateProgress(Service* srv, NsSystemUpdateProgress *out, u32 cmd_id) { + return serviceDispatchOut(srv, cmd_id, *out); +} + +static Result _nsCmdRequestSendReceiveSystemUpdate(Service* srv, AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info, u32 cmd_id) { + const struct { + u16 inval0; + u32 inval1; + } in = { inval0, inval1 }; + + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + Result rc = serviceDispatchIn(srv, cmd_id, in, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { info, sizeof(*info) } }, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + +static Result _nsCmdNoInOutAsyncValue(Service* srv, AsyncValue *a, u32 cmd_id) { + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + Result rc = serviceDispatch(srv, cmd_id, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + +static Result _nsCmdNoInOutAsyncResult(Service* srv, AsyncResult *a, u32 cmd_id) { + memset(a, 0, sizeof(*a)); + Handle event = INVALID_HANDLE; + Result rc = serviceDispatch(srv, cmd_id, + .out_num_objects = 1, + .out_objects = &a->s, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &event, + ); + + if (R_SUCCEEDED(rc)) + eventLoadRemote(&a->event, event, false); + + return rc; +} + Result nsListApplicationRecord(NsApplicationRecord* records, s32 count, s32 entry_offset, s32* out_entrycount) { return serviceDispatchInOut(&g_nsAppManSrv, 0, entry_offset, *out_entrycount, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, @@ -115,13 +199,15 @@ Result nsGetApplicationControlData(u8 flag, u64 titleID, NsApplicationControlDat } Result nsGetTotalSpaceSize(FsStorageId storage_id, u64 *size) { - return _nsCmdInU64OutU64(&g_nsAppManSrv, 47, storage_id, size); + return _nsCmdInU64OutU64(&g_nsAppManSrv, storage_id, size, 47); } Result nsGetFreeSpaceSize(FsStorageId storage_id, u64 *size) { - return _nsCmdInU64OutU64(&g_nsAppManSrv, 48, storage_id, size); + return _nsCmdInU64OutU64(&g_nsAppManSrv, storage_id, size, 48); } +// ns:vm + NX_GENERATE_SERVICE_GUARD(nsvm); Result _nsvmInitialize(void) @@ -144,7 +230,7 @@ Result nsvmNeedsUpdateVulnerability(bool *out) { Service *srv = &g_nsAppManSrv; if (hosversionAtLeast(3,0,0)) srv = &g_nsvmSrv; - return _nsCmdNoInOutBool(srv, 1200, out); + return _nsCmdNoInOutBool(srv, out, 1200); } Result nsvmGetSafeSystemVersion(u16 *out) { @@ -154,6 +240,8 @@ Result nsvmGetSafeSystemVersion(u16 *out) { return serviceDispatchOut(&g_nsvmSrv, 1202, out); } +// ns:dev + NX_GENERATE_SERVICE_GUARD(nsdev); Result _nsdevInitialize(void) { @@ -174,15 +262,15 @@ Result nsdevLaunchProgram(u64* out_pid, const NsLaunchProperties* properties, u3 } Result nsdevTerminateProcess(u64 pid) { - return _nsCmdInU64(&g_nsdevSrv, 1, pid); + return _nsCmdInU64(&g_nsdevSrv, pid, 1); } Result nsdevTerminateProgram(u64 tid) { - return _nsCmdInU64(&g_nsdevSrv, 2, tid); + return _nsCmdInU64(&g_nsdevSrv, tid, 2); } Result nsdevGetShellEvent(Event* out_event) { - return _appletGetEvent(&g_nsdevSrv, 4, out_event, true); + return _nsCmdGetEvent(&g_nsdevSrv, out_event, true, 4); } Result nsdevGetShellEventInfo(NsShellEventInfo* out) { @@ -233,17 +321,326 @@ Result nsdevLaunchApplicationWithStorageIdForDevelop(u64* out_pid, u64 app_title Result nsdevIsSystemMemoryResourceLimitBoosted(bool* out) { if (hosversionBefore(6,0,0) || hosversionAtLeast(9,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _nsCmdNoInOutBool(&g_nsdevSrv, 10, out); + return _nsCmdNoInOutBool(&g_nsdevSrv, out, 10); } Result nsdevGetRunningApplicationProcessIdForDevelop(u64* out_pid) { if (hosversionBefore(6,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _nsCmdNoInOutU64(&g_nsdevSrv, 11, out_pid); + return _nsCmdNoInOutU64(&g_nsdevSrv, out_pid, 11); } Result nsdevSetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop(bool can_be_active) { if (hosversionBefore(6,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _nsCmdInBool(&g_nsdevSrv, 12, can_be_active); + return _nsCmdInBool(&g_nsdevSrv, can_be_active, 12); } + +// ns:su + +NX_GENERATE_SERVICE_GUARD(nssu); + +Result _nssuInitialize(void) { + return smGetService(&g_nssuSrv, "ns:su"); +} + +void _nssuCleanup(void) { + serviceClose(&g_nssuSrv); +} + +Result nssuGetBackgroundNetworkUpdateState(NsBackgroundNetworkUpdateState *out) { + u8 tmpout=0; + Result rc = _nsCmdNoInOutU8(&g_nssuSrv, &tmpout, 0); + if (R_SUCCEEDED(rc)) *out = tmpout; + return rc; +} + +Result nssuOpenSystemUpdateControl(NsSystemUpdateControl *c) { + return _nsGetSession(&g_nssuSrv, &c->s, 1); +} + +Result nssuNotifyExFatDriverRequired(void) { + return _nsCmdNoIO(&g_nssuSrv, 2); +} + +Result nssuClearExFatDriverStatusForDebug(void) { + return _nsCmdNoIO(&g_nssuSrv, 3); +} + +Result nssuRequestBackgroundNetworkUpdate(void) { + return _nsCmdNoIO(&g_nssuSrv, 4); +} + +Result nssuNotifyBackgroundNetworkUpdate(const NcmContentMetaKey *key) { + return serviceDispatchIn(&g_nssuSrv, 5, *key); +} + +Result nssuNotifyExFatDriverDownloadedForDebug(void) { + return _nsCmdNoIO(&g_nssuSrv, 6); +} + +Result nssuGetSystemUpdateNotificationEventForContentDelivery(Event* out_event) { + return _nsCmdGetEvent(&g_nssuSrv, out_event, false, 9); +} + +Result nssuNotifySystemUpdateForContentDelivery(void) { + return _nsCmdNoIO(&g_nssuSrv, 10); +} + +Result nssuPrepareShutdown(void) { + if (hosversionBefore(3,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdNoIO(&g_nssuSrv, 11); +} + +Result nssuDestroySystemUpdateTask(void) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdNoIO(&g_nssuSrv, 16); +} + +Result nssuRequestSendSystemUpdate(AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdRequestSendReceiveSystemUpdate(&g_nssuSrv, a, inval0, inval1, info, 17); +} + +Result nssuGetSendSystemUpdateProgress(NsSystemUpdateProgress *out) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdNoInOutSystemUpdateProgress(&g_nssuSrv, out, 18); +} + +// ISystemUpdateControl + +void nssuControlClose(NsSystemUpdateControl *c) { + serviceClose(&c->s); + tmemClose(&c->tmem); +} + +static Result _nssuControlGetEulaDataSize(NsSystemUpdateControl *c, u32 cmd_id, const char* path, u64 *filesize) { + NsEulaDataPath datapath; + + memset(&datapath, 0, sizeof(datapath)); + strncpy(datapath.path, path, sizeof(datapath.path)-1); + + return serviceDispatchOut(&c->s, cmd_id, *filesize, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { &datapath, sizeof(datapath) } }, + ); +} + +static Result _nssuControlGetEulaData(NsSystemUpdateControl *c, u32 cmd_id, const char* path, void* buffer, size_t size, u64 *filesize) { + NsEulaDataPath datapath; + + memset(&datapath, 0, sizeof(datapath)); + strncpy(datapath.path, path, sizeof(datapath.path)-1); + + return serviceDispatchOut(&c->s, cmd_id, *filesize, + .buffer_attrs = { + SfBufferAttr_HipcMapAlias | SfBufferAttr_In, + SfBufferAttr_HipcMapAlias | SfBufferAttr_Out, + }, + .buffers = { + { &datapath, sizeof(datapath) }, + { buffer, size }, + }, + ); +} + +static Result _nssuControlCmdTmemNoOut(NsSystemUpdateControl *c, void* buffer, size_t size, u32 cmd_id) { + Result rc=0; + + if (buffer==NULL) rc = tmemCreate(&c->tmem, size, Perm_None); + else rc = tmemCreateFromMemory(&c->tmem, buffer, size, Perm_None); + if (R_FAILED(rc)) return rc; + + rc = _nsCmdInTmemNoOut(&c->s, &c->tmem, cmd_id); + if (R_FAILED(rc)) tmemClose(&c->tmem); + + return rc; +} + +Result nssuControlHasDownloaded(NsSystemUpdateControl *c, bool* out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoInOutBool(&c->s, out, 0); +} + +Result nssuControlRequestCheckLatestUpdate(NsSystemUpdateControl *c, AsyncValue *a) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoInOutAsyncValue(&c->s, a, 1); +} + +Result nssuControlRequestDownloadLatestUpdate(NsSystemUpdateControl *c, AsyncResult *a) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoInOutAsyncResult(&c->s, a, 2); +} + +Result nssuControlGetDownloadProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoInOutSystemUpdateProgress(&c->s, out, 3); +} + +Result nssuControlApplyDownloadedUpdate(NsSystemUpdateControl *c) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoIO(&c->s, 4); +} + +Result nssuControlRequestPrepareCardUpdate(NsSystemUpdateControl *c, AsyncResult *a) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoInOutAsyncResult(&c->s, a, 5); +} + +Result nssuControlGetPrepareCardUpdateProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoInOutSystemUpdateProgress(&c->s, out, 6); +} + +Result nssuControlHasPreparedCardUpdate(NsSystemUpdateControl *c, bool* out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoInOutBool(&c->s, out, 7); +} + +Result nssuControlApplyCardUpdate(NsSystemUpdateControl *c) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nsCmdNoIO(&c->s, 8); +} + +Result nssuControlGetDownloadedEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nssuControlGetEulaDataSize(c, 9, path, filesize); +} + +Result nssuControlGetDownloadedEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nssuControlGetEulaData(c, 10, path, buffer, size, filesize); +} + +Result nssuControlSetupCardUpdate(NsSystemUpdateControl *c, void* buffer, size_t size) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nssuControlCmdTmemNoOut(c, buffer, size, 11); +} + +Result nssuControlGetPreparedCardUpdateEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nssuControlGetEulaDataSize(c, 12, path, filesize); +} + +Result nssuControlGetPreparedCardUpdateEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _nssuControlGetEulaData(c, 13, path, buffer, size, filesize); +} + +Result nssuControlSetupCardUpdateViaSystemUpdater(NsSystemUpdateControl *c, void* buffer, size_t size) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nssuControlCmdTmemNoOut(c, buffer, size, 14); +} + +Result nssuControlHasReceived(NsSystemUpdateControl *c, bool* out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdNoInOutBool(&c->s, out, 15); +} + +Result nssuControlRequestReceiveSystemUpdate(NsSystemUpdateControl *c, AsyncResult *a, u32 inval0, u16 inval1, NsSystemDeliveryInfo *info) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdRequestSendReceiveSystemUpdate(&c->s, a, inval0, inval1, info, 16); +} + +Result nssuControlGetReceiveProgress(NsSystemUpdateControl *c, NsSystemUpdateProgress *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdNoInOutSystemUpdateProgress(&c->s, out, 17); +} + +Result nssuControlApplyReceivedUpdate(NsSystemUpdateControl *c) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdNoIO(&c->s, 18); +} + +Result nssuControlGetReceivedEulaDataSize(NsSystemUpdateControl *c, const char* path, u64 *filesize) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nssuControlGetEulaDataSize(c, 19, path, filesize); +} + +Result nssuControlGetReceivedEulaData(NsSystemUpdateControl *c, const char* path, void* buffer, size_t size, u64 *filesize) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nssuControlGetEulaData(c, 20, path, buffer, size, filesize); +} + +Result nssuControlSetupToReceiveSystemUpdate(NsSystemUpdateControl *c) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdNoIO(&c->s, 21); +} + +Result nssuControlRequestCheckLatestUpdateIncludesRebootlessUpdate(NsSystemUpdateControl *c, AsyncValue *a) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _nsCmdNoInOutAsyncValue(&c->s, a, 22); +} +