Added the rest of the kernel resource functions

This commit is contained in:
wheremyfoodat 2022-09-16 16:05:17 +03:00
parent a89c850189
commit 0fbc5f210f
8 changed files with 206 additions and 30 deletions

View file

@ -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 {

View file

@ -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<u32, 16>& regs, Memory& mem) : regs(regs), mem(mem), handleCounter(0) {

View file

@ -46,6 +46,8 @@ using Handle = u32;
struct ResourceLimits {
Handle handle;
s32 currentCommit = 0;
};
struct ProcessData {

View file

@ -1,2 +1,88 @@
#pragma once
#include "kernel_types.hpp"
#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
};
}

View file

@ -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);
};

View file

@ -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<ProcessData*>(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";

View file

@ -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<ProcessData*>(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<ResourceLimits*>(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);
}
}

View file

@ -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;