From 7416b23ef927e3681275bc133d4e9b6965292c9a Mon Sep 17 00:00:00 2001 From: fincs Date: Sun, 11 Apr 2021 00:54:52 +0200 Subject: [PATCH] sm: update for 12.0.0, tipc --- nx/include/switch/services/sm.h | 28 +++++++++- nx/source/services/sm.c | 91 +++++++++++++++++++++++++++------ 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/nx/include/switch/services/sm.h b/nx/include/switch/services/sm.h index 0b037d43..e408540c 100644 --- a/nx/include/switch/services/sm.h +++ b/nx/include/switch/services/sm.h @@ -9,6 +9,7 @@ #include "../types.h" #include "../kernel/svc.h" #include "../sf/service.h" +#include "../sf/tipc.h" /// Structure representing a service name (null terminated, remaining characters set to zero). typedef struct SmServiceName { @@ -117,6 +118,12 @@ Handle smGetServiceOverride(SmServiceName name); */ Result smRegisterService(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions); +/// Same as \ref smRegisterService, but always using cmif serialization. +Result smRegisterServiceCmif(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions); + +/// Same as \ref smRegisterService, but always using cmif serialization. +Result smRegisterServiceTipc(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions); + /** * @brief Unregisters a previously registered service in SM. * @param[in] name Name of the service. @@ -124,19 +131,38 @@ Result smRegisterService(Handle* handle_out, SmServiceName name, bool is_light, */ Result smUnregisterService(SmServiceName name); +/// Same as \ref smUnregisterService, but always using cmif serialization. +Result smUnregisterServiceCmif(SmServiceName name); + +/// Same as \ref smUnregisterService, but always using cmif serialization. +Result smUnregisterServiceTipc(SmServiceName name); + /** * @brief Detaches the current SM session. * @note After this function is called, the rest of the SM API cannot be used. - * @note Only available on [11.0.0+]. + * @note Only available on [11.0.0-11.0.1], or Atmosphère. */ Result smDetachClient(void); +/// Same as \ref smDetachClient, but always using cmif serialization. +Result smDetachClientCmif(void); + +/// Same as \ref smDetachClient, but always using tipc serialization. +Result smDetachClientTipc(void); + /** * @brief Gets the Service session used to communicate with SM. * @return Pointer to service session used to communicate with SM. */ Service *smGetServiceSession(void); +/** + * @brief Gets the TipcService session used to communicate with SM. + * @return Pointer to tipc service session used to communicate with SM. + * @note Only available on [12.0.0+], or Atmosphère. + */ +TipcService *smGetServiceSessionTipc(void); + /** * @brief Overrides a service with a custom IPC service handle. * @param[in] name Name of the service. diff --git a/nx/source/services/sm.c b/nx/source/services/sm.c index aba4fa6c..da7201b1 100644 --- a/nx/source/services/sm.c +++ b/nx/source/services/sm.c @@ -1,9 +1,13 @@ #define NX_SERVICE_ASSUME_NON_DOMAIN #include "service_guard.h" +#include "sf/tipc.h" #include "runtime/hosversion.h" #include "runtime/diag.h" -static Service g_smSrv; +static union { + Service cmif; + TipcService tipc; +} g_smSrv; #define MAX_OVERRIDES 32 @@ -14,6 +18,10 @@ static struct { static size_t g_smOverridesNum = 0; +static bool _smShouldUseTipc(void) { + return hosversionIsAtmosphere() || hosversionAtLeast(12,0,0); +} + void smAddOverrideHandle(SmServiceName name, Handle handle) { if (g_smOverridesNum == MAX_OVERRIDES) diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_TooManyOverrides)); @@ -36,9 +44,13 @@ Handle smGetServiceOverride(SmServiceName name) { NX_GENERATE_SERVICE_GUARD(sm); -static Result _smCmdInPid(u32 cmd_id) { +static Result _smCmifCmdInPid(u32 cmd_id) { u64 pid_placeholder = 0; - return serviceDispatchIn(&g_smSrv, cmd_id, pid_placeholder, .in_send_pid = true); + return serviceDispatchIn(&g_smSrv.cmif, cmd_id, pid_placeholder, .in_send_pid = true); +} + +static Result _smTipcCmdInPid(u32 cmd_id) { + return tipcDispatch(&g_smSrv.tipc, cmd_id, .in_send_pid = true); } Result _smInitialize(void) { @@ -49,24 +61,26 @@ Result _smInitialize(void) { rc = svcConnectToNamedPort(&sm_handle, "sm:"); } + // Call RegisterClient. This is unconditionally done through cmif, + // see comment in smGetServiceOriginal for more details. if (R_SUCCEEDED(rc)) { - serviceCreate(&g_smSrv, sm_handle); - } - - Handle tmp; - if (R_SUCCEEDED(rc) && R_VALUE(smGetServiceOriginal(&tmp, (SmServiceName){})) == 0x415) { - rc = _smCmdInPid(0); + serviceCreate(&g_smSrv.cmif, sm_handle); + rc = _smCmifCmdInPid(0); // RegisterClient } return rc; } void _smCleanup(void) { - serviceClose(&g_smSrv); + serviceClose(&g_smSrv.cmif); } Service *smGetServiceSession(void) { - return &g_smSrv; + return &g_smSrv.cmif; +} + +TipcService *smGetServiceSessionTipc(void) { + return &g_smSrv.tipc; } Result smGetServiceWrapper(Service* service_out, SmServiceName name) { @@ -88,30 +102,75 @@ Result smGetServiceWrapper(Service* service_out, SmServiceName name) { } Result smGetServiceOriginal(Handle* handle_out, SmServiceName name) { - return serviceDispatchIn(&g_smSrv, 1, name, + // Even though GetServiceHandle is also available through tipc, we choose to only + // call this command through cmif, since that is available on all system versions. + return serviceDispatchIn(&g_smSrv.cmif, 1, name, .out_handle_attrs = { SfOutHandleAttr_HipcMove }, .out_handles = handle_out, ); } Result smRegisterService(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions) { + if (_smShouldUseTipc()) + return smRegisterServiceTipc(handle_out, name, is_light, max_sessions); + else + return smRegisterServiceCmif(handle_out, name, is_light, max_sessions); +} + +Result smRegisterServiceCmif(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions) { const struct { SmServiceName service_name; u8 is_light; s32 max_sessions; } in = { name, is_light!=0, max_sessions }; - return serviceDispatchIn(&g_smSrv, 2, in, + return serviceDispatchIn(&g_smSrv.cmif, 2, in, + .out_handle_attrs = { SfOutHandleAttr_HipcMove }, + .out_handles = handle_out, + ); +} + +Result smRegisterServiceTipc(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions) { + const struct { + SmServiceName service_name; + s32 max_sessions; + u8 is_light; + } in = { name, max_sessions, is_light!=0 }; + + return tipcDispatchIn(&g_smSrv.tipc, 2, in, .out_handle_attrs = { SfOutHandleAttr_HipcMove }, .out_handles = handle_out, ); } Result smUnregisterService(SmServiceName name) { - return serviceDispatchIn(&g_smSrv, 3, name); + if (_smShouldUseTipc()) + return smUnregisterServiceTipc(name); + else + return smUnregisterServiceCmif(name); +} + +Result smUnregisterServiceCmif(SmServiceName name) { + return serviceDispatchIn(&g_smSrv.cmif, 3, name); +} + +Result smUnregisterServiceTipc(SmServiceName name) { + return tipcDispatchIn(&g_smSrv.tipc, 3, name); } Result smDetachClient(void) { - if (!hosversionIsAtmosphere() && hosversionBefore(11,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _smCmdInPid(4); + if (hosversionIsAtmosphere()) + return smDetachClientTipc(); + else if (hosversionBetween(11, 12)) + return smDetachClientCmif(); + else + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); +} + +Result smDetachClientCmif(void) { + return _smCmifCmdInPid(4); +} + +Result smDetachClientTipc(void) { + return _smTipcCmdInPid(4); }