#define NX_SERVICE_ASSUME_NON_DOMAIN #include "service_guard.h" #include "runtime/hosversion.h" #include "runtime/diag.h" static Service g_smSrv; #define MAX_OVERRIDES 32 static struct { SmServiceName name; Handle handle; } g_smOverrides[MAX_OVERRIDES]; static size_t g_smOverridesNum = 0; void smAddOverrideHandle(SmServiceName name, Handle handle) { if (g_smOverridesNum == MAX_OVERRIDES) diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_TooManyOverrides)); size_t i = g_smOverridesNum; g_smOverrides[i].name = name; g_smOverrides[i].handle = handle; g_smOverridesNum++; } Handle smGetServiceOverride(SmServiceName name) { for (size_t i = 0; i < g_smOverridesNum; i++) if (smServiceNamesAreEqual(g_smOverrides[i].name, name)) return g_smOverrides[i].handle; return INVALID_HANDLE; } NX_GENERATE_SERVICE_GUARD(sm); static Result _smCmdInPid(u32 cmd_id) { u64 pid_placeholder = 0; return serviceDispatchIn(&g_smSrv, cmd_id, pid_placeholder, .in_send_pid = true); } Result _smInitialize(void) { Handle sm_handle; Result rc = svcConnectToNamedPort(&sm_handle, "sm:"); while (R_VALUE(rc) == KERNELRESULT(NotFound)) { svcSleepThread(50000000ul); rc = svcConnectToNamedPort(&sm_handle, "sm:"); } if (R_SUCCEEDED(rc)) { serviceCreate(&g_smSrv, sm_handle); } Handle tmp; if (R_SUCCEEDED(rc) && R_VALUE(smGetServiceOriginal(&tmp, (SmServiceName){})) == 0x415) { rc = _smCmdInPid(0); } return rc; } void _smCleanup(void) { serviceClose(&g_smSrv); } Service *smGetServiceSession(void) { return &g_smSrv; } 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); } if (R_SUCCEEDED(rc)) { serviceCreate(service_out, handle); service_out->own_handle = own_handle; } return rc; } 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, 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, .out_handle_attrs = { SfOutHandleAttr_HipcMove }, .out_handles = handle_out, ); } Result smUnregisterService(SmServiceName name) { return serviceDispatchIn(&g_smSrv, 3, name); } Result smDetachClient(void) { if (!hosversionIsAtmosphere() && hosversionBefore(11,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _smCmdInPid(4); }