From 6154a360c6a38d71d384ffa65920be97cf578bc1 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Sun, 18 Sep 2022 00:21:32 +0300 Subject: [PATCH] Hopefully we're good to start sending commands to services now --- CMakeLists.txt | 5 ++-- include/kernel/handles.hpp | 31 ++++++++++++++++++++ include/kernel/kernel.hpp | 3 +- include/kernel/kernel_types.hpp | 10 +------ include/services/apt.hpp | 11 +++++++ include/services/service_manager.hpp | 8 +++++- src/core/kernel/kernel.cpp | 10 +++---- src/core/kernel/ports.cpp | 16 +++++++++-- src/core/services/apt.cpp | 7 +++++ src/core/services/service_manager.cpp | 41 ++++++++++++++++++++------- 10 files changed, 110 insertions(+), 32 deletions(-) create mode 100644 include/kernel/handles.hpp create mode 100644 include/services/apt.hpp create mode 100644 src/core/services/apt.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fd32e59b..ef5e03e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,12 +48,13 @@ 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/ports.cpp ) -set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp) +set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services/apt.cpp) set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp include/termcolor.hpp include/cpu.hpp include/cpu_dynarmic.hpp include/memory.hpp include/kernel/kernel.hpp include/dynarmic_cp15.hpp include/kernel/resource_limits.hpp include/kernel/kernel_types.hpp - include/kernel/config_mem.hpp include/services/service_manager.hpp + include/kernel/config_mem.hpp include/services/service_manager.hpp include/services/apt.hpp + include/kernel/handles.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp new file mode 100644 index 00000000..38adb99f --- /dev/null +++ b/include/kernel/handles.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "helpers.hpp" + +using Handle = u32; + +namespace KernelHandles { + enum : u32 { + Max = 0xFFFF7FFF, // Max handle the kernel can automagically allocate + + // Hardcoded handles + CurrentThread = 0xFFFF8000, // Used by the original kernel + CurrentProcess = 0xFFFF8001, // Used by the original kernel + APT = 0xFFFF8002, // App Title something service? + + MinServiceHandle = APT, + MaxServiceHandle = APT + }; + + // Returns whether "handle" belongs to one of the OS services + static constexpr bool isServiceHandle(Handle handle) { + return handle >= MinServiceHandle && handle <= MaxServiceHandle; + } + + // Returns the name of a handle as a string based on the given handle + static const char* getServiceName(Handle handle) { + switch (handle) { + case APT: return "APT"; + default: return "Unknown"; + } + } +} \ No newline at end of file diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index 1e0fda80..dcdc7e38 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -40,7 +40,7 @@ class Kernel { } Handle makeObject(KernelObjectType type) { - if (handleCounter == std::numeric_limits::max()) [[unlikely]] { + if (handleCounter > KernelHandles::Max) [[unlikely]] { Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing"); } @@ -52,6 +52,7 @@ class Kernel { Handle makeProcess(); Handle makePort(const char* name); Handle makeSession(Handle port); + std::optional getPortHandle(const char* name); void deleteObjectData(KernelObject& object); diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index a6a379a8..11aa415d 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -1,4 +1,5 @@ #pragma once +#include "handles.hpp" #include "helpers.hpp" namespace SVCResult { @@ -13,13 +14,6 @@ namespace SVCResult { }; } -namespace KernelHandles { - enum : u32 { - CurrentThread = 0xFFFF8000, - CurrentProcess = 0xFFFF8001 - }; -} - enum class KernelObjectType : u8 { Port, Process, ResourceLimit, Session, Dummy }; @@ -44,8 +38,6 @@ enum ResourceTypes { CPU_TIME = 9 }; -using Handle = u32; - struct ResourceLimits { Handle handle; diff --git a/include/services/apt.hpp b/include/services/apt.hpp new file mode 100644 index 00000000..1b570b07 --- /dev/null +++ b/include/services/apt.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "helpers.hpp" +#include "kernel_types.hpp" + +class APTService { + Handle handle = KernelHandles::APT; + +public: + void reset(); + void handleSyncRequest(u32 messagePointer); +}; \ No newline at end of file diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index fee0bf03..7a2a90e6 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -2,11 +2,14 @@ #include #include "helpers.hpp" #include "memory.hpp" +#include "services/apt.hpp" class ServiceManager { std::array& regs; Memory& mem; + APTService apt; + // "srv:" commands void getServiceHandle(u32 messagePointer); void registerClient(u32 messagePointer); @@ -14,5 +17,8 @@ class ServiceManager { public: ServiceManager(std::array& regs, Memory& mem); void reset(); - void handleSyncRequest(u32 TLSPointer); + void handleSyncRequest(u32 messagePointer); + + // Forward a SendSyncRequest IPC message to the service with the respective handle + void sendCommandToService(u32 messagePointer, Handle handle); }; \ No newline at end of file diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 4bb486b2..3b941ad0 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -41,14 +41,14 @@ 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) { + using enum KernelObjectType; + + // Resource limit, service and dummy objects do not allocate heap data, so we don't delete anything + if (object.data == nullptr || object.type == ResourceLimit || object.type == Dummy) { return; } - if (object.data != nullptr) { - delete object.data; - } + delete object.data; } void Kernel::reset() { diff --git a/src/core/kernel/ports.cpp b/src/core/kernel/ports.cpp index cb975ab2..9f5bea3f 100644 --- a/src/core/kernel/ports.cpp +++ b/src/core/kernel/ports.cpp @@ -91,11 +91,21 @@ void Kernel::connectToPort() { } // Result SendSyncRequest(Handle session) +// Send an IPC message to a port (typically "srv:") or a service void Kernel::sendSyncRequest() { const auto handle = regs[0]; - const auto session = getObject(handle, KernelObjectType::Session); - printf("SendSyncRequest(session handle = %d)\n", handle); + u32 messagePointer = getTLSPointer() + 0x80; // The message is stored starting at TLS+0x80 + printf("SendSyncRequest(session handle = %X)\n", handle); + + // The sync request is being sent at a service rather than whatever port, so have the service manager intercept it + if (KernelHandles::isServiceHandle(handle)) { + serviceManager.sendCommandToService(messagePointer, handle); + regs[0] = SVCResult::Success; + return; + } + + const auto session = getObject(handle, KernelObjectType::Session); if (session == nullptr) [[unlikely]] { Helpers::panic("SendSyncRequest: Invalid session handle"); regs[0] = SVCResult::BadHandle; @@ -107,7 +117,7 @@ void Kernel::sendSyncRequest() { const auto portData = static_cast(port.data); if (portData->type == PortType::ServiceManager) { // Special-case SendSyncRequest targetting "srv:" - serviceManager.handleSyncRequest(getTLSPointer()); + serviceManager.handleSyncRequest(messagePointer); } else { Helpers::panic("SendSyncRequest targetting port %s\n", portData->name); } diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp new file mode 100644 index 00000000..6ecefdf0 --- /dev/null +++ b/src/core/services/apt.cpp @@ -0,0 +1,7 @@ +#include "services/apt.hpp" + +void APTService::reset() {} + +void APTService::handleSyncRequest(u32 messagePointer) { + Helpers::panic("APT service requested"); +} \ No newline at end of file diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 9a106a35..0504f544 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -3,7 +3,7 @@ ServiceManager::ServiceManager(std::array& regs, Memory& mem) : regs(regs), mem(mem) {} void ServiceManager::reset() { - + apt.reset(); } // Match IPC messages to a "srv:" command based on their header @@ -26,12 +26,16 @@ namespace Commands { }; } +namespace Result { + enum : u32 { + Success = 0 + }; +} + // Handle an IPC message issued using the SendSyncRequest SVC // The parameters are stored in thread-local storage in this format: https://www.3dbrew.org/wiki/IPC#Message_Structure -// TLSPointer: The base pointer for this thread's thread-local storage -void ServiceManager::handleSyncRequest(u32 TLSPointer) { - // The message is stored at TLS+0x80 in this format: https://www.3dbrew.org/wiki/IPC#Message_Structure - const u32 messagePointer = TLSPointer + 0x80; +// messagePointer: The base pointer for the IPC message +void ServiceManager::handleSyncRequest(u32 messagePointer) { const u32 header = mem.read32(messagePointer); switch (header) { @@ -41,19 +45,34 @@ void ServiceManager::handleSyncRequest(u32 TLSPointer) { } } +// https://www.3dbrew.org/wiki/SRV:RegisterClient void ServiceManager::registerClient(u32 messagePointer) { printf("srv: registerClient (Stubbed)\n"); + mem.write32(messagePointer + 4, Result::Success); } +// https://www.3dbrew.org/wiki/SRV:GetServiceHandle void ServiceManager::getServiceHandle(u32 messagePointer) { - printf("srv: getServiceHandle\n"); + u32 nameLength = mem.read32(messagePointer + 12); + u32 flags = mem.read32(messagePointer + 16); + u32 handle = 0; - std::string myBalls; - myBalls.resize(8); + std::string service = mem.readString(messagePointer + 4, 8); + printf("srv: getServiceHandle (Service: %s, nameLength: %d, flags: %d)\n", service.c_str(), nameLength, flags); - for (int i = 0; i < 8; i++) { - myBalls[i] = mem.read8(messagePointer + 4 + i); + if (service == "APT:S") { + handle = KernelHandles::APT; + } else { + Helpers::panic("srv: GetServiceHandle with unknown service %s", service.c_str()); } - std::cout << "Requested handle for service " << myBalls << "\n"; + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 12, handle); +} + +void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { + switch (handle) { + case KernelHandles::APT: apt.handleSyncRequest(messagePointer); break; + default: Helpers::panic("Sent IPC message to unknown service %08X\n", handle); + } } \ No newline at end of file