From 0e66af8dae8f209f57957c4b4cdde67848099f2a Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sat, 17 Sep 2022 04:37:40 +0300 Subject: [PATCH] Initial implementation of ports and sessions --- CMakeLists.txt | 2 +- include/cpu_dynarmic.hpp | 1 - include/kernel/kernel.hpp | 6 ++++ include/kernel/kernel_types.hpp | 20 ++++++++++-- src/core/kernel/kernel.cpp | 30 ++++++++++------- src/core/kernel/ports.cpp | 57 +++++++++++++++++++++++++++++++++ src/core/memory.cpp | 1 - 7 files changed, 100 insertions(+), 17 deletions(-) create mode 100644 src/core/kernel/ports.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c1ba3950..56f499a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,7 @@ set(SOURCE_FILES src/main.cpp src/emulator.cpp src/core/CPU/cpu_dynarmic.cpp src ) set(KERNEL_SOURCE_FILES src/core/kernel/kernel.cpp src/core/kernel/resource_limits.cpp - src/core/kernel/memory_management.cpp + src/core/kernel/memory_management.cpp src/core/kernel/ports.cpp ) set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp diff --git a/include/cpu_dynarmic.hpp b/include/cpu_dynarmic.hpp index d5b79750..b3903cd5 100644 --- a/include/cpu_dynarmic.hpp +++ b/include/cpu_dynarmic.hpp @@ -130,7 +130,6 @@ public: void runFrame() { env.ticksLeft = 268111856 / 60; const auto exitReason = jit->Run(); - for (u32 i = 0; i < 4; i++)printf("r%d: %08X\n", i, getReg(i)); Helpers::panic("Exit reason: %d\nPC: %08X", (u32)exitReason, getReg(15)); } }; \ No newline at end of file diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index 9af5de5f..68fc4147 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -14,6 +14,7 @@ class Kernel { // The handle number for the next kernel object to be created u32 handleCounter; std::vector objects; + std::vector portHandles; u32 currentProcess; @@ -47,6 +48,10 @@ class Kernel { } Handle makeProcess(); + Handle makePort(const char* name); + std::optional getPortHandle(const char* name); + void deleteObjectData(KernelObject& object); + KernelObject* getProcessFromPID(Handle handle); s32 getCurrentResourceValue(const KernelObject* limit, u32 resourceName); u32 getMaxForResource(const KernelObject* limit, u32 resourceName); @@ -64,6 +69,7 @@ class Kernel { public: Kernel(std::array& regs, Memory& mem) : regs(regs), mem(mem), handleCounter(0) { objects.reserve(512); // Make room for a few objects to avoid further memory allocs later + portHandles.reserve(32); } void serviceSVC(u32 svc); void reset(); diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index 28929e32..9d9216ba 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -5,9 +5,11 @@ namespace SVCResult { enum : u32 { Success = 0, Failure = 0xFFFFFFFF, + ObjectNotFound = 0xD88007FA, // Different calls return a different value BadHandle = 0xD8E007F7, - BadHandleAlt = 0xD9001BF7 + BadHandleAlt = 0xD9001BF7, + PortNameTooLong = 0xE0E0181E }; } @@ -19,7 +21,7 @@ namespace KernelHandles { } enum class KernelObjectType : u8 { - ResourceLimit, Process + Port, Process, ResourceLimit, Session, Dummy }; enum class ResourceLimitCategory : int { @@ -55,10 +57,24 @@ struct ProcessData { ResourceLimits limits; }; +struct PortData { + static constexpr u32 maxNameLen = 11; + + char name[maxNameLen + 1] = {}; + bool isPublic = false; // Setting name=NULL creates a private port not accessible from svcConnectToPort. +}; + +struct SessionData { + +}; + static const char* kernelObjectTypeToString(KernelObjectType t) { switch (t) { + case KernelObjectType::Port: return "port"; case KernelObjectType::Process: return "process"; case KernelObjectType::ResourceLimit: return "resource limit"; + case KernelObjectType::Session: return "session"; + case KernelObjectType::Dummy: return "dummy"; default: return "unknown"; } } diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 65f237aa..2e0a5a18 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -39,18 +39,32 @@ KernelObject* Kernel::getProcessFromPID(Handle handle) { } } +void Kernel::deleteObjectData(KernelObject& object) { + // Resource limit and dummy objects do not allocate heap data, so we don't delete anything + if (object.type == KernelObjectType::ResourceLimit || object.type == KernelObjectType::Dummy) { + return; + } + + if (object.data != nullptr) { + delete object.data; + } +} + void Kernel::reset() { handleCounter = 0; for (auto& object : objects) { - if (object.data != nullptr) { - delete object.data; - } + deleteObjectData(object); } objects.clear(); + portHandles.clear(); - // Make a main process object + // Allocate handle #0 to a dummy object and make a main process object + makeObject(KernelObjectType::Dummy); currentProcess = makeProcess(); + + // Create global service manager port + makePort("srv:"); } // Result CreateAddressArbiter(Handle* arbiter) @@ -65,14 +79,6 @@ void Kernel::svcCloseHandle() { regs[0] = SVCResult::Success; } -void Kernel::connectToPort() { - const u32 handlePointer = regs[0]; - const char* port = static_cast(mem.getReadPointer(regs[1])); - - printf("ConnectToPort(handle pointer = %08X, port = \"%s\")\n", handlePointer, port); - Helpers::panic("Unimplemented IPC"); -} - std::string Kernel::getProcessName(u32 pid) { if (pid == KernelHandles::CurrentProcess) { return "current"; diff --git a/src/core/kernel/ports.cpp b/src/core/kernel/ports.cpp new file mode 100644 index 00000000..4b523d11 --- /dev/null +++ b/src/core/kernel/ports.cpp @@ -0,0 +1,57 @@ +#include "kernel.hpp" +#include + +Handle Kernel::makePort(const char* name) { + Handle ret = makeObject(KernelObjectType::Port); + portHandles.push_back(ret); // Push the port handle to our cache of port handles + + objects[ret].data = new PortData(); + const auto data = static_cast(objects[ret].data); + + // If the name is empty (ie the first char is the null terminator) then the port is private + data->isPublic = name[0] != '\0'; + std::strncpy(data->name, name, PortData::maxNameLen); + + // printf("Created %s port \"%s\" with handle %d\n", data->isPublic ? "public" : "private", data->name, ret); + return ret; +} + +// Get the handle of a port based on its name +// If there's no such port, return nullopt +std::optional Kernel::getPortHandle(const char* name) { + for (auto handle : portHandles) { + const auto data = static_cast(objects[handle].data); + if (std::strncmp(name, data->name, PortData::maxNameLen) == 0) { + return handle; + } + } + + return std::nullopt; +} + +// Result ConnectToPort(Handle* out, const char* portName) +void Kernel::connectToPort() { + const u32 handlePointer = regs[0]; + const char* port = static_cast(mem.getReadPointer(regs[1])); + printf("ConnectToPort(handle pointer = %08X, port = \"%s\")\n", handlePointer, port); + + // TODO: This is unsafe + if (std::strlen(port) > PortData::maxNameLen) { + Helpers::panic("ConnectToPort: Port name too long\n"); + regs[0] = SVCResult::PortNameTooLong; + return; + } + + const auto portHandle = getPortHandle(port); + if (!portHandle.has_value()) { + Helpers::panic("ConnectToPort: Port doesn't exist\n"); + regs[0] = SVCResult::ObjectNotFound; + return; + } + + // TODO: Actually create session + Handle sessionHandle = makeObject(KernelObjectType::Session); + + regs[0] = SVCResult::Success; + regs[1] = sessionHandle; +} \ No newline at end of file diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 964a521a..5b2cc284 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -2,7 +2,6 @@ #include "config_mem.hpp" #include - Memory::Memory() { fcram = new uint8_t[FCRAM_SIZE](); readTable.resize(totalPageCount, 0);