diff --git a/nx/include/switch/services/sm.h b/nx/include/switch/services/sm.h index 40de8d36..52e01f0e 100644 --- a/nx/include/switch/services/sm.h +++ b/nx/include/switch/services/sm.h @@ -97,6 +97,55 @@ static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t siz #pragma GCC diagnostic pop +/// Structure representing a service name (null terminated, remaining characters set to zero). +typedef struct SmServiceName { + char name[8]; +} SmServiceName; + +/// Converts a service name into a 64-bit integer. +NX_CONSTEXPR u64 smServiceNameToU64(SmServiceName name) +{ + u64 ret = 0; + __builtin_memcpy(&ret, &name, sizeof(u64)); + return ret; +} + +/// Converts a 64-bit integer into a service name. +NX_CONSTEXPR SmServiceName smServiceNameFromU64(u64 name) +{ + SmServiceName ret = {0}; + __builtin_memcpy(&ret, &name, sizeof(SmServiceName)); + return ret; +} + +/** + * @brief Checks whether two service names are equal. + * @param[in] a First name. + * @param[in] b Second name. + * @return Comparison result. + */ +NX_CONSTEXPR bool smServiceNamesAreEqual(SmServiceName a, SmServiceName b) +{ + return smServiceNameToU64(a) == smServiceNameToU64(b); +} + +/** + * @brief Encodes a service name string as a \ref SmServiceName structure. + * @param[in] name Name of the service. + * @return Encoded name. + */ +NX_CONSTEXPR SmServiceName smEncodeName(const char* name) +{ + SmServiceName name_encoded = {}; + unsigned len = __builtin_strlen(name); +#define __COPY_CHAR(_n) \ + if (len > _n) name_encoded.name[_n] = name[_n] + __COPY_CHAR(0); __COPY_CHAR(1); __COPY_CHAR(2); __COPY_CHAR(3); + __COPY_CHAR(4); __COPY_CHAR(5); __COPY_CHAR(6); __COPY_CHAR(7); +#undef __COPY_CHAR + return name_encoded; +} + /** * @brief Initializes SM. * @return Result code. @@ -112,12 +161,12 @@ Result smInitialize(void); void smExit(void); /** - * @brief Requests a service from SM. + * @brief Requests a service from SM, allowing overrides. * @param[out] service_out Service structure which will be filled in. * @param[in] name Name of the service to request. * @return Result code. */ -Result smGetService(Service* service_out, const char* name); +Result smGetServiceWrapper(Service* service_out, SmServiceName name); /** * @brief Requests a service from SM, as an IPC session handle directly @@ -125,14 +174,25 @@ Result smGetService(Service* service_out, const char* name); * @param[in] name Name of the service to request. * @return Result code. */ -Result smGetServiceOriginal(Handle* handle_out, u64 name); +Result smGetServiceOriginal(Handle* handle_out, SmServiceName name); + +/** + * @brief Requests a service from SM. + * @param[out] service_out Service structure which will be filled in. + * @param[in] name Name of the service to request (as a string). + * @return Result code. + */ +NX_INLINE Result smGetService(Service* service_out, const char* name) +{ + return smGetServiceWrapper(service_out, smEncodeName(name)); +} /** * @brief Retrieves an overriden service in the homebrew environment. - * @param[in] name Name of the service to request (as 64-bit integer). + * @param[in] name Name of the service to request. * @return IPC session handle. */ -Handle smGetServiceOverride(u64 name); +Handle smGetServiceOverride(SmServiceName name); /** * @brief Creates and registers a new service within SM. @@ -142,14 +202,14 @@ Handle smGetServiceOverride(u64 name); * @param[in] max_sessions Maximum number of concurrent sessions that the service will accept. * @return Result code. */ -Result smRegisterService(Handle* handle_out, const char* name, bool is_light, s32 max_sessions); +Result smRegisterService(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. * @return Result code. */ -Result smUnregisterService(const char* name); +Result smUnregisterService(SmServiceName name); /** * @brief Gets the Service session used to communicate with SM. @@ -157,22 +217,9 @@ Result smUnregisterService(const char* name); */ Service *smGetServiceSession(void); -/** - * @brief Encodes a service name as a 64-bit integer. - * @param[in] name Name of the service. - * @return Encoded name. - */ -NX_CONSTEXPR u64 smEncodeName(const char* name) -{ - u64 name_encoded = 0; - for (unsigned i = 0; name[i] && i < 8; i ++) - name_encoded |= ((u64) name[i]) << (8*i); - return name_encoded; -} - /** * @brief Overrides a service with a custom IPC service handle. - * @param[in] name Name of the service (as 64-bit integer). + * @param[in] name Name of the service. * @param[in] handle IPC session handle. */ -void smAddOverrideHandle(u64 name, Handle handle); +void smAddOverrideHandle(SmServiceName name, Handle handle); diff --git a/nx/source/runtime/env.c b/nx/source/runtime/env.c index 740c8158..7d146c16 100644 --- a/nx/source/runtime/env.c +++ b/nx/source/runtime/env.c @@ -73,7 +73,7 @@ void envSetup(void* ctx, Handle main_thread, LoaderReturnFn saved_lr) break; case EntryType_OverrideService: - smAddOverrideHandle(ent->Value[0], ent->Value[1]); + smAddOverrideHandle(smServiceNameFromU64(ent->Value[0]), ent->Value[1]); break; case EntryType_Argv: diff --git a/nx/source/services/sm.c b/nx/source/services/sm.c index 8ae9ca11..e0fcca54 100644 --- a/nx/source/services/sm.c +++ b/nx/source/services/sm.c @@ -7,13 +7,13 @@ static Service g_smSrv; #define MAX_OVERRIDES 32 static struct { - u64 name; + SmServiceName name; Handle handle; } g_smOverrides[MAX_OVERRIDES]; static size_t g_smOverridesNum = 0; -void smAddOverrideHandle(u64 name, Handle handle) { +void smAddOverrideHandle(SmServiceName name, Handle handle) { if (g_smOverridesNum == MAX_OVERRIDES) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_TooManyOverrides)); @@ -25,9 +25,9 @@ void smAddOverrideHandle(u64 name, Handle handle) { g_smOverridesNum++; } -Handle smGetServiceOverride(u64 name) { +Handle smGetServiceOverride(SmServiceName name) { for (size_t i = 0; i < g_smOverridesNum; i++) - if (g_smOverrides[i].name == name) + if (smServiceNamesAreEqual(g_smOverrides[i].name, name)) return g_smOverrides[i].handle; return INVALID_HANDLE; @@ -48,12 +48,9 @@ Result _smInitialize(void) { } Handle tmp; - if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, smEncodeName("")) == 0x415) { - const struct { - u64 pid_placeholder; - } in = { 0 }; - - rc = serviceDispatchIn(&g_smSrv, 0, in, .in_send_pid = true); + if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, (SmServiceName){}) == 0x415) { + u64 pid_placeholder = 0; + rc = serviceDispatchIn(&g_smSrv, 0, pid_placeholder, .in_send_pid = true); } return rc; @@ -67,15 +64,14 @@ Service *smGetServiceSession(void) { return &g_smSrv; } -Result smGetService(Service* service_out, const char* name) { - u64 name_encoded = smEncodeName(name); - Handle handle = smGetServiceOverride(name_encoded); +Result smGetServiceWrapper(Service* service_out, SmServiceName name) { + Handle handle = smGetServiceOverride(name); bool own_handle = false; Result rc = 0; if (handle == INVALID_HANDLE) { own_handle = true; - rc = smGetServiceOriginal(&handle, name_encoded); + rc = smGetServiceOriginal(&handle, name); } if (R_SUCCEEDED(rc)) { @@ -86,19 +82,19 @@ Result smGetService(Service* service_out, const char* name) { return rc; } -Result smGetServiceOriginal(Handle* handle_out, u64 name) { +Result smGetServiceOriginal(Handle* handle_out, SmServiceName name) { return serviceDispatchIn(&g_smSrv, 1, name, .out_handle_attrs = { SfOutHandleAttr_HipcMove }, .out_handles = handle_out, ); } -Result smRegisterService(Handle* handle_out, const char* name, bool is_light, s32 max_sessions) { +Result smRegisterService(Handle* handle_out, SmServiceName name, bool is_light, s32 max_sessions) { const struct { - u64 service_name; + SmServiceName service_name; u8 is_light; s32 max_sessions; - } in = { smEncodeName(name), is_light!=0, max_sessions }; + } in = { name, is_light!=0, max_sessions }; return serviceDispatchIn(&g_smSrv, 2, in, .out_handle_attrs = { SfOutHandleAttr_HipcMove }, @@ -106,7 +102,6 @@ Result smRegisterService(Handle* handle_out, const char* name, bool is_light, s3 ); } -Result smUnregisterService(const char* name) { - u64 service_name = smEncodeName(name); - return serviceDispatchIn(&g_smSrv, 3, service_name); +Result smUnregisterService(SmServiceName name) { + return serviceDispatchIn(&g_smSrv, 3, name); }