From 657beea0705e5f38976108447dfc584287be7d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Sat, 17 Oct 2020 17:08:27 +0530 Subject: [PATCH] JVM Auto-Attach + Fix Thread Exiting + Fix Thread Signal Handler --- app/src/main/cpp/skyline/jvm.cpp | 53 +++++++++++++------ app/src/main/cpp/skyline/jvm.h | 11 ---- app/src/main/cpp/skyline/kernel/memory.cpp | 18 ++++--- app/src/main/cpp/skyline/kernel/memory.h | 6 +-- app/src/main/cpp/skyline/kernel/svc.cpp | 21 ++++---- .../skyline/kernel/types/KPrivateMemory.cpp | 4 +- .../cpp/skyline/kernel/types/KProcess.cpp | 11 +++- .../main/cpp/skyline/kernel/types/KProcess.h | 3 +- .../skyline/kernel/types/KSharedMemory.cpp | 4 +- .../main/cpp/skyline/kernel/types/KThread.cpp | 42 +++++++++------ .../main/cpp/skyline/kernel/types/KThread.h | 10 ++-- app/src/main/cpp/skyline/os.cpp | 13 ----- app/src/main/cpp/skyline/os.h | 6 --- .../services/am/storage/IStorageAccessor.cpp | 2 +- .../hosbinder/GraphicBufferProducer.cpp | 13 +++-- .../services/nvdrv/devices/nvhost_as_gpu.cpp | 4 +- .../skyline/services/nvdrv/devices/nvmap.cpp | 27 +++++----- .../skyline/services/nvdrv/devices/nvmap.h | 17 ++++-- 18 files changed, 149 insertions(+), 116 deletions(-) diff --git a/app/src/main/cpp/skyline/jvm.cpp b/app/src/main/cpp/skyline/jvm.cpp index 2618d83f..d6d2bf06 100644 --- a/app/src/main/cpp/skyline/jvm.cpp +++ b/app/src/main/cpp/skyline/jvm.cpp @@ -3,13 +3,46 @@ #include "jvm.h" -thread_local JNIEnv *env; - namespace skyline { + /* + * @brief A thread-local wrapper over JNIEnv and JavaVM which automatically handles attaching and detaching threads + */ + struct JniEnvironment { + static inline JNIEnv *env{}; + static inline JavaVM *vm{}; + bool attached{}; + + JniEnvironment(JNIEnv *environment) { + env = environment; + if (env->GetJavaVM(&vm) < 0) + throw exception("Cannot get JavaVM from environment"); + } + + JniEnvironment() { + if (vm) { + vm->AttachCurrentThread(&env, nullptr); + attached = true; + } + } + + ~JniEnvironment() { + if (vm && attached) + vm->DetachCurrentThread(); + } + + operator JNIEnv *() { + return env; + } + + JNIEnv* operator->() { + return env; + } + }; + + thread_local inline JniEnvironment env; + JvmManager::JvmManager(JNIEnv *environ, jobject instance) : instance(environ->NewGlobalRef(instance)), instanceClass(reinterpret_cast(environ->NewGlobalRef(environ->GetObjectClass(instance)))), initializeControllersId(environ->GetMethodID(instanceClass, "initializeControllers", "()V")), vibrateDeviceId(environ->GetMethodID(instanceClass, "vibrateDevice", "(I[J[I)V")), clearVibrationDeviceId(environ->GetMethodID(instanceClass, "clearVibrationDevice", "(I)V")) { - env = environ; - if (env->GetJavaVM(&vm) < 0) - throw exception("Cannot get JavaVM from environment"); + env = JniEnvironment(environ); } JvmManager::~JvmManager() { @@ -17,16 +50,6 @@ namespace skyline { env->DeleteGlobalRef(instance); } - void JvmManager::AttachThread() { - if (!env) - vm->AttachCurrentThread(&env, nullptr); - } - - void JvmManager::DetachThread() { - if (env) - vm->DetachCurrentThread(); - } - JNIEnv *JvmManager::GetEnv() { return env; } diff --git a/app/src/main/cpp/skyline/jvm.h b/app/src/main/cpp/skyline/jvm.h index e5d6c8e6..a5006e93 100644 --- a/app/src/main/cpp/skyline/jvm.h +++ b/app/src/main/cpp/skyline/jvm.h @@ -12,7 +12,6 @@ namespace skyline { */ class JvmManager { public: - JavaVM *vm{}; //!< A pointer to the Java VM jobject instance; //!< A reference to the activity jclass instanceClass; //!< The class of the activity @@ -24,16 +23,6 @@ namespace skyline { ~JvmManager(); - /** - * @brief Attach the current thread to the Java VM - */ - void AttachThread(); - - /** - * @brief Detach the current thread to the Java VM - */ - void DetachThread(); - /** * @brief Returns a pointer to the JNI environment for the current thread */ diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index 066490e7..d7f085cc 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -142,15 +142,21 @@ namespace skyline::kernel { upper = chunks.insert(upper, lowerExtension); chunks.insert(upper, chunk); } else { - *lower = chunk; - chunks.insert(upper, lowerExtension); + auto lower2{std::prev(lower)}; + if (chunk.IsCompatible(*lower2) && lower2->ptr + lower2->size >= chunk.ptr) { + lower2->size = chunk.ptr + chunk.size - lower2->ptr; + upper = chunks.erase(lower); + } else { + *lower = chunk; + } + upper = chunks.insert(upper, lowerExtension); } - } else if (chunk.IsCompatible(*lower)) { - lower->size = std::max(lower->ptr + lower->size, chunk.ptr + chunk.size) - lower->ptr; + } else if (chunk.IsCompatible(*lower) && lower->ptr + lower->size >= chunk.ptr) { + lower->size = chunk.ptr + chunk.size - lower->ptr; } else { if (lower->ptr + lower->size > chunk.ptr) lower->size = chunk.ptr - lower->ptr; - if (upper != chunks.end() && chunk.IsCompatible(*upper)) { + if (upper != chunks.end() && chunk.IsCompatible(*upper) && chunk.ptr + chunk.size >= upper->ptr) { upper->ptr = chunk.ptr; upper->size = chunk.size + upper->size; } else { @@ -170,7 +176,7 @@ namespace skyline::kernel { return std::nullopt; } - size_t MemoryManager::GetProgramSize() { + size_t MemoryManager::GetMemoryUsage() { size_t size{}; for (const auto &chunk : chunks) if (chunk.state != memory::states::Unmapped) diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index 468145e1..5a347d38 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -53,7 +53,7 @@ namespace skyline { bool isDeviceShared : 1; //!< True when DeviceRefCount > 0 bool isUncached : 1; //!< This is used to disable memory caching to share memory with the GPU }; - u32 value; + u32 value{}; }; /** @@ -137,7 +137,7 @@ namespace skyline { bool attributeChangeAllowed : 1; //!< If the application can use svcSetMemoryAttribute on this block bool codeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block }; - u32 value; + u32 value{}; }; static_assert(sizeof(MemoryState) == sizeof(u32)); @@ -239,7 +239,7 @@ namespace skyline { /** * @return The cumulative size of all memory mappings in bytes */ - size_t GetProgramSize(); + size_t GetMemoryUsage(); }; } } diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index d0315301..a948fd6a 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -24,7 +24,7 @@ namespace skyline::kernel::svc { state.ctx->gpr.w0 = Result{}; state.ctx->gpr.x1 = reinterpret_cast(heap->ptr); - state.logger->Debug("svcSetHeapSize: Allocated at {} for 0x{:X} bytes", heap->ptr, heap->size); + state.logger->Debug("svcSetHeapSize: Allocated at 0x{:X} - 0x{:X} (0x{:X} bytes)", heap->ptr, heap->ptr + heap->size, heap->size); } void SetMemoryAttribute(const DeviceState &state) { @@ -71,7 +71,7 @@ namespace skyline::kernel::svc { newChunk.attributes.isUncached = value.isUncached; state.process->memory.InsertChunk(newChunk); - state.logger->Debug("svcSetMemoryAttribute: Set caching to {} at 0x{:X} for 0x{:X} bytes", static_cast(value.isUncached), pointer, size); + state.logger->Debug("svcSetMemoryAttribute: Set caching to {} at 0x{:X} - 0x{:X} (0x{:X} bytes)", static_cast(value.isUncached), pointer, pointer + size, size); state.ctx->gpr.w0 = Result{}; } @@ -216,7 +216,7 @@ namespace skyline::kernel::svc { void ExitProcess(const DeviceState &state) { state.logger->Debug("svcExitProcess: Exiting process"); - //state.os->KillThread(state.process->pid); + exit(0); } void CreateThread(const DeviceState &state) { @@ -235,7 +235,7 @@ namespace skyline::kernel::svc { if (!stack) throw exception("svcCreateThread: Cannot find memory object in handle table for thread stack: 0x{:X}", stackTop); - auto thread{state.process->CreateThread(entry, entryArgument, priority, static_pointer_cast(stack->item))}; + auto thread{state.process->CreateThread(entry, entryArgument, stackTop, priority)}; state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, ID: {})", thread->handle, entry, entryArgument, stackTop, priority, thread->id); state.ctx->gpr.w1 = thread->handle; @@ -257,7 +257,8 @@ namespace skyline::kernel::svc { void ExitThread(const DeviceState &state) { state.logger->Debug("svcExitThread: Exiting current thread: {}", state.thread->id); - state.os->KillThread(state.thread->id); + state.thread->Kill(); + pthread_exit(nullptr); } void SleepThread(const DeviceState &state) { @@ -338,7 +339,7 @@ namespace skyline::kernel::svc { return; } - state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} for {} bytes ({}{}{})", pointer, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-'); + state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-'); object->Map(pointer, size, permission); @@ -372,7 +373,7 @@ namespace skyline::kernel::svc { } auto tmem{state.process->NewHandle(pointer, size, permission)}; - state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} for {} bytes ({}{}{})", pointer, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-'); + state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{})", pointer, pointer + size, size, permission.r ? 'R' : '-', permission.w ? 'W' : '-', permission.x ? 'X' : '-'); state.ctx->gpr.w0 = Result{}; state.ctx->gpr.w1 = tmem.handle; @@ -674,7 +675,7 @@ namespace skyline::kernel::svc { break; case constant::infoState::TotalMemoryUsage: - out = state.process->heap->size + state.thread->stack->size + state.process->memory.GetProgramSize(); + out = state.process->memory.GetMemoryUsage(); break; case constant::infoState::AddressSpaceBaseAddr: @@ -698,7 +699,7 @@ namespace skyline::kernel::svc { break; case constant::infoState::PersonalMmHeapUsage: - out = state.process->heap->size + state.thread->stack->size; + out = state.process->heap->size + state.process->mainThreadStack->size; break; case constant::infoState::TotalMemoryAvailableWithoutMmHeap: @@ -706,7 +707,7 @@ namespace skyline::kernel::svc { break; case constant::infoState::TotalMemoryUsedWithoutMmHeap: - out = state.process->heap->size + state.thread->stack->size; // TODO: Same as above + out = state.process->heap->size + state.process->mainThreadStack->size; // TODO: Same as above break; case constant::infoState::UserExceptionContextAddr: diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp index 3ed9f503..ca01fa97 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp @@ -11,8 +11,8 @@ namespace skyline::kernel::type { KPrivateMemory::KPrivateMemory(const DeviceState &state, u8* ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memState(memState), KMemory(state, KType::KPrivateMemory) { if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + size)) throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size); - if (!util::PageAligned(ptr)) - throw exception("KPrivateMemory was created with non-page-aligned address: 0x{:X}", ptr); + if (!util::PageAligned(ptr) || !util::PageAligned(size)) + throw exception("KPrivateMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size); if (mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) // We only need to reprotect as the allocation has already been reserved by the MemoryManager throw exception("An occurred while mapping private memory: {} with 0x{:X} @ 0x{:X}", strerror(errno), ptr, size); diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index 8ad688cd..b248199f 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -49,8 +49,15 @@ namespace skyline::kernel::type { return tlsPage->ReserveSlot(); } - std::shared_ptr KProcess::CreateThread(void *entry, u64 argument, i8 priority, const std::shared_ptr &stack) { - auto thread{NewHandle(this, threads.size(), entry, argument, priority, stack).item}; + std::shared_ptr KProcess::CreateThread(void *entry, u64 argument, void *stackTop, i8 priority) { + if (!stackTop && threads.empty()) { //!< Main thread stack is created by the kernel and owned by the process + constexpr u64 DefaultStackSize{0x200000}; //!< The default amount of stack: 2 MB + mainThreadStack = mainThreadStack.make_shared(state, reinterpret_cast(state.process->memory.stack.address), DefaultStackSize, memory::Permission{true, true, false}, memory::states::Stack); + if (mprotect(mainThreadStack->ptr, PAGE_SIZE, PROT_NONE)) + throw exception("Failed to create guard page for thread stack at 0x{:X}", mainThreadStack->ptr); + stackTop = mainThreadStack->ptr + mainThreadStack->size; + } + auto thread{NewHandle(this, threads.size(), entry, argument, stackTop, priority).item}; threads.push_back(thread); return thread; } diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index 365eea09..90e5ce8c 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -64,6 +64,7 @@ namespace skyline { public: MemoryManager memory; + std::shared_ptr mainThreadStack; std::shared_ptr heap; std::vector> threads; std::vector> tlsPages; @@ -80,7 +81,7 @@ namespace skyline { */ u8* AllocateTlsSlot(); - std::shared_ptr CreateThread(void *entry, u64 argument = 0, i8 priority = 44, const std::shared_ptr &stack = nullptr); + std::shared_ptr CreateThread(void *entry, u64 argument = 0, void *stackTop = nullptr, i8 priority = constant::DefaultPriority); /** * @brief The output for functions that return created kernel objects diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index d93f7371..f56ee33e 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -23,8 +23,8 @@ namespace skyline::kernel::type { u8 *KSharedMemory::Map(u8 *ptr, u64 size, memory::Permission permission) { if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + size)) throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size); - if (ptr && !util::PageAligned(ptr)) - throw exception("KSharedMemory was mapped to a non-page-aligned address: 0x{:X}", ptr); + if (!util::PageAligned(ptr) || !util::PageAligned(size)) + throw exception("KSharedMemory mapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", ptr, ptr + size, size); guest.ptr = reinterpret_cast(mmap(ptr, size, permission.Get(), MAP_SHARED | (ptr ? MAP_FIXED : 0), fd, 0)); if (guest.ptr == MAP_FAILED) diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index a90be954..e40cec64 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -4,12 +4,15 @@ #include #include #include +#include #include #include +#include +#include #include "KProcess.h" namespace skyline::kernel::type { - KThread::KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, i8 priority, const std::shared_ptr &stack) : handle(handle), parent(parent), id(id), entry(entry), entryArgument(argument), stack(stack), KSyncObject(state, KType::KThread) { + KThread::KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, void *stackTop, i8 priority) : handle(handle), parent(parent), id(id), entry(entry), entryArgument(argument), stackTop(stackTop), KSyncObject(state, KType::KThread) { UpdatePriority(priority); } @@ -17,6 +20,24 @@ namespace skyline::kernel::type { Kill(); } + /** + * @brief Our delegator for sigaction, we need to do this due to sigchain hooking bionic's sigaction and it intercepting signals before they're passed onto userspace + * This not only leads to performance degradation but also requires host TLS to be in the TLS register which we cannot ensure for in-guest signals + */ + inline void Sigaction(int signal, const struct sigaction &action, struct sigaction *oldAction = nullptr) { + static decltype(&sigaction) realSigaction{}; + if (!realSigaction) { + void *libc{dlopen("libc.so", RTLD_LOCAL | RTLD_LAZY)}; + if (!libc) + throw exception("dlopen-ing libc has failed with: {}", dlerror()); + realSigaction = reinterpret_cast(dlsym(libc, "sigaction")); + if (!realSigaction) + throw exception("Cannot find 'sigaction' in libc: {}", dlerror()); + } + if (realSigaction(signal, &action, oldAction) < 0) + throw exception("sigaction has failed with {}", strerror(errno)); + } + void KThread::StartThread() { pthread_setname_np(pthread_self(), fmt::format("HOS-{}", id).c_str()); @@ -31,9 +52,8 @@ namespace skyline::kernel::type { .sa_sigaction = &nce::NCE::SignalHandler, .sa_flags = SA_SIGINFO, }; - - //for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}) - // sigaction(signal, &sigact, nullptr); + for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}) + Sigaction(signal, sigact); asm volatile( "MRS X0, TPIDR_EL0\n\t" @@ -109,7 +129,7 @@ namespace skyline::kernel::type { "DUP V31.16B, WZR\n\t" "RET" : - : "r"(&ctx), "r"(stack->ptr + stack->size), "r"(entry), "r"(entryArgument), "r"(handle) + : "r"(&ctx), "r"(stackTop), "r"(entry), "r"(entryArgument), "r"(handle) : "x0", "x1", "lr" ); @@ -119,16 +139,7 @@ namespace skyline::kernel::type { void KThread::Start(bool self) { if (!running) { running = true; - state.logger->Debug("Starting thread #{}", id); - - if (!stack) { - constexpr u64 DefaultStackSize{0x1E8480}; //!< The default amount of stack: 2 MB - stack = stack.make_shared(state, reinterpret_cast(state.process->memory.stack.address), DefaultStackSize, memory::Permission{true, true, false}, memory::states::Stack); - if (mprotect(stack->ptr, PAGE_SIZE, PROT_NONE)) - throw exception("Failed to create guard page for thread stack at 0x{:X}", stack->ptr); - } - if (self) StartThread(); else @@ -139,10 +150,7 @@ namespace skyline::kernel::type { void KThread::Kill() { if (running) { running = false; - Signal(); - exit(0); - //tgkill(gettgid(), tid, SIGTERM); } } diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.h b/app/src/main/cpp/skyline/kernel/types/KThread.h index e644d5c8..5dc726f5 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.h +++ b/app/src/main/cpp/skyline/kernel/types/KThread.h @@ -51,20 +51,20 @@ namespace skyline { void StartThread(); public: - std::atomic running{false}; + bool running{false}; std::atomic cancelSync{false}; //!< This is to flag to a thread to cancel a synchronization call it currently is in KHandle handle; size_t id; //!< Index of thread in parent process's KThread vector - std::shared_ptr stack; nce::ThreadContext ctx{}; void* entry; u64 entryArgument; + void* stackTop; i8 priority; - KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument = 0, i8 priority = constant::DefaultPriority, const std::shared_ptr& stack = nullptr); + KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, void *stackTop, i8 priority = constant::DefaultPriority); ~KThread(); @@ -75,6 +75,10 @@ namespace skyline { */ void Start(bool self = false); + /** + * @brief Updates the internal state of the thread to signal it being dead + * @note This should only be called by the host thread running this guest thread + */ void Kill(); /** diff --git a/app/src/main/cpp/skyline/os.cpp b/app/src/main/cpp/skyline/os.cpp index 0e14607f..a2d185a9 100644 --- a/app/src/main/cpp/skyline/os.cpp +++ b/app/src/main/cpp/skyline/os.cpp @@ -36,17 +36,4 @@ namespace skyline::kernel { state.nce->Execute(); } - - void OS::KillThread(pid_t pid) { - /* - if (process->pid == pid) { - state.logger->Debug("Killing process with PID: {}", pid); - for (auto &thread: process->threads) - thread.second->Kill(); - } else { - state.logger->Debug("Killing thread with TID: {}", pid); - process->threads.at(pid)->Kill(); - } - */ - } } diff --git a/app/src/main/cpp/skyline/os.h b/app/src/main/cpp/skyline/os.h index 9494101c..ec53d361 100644 --- a/app/src/main/cpp/skyline/os.h +++ b/app/src/main/cpp/skyline/os.h @@ -39,11 +39,5 @@ namespace skyline::kernel { * @return An instance of the KProcess of the created process */ std::shared_ptr CreateProcess(u64 entry, u64 argument, size_t stackSize); - - /** - * @brief Kill a particular thread - * @param pid The PID of the thread - */ - void KillThread(pid_t pid); }; } diff --git a/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp index bdf0dbdd..e22b7250 100644 --- a/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp +++ b/app/src/main/cpp/skyline/services/am/storage/IStorageAccessor.cpp @@ -20,7 +20,7 @@ namespace skyline::service::am { return result::OutOfBounds; if (size) - request.outputBuf.at(0).copy_from(span(parent->content.data() + offset, size)); + span(parent->content).copy_from(request.outputBuf.at(0), size); return {}; } diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp index a476d973..1c42f649 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp @@ -124,16 +124,18 @@ namespace skyline::service::hosbinder { auto nvmap{driver->nvMap.lock()}; if (gbpBuffer.nvmapHandle) { - nvBuffer = nvmap->handleTable.at(gbpBuffer.nvmapHandle); + nvBuffer = nvmap->GetObject(gbpBuffer.nvmapHandle); } else { - for (const auto &object : nvmap->handleTable) { - if (object.second->id == gbpBuffer.nvmapId) { - nvBuffer = object.second; + std::shared_lock nvmapLock(nvmap->mapMutex); + for (const auto &object : nvmap->maps) { + if (object->id == gbpBuffer.nvmapId) { + nvBuffer = object; break; } } if (!nvBuffer) throw exception("A QueueBuffer request has an invalid NVMap Handle ({}) and ID ({})", gbpBuffer.nvmapHandle, gbpBuffer.nvmapId); + nvmapLock.unlock(); } gpu::texture::Format format; @@ -187,9 +189,6 @@ namespace skyline::service::hosbinder { } } - /** - * @brief A mapping from a display's name to it's displayType entry - */ static frz::unordered_map DisplayTypeMap{ {"Default", DisplayId::Default}, {"External", DisplayId::External}, diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp index 42feae1f..ec1308ee 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp @@ -81,7 +81,7 @@ namespace skyline::service::nvdrv::device { try { auto driver{nvdrv::driver.lock()}; auto nvmap{driver->nvMap.lock()}; - auto mapping{nvmap->handleTable.at(data.nvmapHandle)}; + auto mapping{nvmap->GetObject(data.nvmapHandle)}; if (data.flags.remap) { auto region{regionMap.upper_bound(data.offset)}; @@ -180,7 +180,7 @@ namespace skyline::service::nvdrv::device { try { auto driver{nvdrv::driver.lock()}; auto nvmap{driver->nvMap.lock()}; - auto mapping{nvmap->handleTable.at(entry.nvmapHandle)}; + auto mapping{nvmap->GetObject(entry.nvmapHandle)}; u64 mapAddress{static_cast(entry.gpuOffset) << MinAlignmentShift}; u8* mapPointer{mapping->pointer + (static_cast(entry.mapOffset) << MinAlignmentShift)}; diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp index 20c43431..839895f8 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp @@ -14,8 +14,9 @@ namespace skyline::service::nvdrv::device { u32 handle; // Out } &data = buffer.as(); - handleTable[handleIndex] = std::make_shared(idIndex++, data.size); - data.handle = handleIndex++; + std::unique_lock lock(mapMutex); + maps.push_back(std::make_shared(idIndex++, data.size)); + data.handle = maps.size(); state.logger->Debug("Size: 0x{:X} -> Handle: 0x{:X}", data.size, data.handle); return NvStatus::Success; @@ -27,9 +28,10 @@ namespace skyline::service::nvdrv::device { u32 handle; // Out } &data = buffer.as(); - for (const auto &object : handleTable) { - if (object.second->id == data.id) { - data.handle = object.first; + std::shared_lock lock(mapMutex); + for (auto it{maps.begin()}; it < maps.end(); it++) { + if ((*it)->id == data.id) { + data.handle = (it - maps.begin()) + 1; state.logger->Debug("ID: 0x{:X} -> Handle: 0x{:X}", data.id, data.handle); return NvStatus::Success; } @@ -47,11 +49,11 @@ namespace skyline::service::nvdrv::device { u32 align; // In u8 kind; // In u8 _pad0_[7]; - u8* pointer; // InOut + u8 *pointer; // InOut } &data = buffer.as(); try { - auto &object{handleTable.at(data.handle)}; + auto object{GetObject(data.handle)}; object->heapMask = data.heapMask; object->flags = data.flags; object->align = data.align; @@ -71,13 +73,14 @@ namespace skyline::service::nvdrv::device { struct Data { u32 handle; // In u32 _pad0_; - u8* pointer; // Out + u8 *pointer; // Out u32 size; // Out u32 flags; // Out } &data = buffer.as(); + std::unique_lock lock(mapMutex); try { - const auto &object{handleTable.at(data.handle)}; + auto &object{maps.at(data.handle)}; if (object.use_count() > 1) { data.pointer = object->pointer; data.flags = 0x0; @@ -87,7 +90,7 @@ namespace skyline::service::nvdrv::device { } data.size = object->size; - handleTable.erase(data.handle); + object = nullptr; state.logger->Debug("Handle: 0x{:X} -> Pointer: 0x{:X}, Size: 0x{:X}, Flags: 0x{:X}", data.handle, data.pointer, data.size, data.flags); return NvStatus::Success; @@ -115,7 +118,7 @@ namespace skyline::service::nvdrv::device { } &data = buffer.as(); try { - auto &object{handleTable.at(data.handle)}; + auto object{GetObject(data.handle)}; switch (data.parameter) { case Parameter::Size: @@ -158,7 +161,7 @@ namespace skyline::service::nvdrv::device { } &data = buffer.as(); try { - data.id = handleTable.at(data.handle)->id; + data.id = GetObject(data.handle)->id; state.logger->Debug("Handle: 0x{:X} -> ID: 0x{:X}", data.handle, data.id); return NvStatus::Success; } catch (const std::out_of_range &) { diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h index 9d471805..50ad540d 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h @@ -18,7 +18,7 @@ namespace skyline::service::nvdrv::device { struct NvMapObject { u32 id; u32 size; - u8* pointer{}; + u8 *pointer{}; u32 flags{}; //!< The flag of the memory (0 = Read Only, 1 = Read-Write) u32 align{}; u32 heapMask{}; //!< This is set during Alloc and returned during Param @@ -32,12 +32,23 @@ namespace skyline::service::nvdrv::device { NvMapObject(u32 id, u32 size); }; - std::unordered_map> handleTable; //!< A mapping from a handle to it's corresponding NvMapObject - KHandle handleIndex{1}; //!< This is used to keep track of the next handle to allocate + std::shared_mutex mapMutex; //!< Synchronizes mutations and accesses of the mappings + std::vector> maps; + u32 idIndex{1}; //!< This is used to keep track of the next ID to allocate NvMap(const DeviceState &state); + inline std::shared_ptr GetObject(u32 handle) { + if (handle-- == 0) + throw std::out_of_range("0 is an invalid nvmap handle"); + std::shared_lock lock(mapMutex); + auto& object{maps.at(handle)}; + if (!object) + throw std::out_of_range("A freed nvmap handle was requested"); + return object; + } + /** * @brief Creates an NvMapObject and returns an handle to it * @url https://switchbrew.org/wiki/NV_services#NVMAP_IOC_CREATE