mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 13:21:49 +01:00
JVM Auto-Attach + Fix Thread Exiting + Fix Thread Signal Handler
This commit is contained in:
parent
6f2cd41470
commit
657beea070
@ -3,30 +3,53 @@
|
||||
|
||||
#include "jvm.h"
|
||||
|
||||
thread_local JNIEnv *env;
|
||||
|
||||
namespace skyline {
|
||||
JvmManager::JvmManager(JNIEnv *environ, jobject instance) : instance(environ->NewGlobalRef(instance)), instanceClass(reinterpret_cast<jclass>(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;
|
||||
/*
|
||||
* @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<jclass>(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 = JniEnvironment(environ);
|
||||
}
|
||||
|
||||
JvmManager::~JvmManager() {
|
||||
env->DeleteGlobalRef(instanceClass);
|
||||
env->DeleteGlobalRef(instance);
|
||||
}
|
||||
|
||||
void JvmManager::AttachThread() {
|
||||
if (!env)
|
||||
vm->AttachCurrentThread(&env, nullptr);
|
||||
}
|
||||
|
||||
void JvmManager::DetachThread() {
|
||||
if (env)
|
||||
vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
JNIEnv *JvmManager::GetEnv() {
|
||||
return env;
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -141,16 +141,22 @@ namespace skyline::kernel {
|
||||
if (lower->size) {
|
||||
upper = chunks.insert(upper, lowerExtension);
|
||||
chunks.insert(upper, chunk);
|
||||
} else {
|
||||
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;
|
||||
chunks.insert(upper, lowerExtension);
|
||||
}
|
||||
} else if (chunk.IsCompatible(*lower)) {
|
||||
lower->size = std::max(lower->ptr + lower->size, chunk.ptr + chunk.size) - lower->ptr;
|
||||
upper = chunks.insert(upper, lowerExtension);
|
||||
}
|
||||
} 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)
|
||||
|
@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace skyline::kernel::svc {
|
||||
state.ctx->gpr.w0 = Result{};
|
||||
state.ctx->gpr.x1 = reinterpret_cast<u64>(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<bool>(value.isUncached), pointer, size);
|
||||
state.logger->Debug("svcSetMemoryAttribute: Set caching to {} at 0x{:X} - 0x{:X} (0x{:X} bytes)", static_cast<bool>(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<type::KPrivateMemory>(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<type::KTransferMemory>(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:
|
||||
|
@ -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);
|
||||
|
@ -49,8 +49,15 @@ namespace skyline::kernel::type {
|
||||
return tlsPage->ReserveSlot();
|
||||
}
|
||||
|
||||
std::shared_ptr<KThread> KProcess::CreateThread(void *entry, u64 argument, i8 priority, const std::shared_ptr<KPrivateMemory> &stack) {
|
||||
auto thread{NewHandle<KThread>(this, threads.size(), entry, argument, priority, stack).item};
|
||||
std::shared_ptr<KThread> 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<u8 *>(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<KThread>(this, threads.size(), entry, argument, stackTop, priority).item};
|
||||
threads.push_back(thread);
|
||||
return thread;
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ namespace skyline {
|
||||
|
||||
public:
|
||||
MemoryManager memory;
|
||||
std::shared_ptr<KPrivateMemory> mainThreadStack;
|
||||
std::shared_ptr<KPrivateMemory> heap;
|
||||
std::vector<std::shared_ptr<KThread>> threads;
|
||||
std::vector<std::shared_ptr<TlsPage>> tlsPages;
|
||||
@ -80,7 +81,7 @@ namespace skyline {
|
||||
*/
|
||||
u8* AllocateTlsSlot();
|
||||
|
||||
std::shared_ptr<KThread> CreateThread(void *entry, u64 argument = 0, i8 priority = 44, const std::shared_ptr<KPrivateMemory> &stack = nullptr);
|
||||
std::shared_ptr<KThread> CreateThread(void *entry, u64 argument = 0, void *stackTop = nullptr, i8 priority = constant::DefaultPriority);
|
||||
|
||||
/**
|
||||
* @brief The output for functions that return created kernel objects
|
||||
|
@ -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<u8 *>(mmap(ptr, size, permission.Get(), MAP_SHARED | (ptr ? MAP_FIXED : 0), fd, 0));
|
||||
if (guest.ptr == MAP_FAILED)
|
||||
|
@ -4,12 +4,15 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <nce.h>
|
||||
#include <os.h>
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
#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<KPrivateMemory> &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<decltype(&sigaction)>(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<u8 *>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,20 +51,20 @@ namespace skyline {
|
||||
void StartThread();
|
||||
|
||||
public:
|
||||
std::atomic<bool> running{false};
|
||||
bool running{false};
|
||||
std::atomic<bool> 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<KPrivateMemory> 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<KPrivateMemory>& 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();
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,5 @@ namespace skyline::kernel {
|
||||
* @return An instance of the KProcess of the created process
|
||||
*/
|
||||
std::shared_ptr<type::KProcess> 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);
|
||||
};
|
||||
}
|
||||
|
@ -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 {};
|
||||
}
|
||||
|
@ -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<frz::string, DisplayId, 5> DisplayTypeMap{
|
||||
{"Default", DisplayId::Default},
|
||||
{"External", DisplayId::External},
|
||||
|
@ -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<u64>(entry.gpuOffset) << MinAlignmentShift};
|
||||
u8* mapPointer{mapping->pointer + (static_cast<u64>(entry.mapOffset) << MinAlignmentShift)};
|
||||
|
@ -14,8 +14,9 @@ namespace skyline::service::nvdrv::device {
|
||||
u32 handle; // Out
|
||||
} &data = buffer.as<Data>();
|
||||
|
||||
handleTable[handleIndex] = std::make_shared<NvMapObject>(idIndex++, data.size);
|
||||
data.handle = handleIndex++;
|
||||
std::unique_lock lock(mapMutex);
|
||||
maps.push_back(std::make_shared<NvMapObject>(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<Data>();
|
||||
|
||||
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<Data>();
|
||||
|
||||
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<Data>();
|
||||
|
||||
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<Data>();
|
||||
|
||||
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<Data>();
|
||||
|
||||
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 &) {
|
||||
|
@ -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<KHandle, std::shared_ptr<NvMapObject>> 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<std::shared_ptr<NvMapObject>> maps;
|
||||
|
||||
u32 idIndex{1}; //!< This is used to keep track of the next ID to allocate
|
||||
|
||||
NvMap(const DeviceState &state);
|
||||
|
||||
inline std::shared_ptr<NvMapObject> 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
|
||||
|
Loading…
Reference in New Issue
Block a user