diff --git a/nx/Makefile b/nx/Makefile index d236e525..b552c627 100644 --- a/nx/Makefile +++ b/nx/Makefile @@ -24,7 +24,7 @@ VERSION := $(LIBNX_MAJOR).$(LIBNX_MINOR).$(LIBNX_PATCH) #--------------------------------------------------------------------------------- TARGET := nx #BUILD := build -SOURCES := source/arm source/kernel source/services source/crypto source/nvidia source/nvidia/ioctl source/display source/audio source/applets source/runtime source/runtime/devices source/runtime/util/utf +SOURCES := source/arm source/kernel source/sf source/services source/crypto source/nvidia source/nvidia/ioctl source/display source/audio source/applets source/runtime source/runtime/devices source/runtime/util/utf DATA := data INCLUDES := include external/bsd/include diff --git a/nx/include/switch.h b/nx/include/switch.h index 69550034..2d8fb7c8 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -42,6 +42,7 @@ extern "C" { #include "switch/sf/hipc.h" #include "switch/sf/cmif.h" #include "switch/sf/service.h" +#include "switch/sf/sessionmgr.h" #include "switch/services/sm.h" #include "switch/services/smm.h" diff --git a/nx/include/switch/sf/sessionmgr.h b/nx/include/switch/sf/sessionmgr.h new file mode 100644 index 00000000..73979937 --- /dev/null +++ b/nx/include/switch/sf/sessionmgr.h @@ -0,0 +1,26 @@ +#pragma once +#include "../types.h" +#include "../kernel/mutex.h" +#include "../kernel/condvar.h" + +#define NX_SESSION_MGR_MAX_SESSIONS 16 + +typedef struct SessionMgr +{ + Handle sessions[NX_SESSION_MGR_MAX_SESSIONS]; + u32 num_sessions; + u32 free_mask; + Mutex mutex; + CondVar condvar; + bool is_waiting; +} SessionMgr; + +Result sessionmgrCreate(SessionMgr* mgr, Handle root_session, u32 num_sessions); +void sessionmgrClose(SessionMgr* mgr); +int sessionmgrAttachClient(SessionMgr* mgr); +void sessionmgrDetachClient(SessionMgr* mgr, int slot); + +NX_CONSTEXPR Handle sessionmgrGetClientSession(SessionMgr* mgr, int slot) +{ + return mgr->sessions[slot]; +} diff --git a/nx/source/services/fs.c b/nx/source/services/fs.c index 15a518a7..ed0b99dd 100644 --- a/nx/source/services/fs.c +++ b/nx/source/services/fs.c @@ -1,52 +1,18 @@ // Copyright 2017 plutoo #include #include "service_guard.h" -#include "kernel/mutex.h" -#include "kernel/condvar.h" +#include "sf/sessionmgr.h" #include "runtime/hosversion.h" #include "services/fs.h" #include "services/acc.h" -#define FS_MAX_SESSIONS 8 - __attribute__((weak)) u32 __nx_fs_num_sessions = 3; static Service g_fsSrv; - -static Handle g_fsSessions[FS_MAX_SESSIONS]; -static u32 g_fsSessionFreeMask; -static Mutex g_fsSessionMutex; -static CondVar g_fsSessionCondVar; -static bool g_fsSessionWaiting; +static SessionMgr g_fsSessionMgr; static __thread u32 g_fsPriority = FsPriority_Normal; -static int _fsGetSessionSlot(void) -{ - mutexLock(&g_fsSessionMutex); - int slot; - for (;;) { - slot = __builtin_ffs(g_fsSessionFreeMask)-1; - if (slot >= 0) break; - g_fsSessionWaiting = true; - condvarWait(&g_fsSessionCondVar, &g_fsSessionMutex); - } - g_fsSessionFreeMask &= ~(1U << slot); - mutexUnlock(&g_fsSessionMutex); - return slot; -} - -static void _fsPutSessionSlot(int slot) -{ - mutexLock(&g_fsSessionMutex); - g_fsSessionFreeMask |= 1U << slot; - if (g_fsSessionWaiting) { - g_fsSessionWaiting = false; - condvarWakeOne(&g_fsSessionCondVar); - } - mutexUnlock(&g_fsSessionMutex); -} - NX_INLINE bool _fsObjectIsChild(Service* s) { return s->session == g_fsSrv.session; @@ -58,12 +24,12 @@ static void _fsObjectClose(Service* s) serviceClose(s); } else { - int slot = _fsGetSessionSlot(); + int slot = sessionmgrAttachClient(&g_fsSessionMgr); uint32_t object_id = serviceGetObjectId(s); serviceAssumeDomain(s); cmifMakeCloseRequest(armGetTls(), object_id); - svcSendSyncRequest(g_fsSessions[slot]); - _fsPutSessionSlot(slot); + svcSendSyncRequest(sessionmgrGetClientSession(&g_fsSessionMgr, slot)); + sessionmgrDetachClient(&g_fsSessionMgr, slot); } } @@ -75,9 +41,9 @@ NX_INLINE Result _fsObjectDispatchImpl( ) { int slot = -1; if (_fsObjectIsChild(s)) { - slot = _fsGetSessionSlot(); + slot = sessionmgrAttachClient(&g_fsSessionMgr); if (slot < 0) __builtin_unreachable(); - disp.target_session = g_fsSessions[slot]; + disp.target_session = sessionmgrGetClientSession(&g_fsSessionMgr, slot); serviceAssumeDomain(s); } @@ -85,7 +51,7 @@ NX_INLINE Result _fsObjectDispatchImpl( Result rc = serviceDispatchImpl(s, request_id, in_data, in_data_size, out_data, out_data_size, disp); if (slot >= 0) { - _fsPutSessionSlot(slot); + sessionmgrDetachClient(&g_fsSessionMgr, slot); } return rc; @@ -106,9 +72,6 @@ NX_INLINE Result _fsObjectDispatchImpl( NX_GENERATE_SERVICE_GUARD(fs); Result _fsInitialize(void) { - if (__nx_fs_num_sessions < 1 || __nx_fs_num_sessions > FS_MAX_SESSIONS) - return MAKERESULT(Module_Libnx, LibnxError_BadInput); - Result rc = smGetService(&g_fsSrv, "fsp-srv"); if (R_SUCCEEDED(rc)) { @@ -121,28 +84,15 @@ Result _fsInitialize(void) { rc = serviceDispatchIn(&g_fsSrv, 1, pid_placeholder, .in_send_pid = true); } - if (R_SUCCEEDED(rc)) { - g_fsSessionFreeMask = (1U << __nx_fs_num_sessions) - 1U; - g_fsSessions[0] = g_fsSrv.session; - } - - for (u32 i = 1; R_SUCCEEDED(rc) && i < __nx_fs_num_sessions; i ++) { - rc = cmifCloneCurrentObject(g_fsSessions[0], &g_fsSessions[i]); - } + if (R_SUCCEEDED(rc)) + rc = sessionmgrCreate(&g_fsSessionMgr, g_fsSrv.session, __nx_fs_num_sessions); return rc; } void _fsCleanup(void) { // Close extra sessions - g_fsSessions[0] = INVALID_HANDLE; - for (u32 i = 1; i < __nx_fs_num_sessions; i ++) { - if (g_fsSessions[i] != INVALID_HANDLE) { - cmifMakeCloseRequest(armGetTls(), 0); - svcSendSyncRequest(g_fsSessions[i]); - g_fsSessions[i] = INVALID_HANDLE; - } - } + sessionmgrClose(&g_fsSessionMgr); // We can't assume g_fsSrv is a domain here because serviceConvertToDomain might have failed serviceClose(&g_fsSrv); diff --git a/nx/source/sf/sessionmgr.c b/nx/source/sf/sessionmgr.c new file mode 100644 index 00000000..b1a1b70d --- /dev/null +++ b/nx/source/sf/sessionmgr.c @@ -0,0 +1,61 @@ +#include "kernel/svc.h" +#include "sf/cmif.h" +#include "sf/sessionmgr.h" + +Result sessionmgrCreate(SessionMgr* mgr, Handle root_session, u32 num_sessions) { + if (root_session == INVALID_HANDLE) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + if (num_sessions < 1 || num_sessions > NX_SESSION_MGR_MAX_SESSIONS) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + if (mgr->sessions[0] != INVALID_HANDLE) + return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized); + + __builtin_memset(mgr, 0, sizeof(*mgr)); + mgr->sessions[0] = root_session; + mgr->num_sessions = num_sessions; + mgr->free_mask = (1U << num_sessions) - 1U; + + Result rc = 0; + for (u32 i = 1; R_SUCCEEDED(rc) && i < num_sessions; i ++) + rc = cmifCloneCurrentObject(root_session, &mgr->sessions[i]); + + return rc; +} + +void sessionmgrClose(SessionMgr* mgr) { + if (mgr->sessions[0] == INVALID_HANDLE) + return; + + mgr->sessions[0] = INVALID_HANDLE; + for (u32 i = 1; i < mgr->num_sessions; i ++) { + if (mgr->sessions[i] != INVALID_HANDLE) { + cmifMakeCloseRequest(armGetTls(), 0); + svcSendSyncRequest(mgr->sessions[i]); + mgr->sessions[i] = INVALID_HANDLE; + } + } +} + +int sessionmgrAttachClient(SessionMgr* mgr) { + mutexLock(&mgr->mutex); + int slot; + for (;;) { + slot = __builtin_ffs(mgr->free_mask)-1; + if (slot >= 0) break; + mgr->is_waiting = true; + condvarWait(&mgr->condvar, &mgr->mutex); + } + mgr->free_mask &= ~(1U << slot); + mutexUnlock(&mgr->mutex); + return slot; +} + +void sessionmgrDetachClient(SessionMgr* mgr, int slot) { + mutexLock(&mgr->mutex); + mgr->free_mask |= 1U << slot; + if (mgr->is_waiting) { + mgr->is_waiting = false; + condvarWakeOne(&mgr->condvar); + } + mutexUnlock(&mgr->mutex); +}