diff --git a/CMakeLists.txt b/CMakeLists.txt index 3810bf5b..e6459bba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,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/ports.cpp src/core/kernel/events.cpp src/core/kernel/threads.cpp - src/core/kernel/address_arbiter.cpp + src/core/kernel/address_arbiter.cpp src/core/kernel/error.cpp ) set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services/apt.cpp src/core/services/hid.cpp src/core/services/fs.cpp src/core/services/gsp_gpu.cpp src/core/services/gsp_lcd.cpp diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index 391406ef..22ee4cb5 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -27,6 +27,8 @@ class Kernel { Handle mainThread; int currentThreadIndex; Handle srvHandle; // Handle for the special service manager port "srv:" + Handle errorPortHandle; // Handle for the err:f port used for displaying errors + u32 arbiterCount; u32 threadCount; ServiceManager serviceManager; @@ -65,7 +67,7 @@ class Kernel { Handle makeArbiter(); Handle makeEvent(ResetType resetType); - Handle makeProcess(); + Handle makeProcess(u32 id); Handle makePort(const char* name); Handle makeSession(Handle port); Handle makeThread(u32 entrypoint, u32 initialSP, u32 priority, s32 id, u32 arg,ThreadStatus status = ThreadStatus::Dormant); @@ -81,12 +83,17 @@ class Kernel { u32 getMaxForResource(const KernelObject* limit, u32 resourceName); u32 getTLSPointer(); + // Functions for the err:f port + void handleErrorSyncRequest(u32 messagePointer); + void throwError(u32 messagePointer); + std::string getProcessName(u32 pid); const char* resetTypeToString(u32 type); MAKE_LOG_FUNCTION(log, kernelLogger) MAKE_LOG_FUNCTION(logSVC, svcLogger) MAKE_LOG_FUNCTION(logDebugString, debugStringLogger) + MAKE_LOG_FUNCTION(logError, errorLogger) // SVC implementations void arbitrateAddress(); @@ -98,6 +105,7 @@ class Kernel { void duplicateHandle(); void mapMemoryBlock(); void queryMemory(); + void getProcessID(); void getProcessInfo(); void getResourceLimit(); void getResourceLimitLimitValues(); diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index debd0d36..3dcf8590 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -61,6 +61,10 @@ struct ResourceLimits { struct Process { // Resource limits for this process ResourceLimits limits; + // Process ID + u32 id; + + Process(u32 id) : id(id) {} }; struct Event { diff --git a/src/core/kernel/error.cpp b/src/core/kernel/error.cpp new file mode 100644 index 00000000..43ca89f4 --- /dev/null +++ b/src/core/kernel/error.cpp @@ -0,0 +1,45 @@ +#include "kernel.hpp" + +namespace Commands { + enum : u32 { + Throw = 0x00010800 + }; +} + +namespace FatalErrorType { + enum : u32 { + Generic = 0, + Corrupted = 1, + CardRemoved = 2, + Exception = 3, + ResultFailure = 4, + Logged = 5 + }; +} + +// Handle SendSyncRequest targetting the err:f port +void Kernel::handleErrorSyncRequest(u32 messagePointer) { + u32 cmd = mem.read32(messagePointer); + switch (cmd) { + case Commands::Throw: throwError(messagePointer); break; + + default: + Helpers::panic("Unimplemented err:f command %08X\n", cmd); + break; + } +} + +void Kernel::throwError(u32 messagePointer) { + const auto type = mem.read8(messagePointer + 4); // Fatal error type + const u32 pc = mem.read32(messagePointer + 12); + const u32 pid = mem.read32(messagePointer + 16); + logError("Thrown fatal error @ %08X (pid = %X, type = %d)\n", pc, pid, type); + + // Read the error message if type == 4 + if (type == FatalErrorType::ResultFailure) { + const auto error = mem.readString(messagePointer + 0x24, 0x60); + logError("ERROR: %s\n", error.c_str()); + } + + Helpers::panic("Thrown fatal error"); +} \ No newline at end of file diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 1de07e9c..0664f58e 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -34,6 +34,7 @@ void Kernel::serviceSVC(u32 svc) { case 0x2B: getProcessInfo(); break; case 0x2D: connectToPort(); break; case 0x32: sendSyncRequest(); break; + case 0x35: getProcessID(); break; case 0x37: getThreadID(); break; case 0x38: getResourceLimit(); break; case 0x39: getResourceLimitLimitValues(); break; @@ -50,12 +51,12 @@ void Kernel::setVersion(u8 major, u8 minor) { mem.kernelVersion = descriptor; // The memory objects needs a copy because you can read the kernel ver from config mem } -Handle Kernel::makeProcess() { +Handle Kernel::makeProcess(u32 id) { const Handle processHandle = makeObject(KernelObjectType::Process); const Handle resourceLimitHandle = makeObject(KernelObjectType::ResourceLimit); // Allocate data - objects[processHandle].data = new Process(); + objects[processHandle].data = new Process(id); const auto processData = objects[processHandle].getData(); // Link resource limit object with its parent process @@ -99,7 +100,7 @@ void Kernel::reset() { // Allocate handle #0 to a dummy object and make a main process object makeObject(KernelObjectType::Dummy); - currentProcess = makeProcess(); + currentProcess = makeProcess(1); // Use ID = 1 for main process // Make main thread object. We do not have to set the entrypoint and SP for it as the ROM loader does. // Main thread seems to have a priority of 0x30. TODO: This creates a dummy context for thread 0, @@ -107,8 +108,9 @@ void Kernel::reset() { mainThread = makeThread(0, VirtualAddrs::StackTop, 0x30, -2, 0, ThreadStatus::Running); currentThreadIndex = 0; - // Create global service manager port - srvHandle = makePort("srv:"); + // Create some of the OS ports + srvHandle = makePort("srv:"); // Service manager port + errorPortHandle = makePort("err:f"); // Error display port } // Get pointer to thread-local storage @@ -142,6 +144,20 @@ void Kernel::outputDebugString() { regs[0] = SVCResult::Success; } +void Kernel::getProcessID() { + const auto pid = regs[1]; + const auto process = getProcessFromPID(pid); + logSVC("GetProcessID(process: %s)\n", getProcessName(pid).c_str()); + + if (process == nullptr) [[unlikely]] { + regs[0] = SVCResult::BadHandle; + return; + } + + regs[0] = SVCResult::Success; + regs[1] = process->getData()->id; +} + // Result GetProcessInfo(s64* out, Handle process, ProcessInfoType type) void Kernel::getProcessInfo() { const auto pid = regs[1]; diff --git a/src/core/kernel/ports.cpp b/src/core/kernel/ports.cpp index 0bcb272c..c2de8d71 100644 --- a/src/core/kernel/ports.cpp +++ b/src/core/kernel/ports.cpp @@ -39,6 +39,7 @@ void Kernel::connectToPort() { const u32 handlePointer = regs[0]; // Read up to max + 1 characters to see if the name is too long std::string port = mem.readString(regs[1], Port::maxNameLen + 1); + logSVC("ConnectToPort(handle pointer = %X, port = \"%s\")\n", handlePointer, port.c_str()); if (port.size() > Port::maxNameLen) { Helpers::panic("ConnectToPort: Port name too long\n"); @@ -55,7 +56,6 @@ void Kernel::connectToPort() { } Handle portHandle = optionalHandle.value(); - logSVC("ConnectToPort(handle pointer = %X, port = \"%s\")\n", handlePointer, port.c_str()); const auto portData = objects[portHandle].getData(); if (!portData->isPublic) { @@ -96,6 +96,8 @@ void Kernel::sendSyncRequest() { if (portHandle == srvHandle) { // Special-case SendSyncRequest targetting the "srv: port" serviceManager.handleSyncRequest(messagePointer); + } else if (portHandle == errorPortHandle) { // Special-case "err:f" for juicy logs too + handleErrorSyncRequest(messagePointer); } else { const auto portData = objects[portHandle].getData(); Helpers::panic("SendSyncRequest targetting port %s\n", portData->name); diff --git a/src/core/services/fs.cpp b/src/core/services/fs.cpp index 524815aa..44c6c228 100644 --- a/src/core/services/fs.cpp +++ b/src/core/services/fs.cpp @@ -28,8 +28,8 @@ void FSService::handleSyncRequest(u32 messagePointer) { } void FSService::initialize(u32 messagePointer) { - log("FS::Initialize (failure)\n"); - mem.write32(messagePointer + 4, Result::Failure); + log("FS::Initialize\n"); + mem.write32(messagePointer + 4, Result::Success); } void FSService::openArchive(u32 messagePointer) { @@ -40,12 +40,17 @@ void FSService::openArchive(u32 messagePointer) { void FSService::openFileDirectly(u32 messagePointer) { const u32 archiveID = mem.read32(messagePointer + 8); const u32 archivePathType = mem.read32(messagePointer + 12); + const u32 archivePathSize = mem.read32(messagePointer + 16); const u32 filePathType = mem.read32(messagePointer + 20); + const u32 filePathSize = mem.read32(messagePointer + 24); + const u32 openFlags = mem.read32(messagePointer + 28); + const u32 attributes = mem.read32(messagePointer + 32); const u32 archivePathPointer = mem.read32(messagePointer + 40); const u32 filePathPointer = mem.read32(messagePointer + 48); log("FS::OpenFileDirectly (failure)\n"); - mem.write32(messagePointer + 4, Result::Failure); - Helpers::panic("[FS::OpenFileDirectly] Tried to open file. Archive ID = %d\n", archiveID); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 12, 69); + //Helpers::panic("[FS::OpenFileDirectly] Tried to open file. Archive ID = %d\n", archiveID); } \ No newline at end of file