Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tmem: Add tmemCloseHandle(), tmemWaitForPermission(), use those functions in nv.c to fix a race condition #606

Merged
merged 7 commits into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions nx/include/switch/kernel/tmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ static inline void* tmemGetAddr(TransferMemory* t){
return t->map_addr;
}

/**
* @brief Closes handle of a transfer memory object.
* @param t Transfer memory information structure.
* @return Result code.
*/
Result tmemCloseHandle(TransferMemory* t);

/**
* @brief Waits until source backing memory permissions match perm.
* @param t Transfer memory information structure.
* @param perm Permissions which the source backing memory is expected to have before return.
* @return Result code.
*/
Result tmemWaitForPermission(TransferMemory* t, Permission perm);

/**
* @brief Frees up resources used by a transfer memory object, unmapping and closing handles, etc.
* @param t Transfer memory information structure.
Expand Down
44 changes: 40 additions & 4 deletions nx/source/kernel/tmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,45 @@ Result tmemUnmap(TransferMemory* t)
return rc;
}

Result tmemCloseHandle(TransferMemory* t)
{
Result rc = 0;

if (t->handle != INVALID_HANDLE) {
rc = svcCloseHandle(t->handle);
t->handle = INVALID_HANDLE;
}

return rc;
}

Result tmemWaitForPermission(TransferMemory* t, Permission perm)
{
Result rc = 0;

if ((t->perm & perm) != perm) {
MemoryInfo m = {0};
u32 p = 0;
rc = svcQueryMemory(&m, &p, (u64)(t->src_addr));

if (R_FAILED(rc)) {
return rc;
}

while ((m.perm & perm) != perm) {
rc = svcQueryMemory(&m, &p, (u64)(t->src_addr));

if (R_FAILED(rc)) {
return rc;
}

svcSleepThread(100000);
}
}

return rc;
}

Result tmemClose(TransferMemory* t)
{
Result rc = 0;
Expand All @@ -109,16 +148,13 @@ Result tmemClose(TransferMemory* t)
}

if (R_SUCCEEDED(rc)) {
if (t->handle != INVALID_HANDLE) {
rc = svcCloseHandle(t->handle);
}
rc = tmemCloseHandle(t);

if (t->src_addr != NULL) {
__libnx_free(t->src_addr);
}

t->src_addr = NULL;
t->handle = INVALID_HANDLE;
}

return rc;
Expand Down
6 changes: 6 additions & 0 deletions nx/source/services/nv.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ Result _nvInitialize(void) {
if (R_SUCCEEDED(rc))
rc = _nvCmdInitialize(CUR_PROCESS_HANDLE, g_nvTransfermem.handle, tmem_size);

Result rc2 = tmemCloseHandle(&g_nvTransfermem);

if (R_SUCCEEDED(rc))
masagrator marked this conversation as resolved.
Show resolved Hide resolved
rc = rc2;

// Clone the session handle - the cloned session is used to execute certain commands in parallel
if (R_SUCCEEDED(rc))
rc = serviceCloneEx(&g_nvSrv, 1, &g_nvSrvClone);
Expand All @@ -73,6 +78,7 @@ Result _nvInitialize(void) {
void _nvCleanup(void) {
serviceClose(&g_nvSrvClone);
serviceClose(&g_nvSrv);
tmemWaitForPermission(&g_nvTransfermem, Perm_Rw);
tmemClose(&g_nvTransfermem);
}

Expand Down