From 0fbc5f210faa5b42bc5762791675215056af9343 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Fri, 16 Sep 2022 16:05:17 +0300 Subject: [PATCH] Added the rest of the kernel resource functions --- include/cpu_dynarmic.hpp | 3 +- include/kernel/kernel.hpp | 6 +- include/kernel/kernel_types.hpp | 2 + include/kernel/resource_limits.hpp | 88 +++++++++++++++++++++++++- include/memory.hpp | 2 + src/core/kernel/kernel.cpp | 28 +-------- src/core/kernel/resource_limits.cpp | 96 +++++++++++++++++++++++++++++ src/core/memory.cpp | 11 ++++ 8 files changed, 206 insertions(+), 30 deletions(-) diff --git a/include/cpu_dynarmic.hpp b/include/cpu_dynarmic.hpp index 643b8809..31c045d0 100644 --- a/include/cpu_dynarmic.hpp +++ b/include/cpu_dynarmic.hpp @@ -42,8 +42,7 @@ public: } void MemoryWrite64(u32 vaddr, u64 value) override { - MemoryWrite32(vaddr, u32(value)); - MemoryWrite32(vaddr + 4, u32(value >> 32)); + mem.write64(vaddr, value); } void InterpreterFallback(u32 pc, size_t num_instructions) override { diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index bb75494a..abc435ee 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -48,11 +48,15 @@ class Kernel { Handle makeProcess(); KernelObject* getProcessFromPID(Handle handle); + s32 getCurrentResourceValue(const KernelObject* limit, u32 resourceName); + u32 getMaxForResource(const KernelObject* limit, u32 resourceName); + std::string getProcessName(u32 pid); + // SVC implementations void createAddressArbiter(); void getResourceLimit(); void getResourceLimitLimitValues(); - std::string getProcessName(u32 pid); + void getResourceLimitCurrentValues(); public: Kernel(std::array& regs, Memory& mem) : regs(regs), mem(mem), handleCounter(0) { diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index 63d44b52..28929e32 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -46,6 +46,8 @@ using Handle = u32; struct ResourceLimits { Handle handle; + + s32 currentCommit = 0; }; struct ProcessData { diff --git a/include/kernel/resource_limits.hpp b/include/kernel/resource_limits.hpp index 9d2077c9..ed414fa3 100644 --- a/include/kernel/resource_limits.hpp +++ b/include/kernel/resource_limits.hpp @@ -1,2 +1,88 @@ #pragma once -#include "kernel_types.hpp" \ No newline at end of file +#include "kernel_types.hpp" + +// Values and resource limit structure taken from Citra + +struct ResourceLimitValues { + u32 maxPriority; + u32 maxCommit; + u32 maxThreads; + u32 maxEvents; + u32 maxMutexes; + u32 maxSemaphores; + u32 maxTimers; + u32 maxSharedMem; + u32 maxAddressArbiters; + u32 maxCPUTime; +}; + +// APPLICATION resource limit +static constexpr ResourceLimitValues appResourceLimits = { + .maxPriority = 0x18, + .maxCommit = 0x4000000, + .maxThreads = 0x20, + .maxEvents = 0x20, + .maxMutexes = 0x20, + .maxSemaphores = 0x8, + .maxTimers = 0x8, + .maxSharedMem = 0x20, + .maxAddressArbiters = 0x2, + .maxCPUTime = 0x1E +}; + +// SYS_APPLET resource limit +static constexpr ResourceLimitValues sysAppletResourceLimits = { + .maxPriority = 0x4, + .maxCommit = 0x5E00000, + .maxThreads = 0x1D, + .maxEvents = 0xB, + .maxMutexes = 0x8, + .maxSemaphores = 0x4, + .maxTimers = 0x4, + .maxSharedMem = 0x8, + .maxAddressArbiters = 0x3, + .maxCPUTime = 0x2710 +}; + +// LIB_APPLET resource limit +static constexpr ResourceLimitValues libAppletResourceLimits = { + .maxPriority = 0x4, + .maxCommit = 0x600000, + .maxThreads = 0xE, + .maxEvents = 0x8, + .maxMutexes = 0x8, + .maxSemaphores = 0x4, + .maxTimers = 0x4, + .maxSharedMem = 0x8, + .maxAddressArbiters = 0x1, + .maxCPUTime = 0x2710 +}; + +// OTHER resource limit +static constexpr ResourceLimitValues otherResourceLimits = { + .maxPriority = 0x4, + .maxCommit = 0x2180000, + .maxThreads = 0xE1, + .maxEvents = 0x108, + .maxMutexes = 0x25, + .maxSemaphores = 0x43, + .maxTimers = 0x2C, + .maxSharedMem = 0x1F, + .maxAddressArbiters = 0x2D, + .maxCPUTime = 0x3E8 +}; + +namespace ResourceType { + enum : u32 { + Priority = 0, + Commit = 1, + Thread = 2, + Events = 3, + Mutex = 4, + Semaphore = 5, + Timer = 6, + SharedMem = 7, + AddressArbiter = 8, + CPUTime = 9 + }; +} \ No newline at end of file diff --git a/include/memory.hpp b/include/memory.hpp index 2f186afc..351733de 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -40,8 +40,10 @@ public: u8 read8(u32 vaddr); u16 read16(u32 vaddr); u32 read32(u32 vaddr); + u64 read64(u32 vaddr); void write8(u32 vaddr, u8 value); void write16(u32 vaddr, u16 value); void write32(u32 vaddr, u32 value); + void write64(u32 vaddr, u64 value); }; \ No newline at end of file diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 08e8ed11..fc079ad7 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -7,7 +7,8 @@ void Kernel::serviceSVC(u32 svc) { case 0x21: createAddressArbiter(); break; case 0x38: getResourceLimit(); break; case 0x39: getResourceLimitLimitValues(); break; - default: Helpers::panic("Unimplemented svc: %x @ %08X", svc, regs[15]); break; + case 0x3A: getResourceLimitCurrentValues(); break; + default: Helpers::panic("Unimplemented svc: %X @ %08X", svc, regs[15]); break; } } @@ -56,31 +57,6 @@ void Kernel::createAddressArbiter() { regs[0] = SVCResult::Success; } -// Result GetResourceLimit(Handle* resourceLimit, Handle process) -// out: r0 -> result -void Kernel::getResourceLimit() { - const auto handlePointer = regs[0]; - const auto pid = regs[1]; - const auto process = getProcessFromPID(pid); - - if (process == nullptr) [[unlikely]] { - regs[0] = SVCResult::BadHandle; - return; - } - - const auto processData = static_cast(process->data); - - printf("GetResourceLimit (Handle pointer = %08X, process: %s)\n", handlePointer, getProcessName(pid).c_str()); - mem.write32(handlePointer, processData->limits.handle); - regs[0] = SVCResult::Success; - // Is the handle meant to be output through both r1 and memory? Libctru breaks otherwise. - regs[1] = processData->limits.handle; -} - -void Kernel::getResourceLimitLimitValues() { - Helpers::panic("Trying to getResourceLimitLimitValues from resourceLimit with handle %08X\n", regs[1]); -} - std::string Kernel::getProcessName(u32 pid) { if (pid == KernelHandles::CurrentProcess) { return "current"; diff --git a/src/core/kernel/resource_limits.cpp b/src/core/kernel/resource_limits.cpp index e69de29b..6b17f2f7 100644 --- a/src/core/kernel/resource_limits.cpp +++ b/src/core/kernel/resource_limits.cpp @@ -0,0 +1,96 @@ +#include "resource_limits.hpp" +#include "kernel.hpp" + +// Result GetResourceLimit(Handle* resourceLimit, Handle process) +// out: r0 -> result, r1 -> handle +void Kernel::getResourceLimit() { + const auto handlePointer = regs[0]; + const auto pid = regs[1]; + const auto process = getProcessFromPID(pid); + + if (process == nullptr) [[unlikely]] { + regs[0] = SVCResult::BadHandle; + return; + } + + const auto processData = static_cast(process->data); + + printf("GetResourceLimit (handle pointer = %08X, process: %s)\n", handlePointer, getProcessName(pid).c_str()); + mem.write32(handlePointer, processData->limits.handle); + regs[0] = SVCResult::Success; + // Is the handle meant to be output through both r1 and memory? Libctru breaks otherwise. + regs[1] = processData->limits.handle; +} + +// Result GetResourceLimitLimitValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount) +void Kernel::getResourceLimitLimitValues() { + u32 values = regs[0]; // Pointer to values (The resource limits get output here) + const Handle resourceLimit = regs[1]; + u32 names = regs[2]; // Pointer to resources that we should return + u32 count = regs[3]; // Number of resources + + const KernelObject* limit = getObject(resourceLimit, KernelObjectType::ResourceLimit); + if (limit == nullptr) [[unlikely]] { + regs[0] = SVCResult::BadHandle; + return; + } + + printf("GetResourceLimitLimitValues(values = %08X, handle = %X, names = %08X, count = %d)\n", values, resourceLimit, names, count); + // printf("[Warning] We do not currently support any resource maximum aside from the application ones"); + while (count != 0) { + const u32 name = mem.read32(names); + u32 max = getMaxForResource(limit, name); + mem.write64(values, u64(max)); + + // Increment pointers and decrement count + values += sizeof(u64); + names += sizeof(u32); + count--; + } + + regs[0] = SVCResult::Success; +} + +// Result GetResourceLimitCurrentValues(s64* values, Handle resourceLimit, LimitableResource* names, s32 nameCount) +void Kernel::getResourceLimitCurrentValues() { + u32 values = regs[0]; // Pointer to values (The resource limits get output here) + const Handle resourceLimit = regs[1]; + u32 names = regs[2]; // Pointer to resources that we should return + u32 count = regs[3]; // Number of resources + + const KernelObject* limit = getObject(resourceLimit, KernelObjectType::ResourceLimit); + if (limit == nullptr) [[unlikely]] { + regs[0] = SVCResult::BadHandle; + return; + } + + printf("GetResourceLimitCurrentValues(values = %08X, handle = %X, names = %08X, count = %d)\n", values, resourceLimit, names, count); + while (count != 0) { + const u32 name = mem.read32(names); + // TODO: Unsure if this is supposed to be s32 or u32. Shouldn't matter as the kernel can't create so many resources + s32 value = getCurrentResourceValue(limit, name); + mem.write64(values, u64(value)); + + // Increment pointers and decrement count + values += sizeof(u64); + names += sizeof(u32); + count--; + } + + regs[0] = SVCResult::Success; +} + +s32 Kernel::getCurrentResourceValue(const KernelObject* limit, u32 resourceName) { + const auto data = static_cast(limit->data); + switch (resourceName) { + case ResourceType::Commit: return data->currentCommit; + default: Helpers::panic("Attempted to get current value of unknown kernel resource: %d\n", resourceName); + } +} + +u32 Kernel::getMaxForResource(const KernelObject* limit, u32 resourceName) { + switch (resourceName) { + case ResourceType::Commit: return appResourceLimits.maxCommit; + default: Helpers::panic("Attempted to get the max of unknown kernel resource: %d\n", resourceName); + } +} \ No newline at end of file diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 8775fe4c..651d7177 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -60,6 +60,12 @@ u32 Memory::read32(u32 vaddr) { } } +u64 Memory::read64(u32 vaddr) { + u64 bottom = u64(read32(vaddr)); + u64 top = u64(read32(vaddr + 4)); + return (top << 32) | bottom; +} + void Memory::write8(u32 vaddr, u8 value) { const u32 page = vaddr >> pageShift; const u32 offset = vaddr & pageMask; @@ -89,6 +95,11 @@ void Memory::write32(u32 vaddr, u32 value) { } } +void Memory::write64(u32 vaddr, u64 value) { + write32(vaddr, u32(value)); + write32(vaddr + 4, u32(value >> 32)); +} + void* Memory::getReadPointer(u32 address) { const u32 page = address >> pageShift; const u32 offset = address & pageMask;