From 1c4348248dbbf7d15093f6fbad95299488096970 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Mon, 19 Sep 2022 16:29:50 +0300 Subject: [PATCH] [Kernel] CreateThread stub --- include/dynarmic_cp15.hpp | 6 +++++- include/kernel/kernel.hpp | 6 +++++- include/kernel/kernel_types.hpp | 7 +++++-- src/core/kernel/kernel.cpp | 5 +++++ src/core/kernel/threads.cpp | 33 +++++++++++++++++++++++++++++++++ src/core/services/gsp_gpu.cpp | 4 ++-- src/emulator.cpp | 2 ++ src/main.cpp | 2 +- 8 files changed, 58 insertions(+), 7 deletions(-) diff --git a/include/dynarmic_cp15.hpp b/include/dynarmic_cp15.hpp index e349dd16..9f9f47b2 100644 --- a/include/dynarmic_cp15.hpp +++ b/include/dynarmic_cp15.hpp @@ -23,8 +23,12 @@ class CP15 final : public Dynarmic::A32::Coprocessor { CallbackOrAccessOneWord CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override { + if (!two && opc1 == 0 && CRn == CoprocReg::C7 && CRm == CoprocReg::C10 && opc2 == 4) { + return &dummy; // Normally inserts a "Data Synchronization Barrier" + } + if (!two && opc1 == 0 && CRn == CoprocReg::C7 && CRm == CoprocReg::C10 && opc2 == 5) { - return &dummy; // TODO: Find out what this is. Some sort of memory barrier reg. + return &dummy; // Normally inserts a "Data Memory Barrier" } Helpers::panic("CP15: CompileSendOneWord\nopc1: %d CRn: %d CRm: %d opc2: %d\n", opc1, (int)CRn, (int)CRm, opc2); } diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index 1461af74..fdd9c719 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -17,7 +17,9 @@ class Kernel { std::vector objects; std::vector portHandles; - u32 currentProcess; + Handle currentProcess; + Handle currentThread; + u32 threadCount; ServiceManager serviceManager; // Get pointer to the object with the specified handle @@ -53,6 +55,7 @@ class Kernel { Handle makeProcess(); Handle makePort(const char* name); Handle makeSession(Handle port); + Handle makeThread(u32 entrypoint, u32 initialSP, u32 priority, u32 id); std::optional getPortHandle(const char* name); void deleteObjectData(KernelObject& object); @@ -68,6 +71,7 @@ class Kernel { // SVC implementations void createAddressArbiter(); void createEvent(); + void createThread(); void controlMemory(); void mapMemoryBlock(); void queryMemory(); diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index d4859eab..e1503b5d 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -10,12 +10,14 @@ namespace SVCResult { // Different calls return a different value BadHandle = 0xD8E007F7, BadHandleAlt = 0xD9001BF7, - PortNameTooLong = 0xE0E0181E + + BadThreadPriority = 0xE0E01BFD, + PortNameTooLong = 0xE0E0181E, }; } enum class KernelObjectType : u8 { - Event, Port, Process, ResourceLimit, Session, Dummy + Event, Port, Process, ResourceLimit, Session, Thread, Dummy }; enum class ResourceLimitCategory : int { @@ -84,6 +86,7 @@ static const char* kernelObjectTypeToString(KernelObjectType t) { case KernelObjectType::Process: return "process"; case KernelObjectType::ResourceLimit: return "resource limit"; case KernelObjectType::Session: return "session"; + case KernelObjectType::Thread: return "thread"; case KernelObjectType::Dummy: return "dummy"; default: return "unknown"; } diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 81a53edc..b831da6b 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -6,6 +6,7 @@ void Kernel::serviceSVC(u32 svc) { switch (svc) { case 0x01: controlMemory(); break; case 0x02: queryMemory(); break; + case 0x08: createThread(); break; case 0x17: createEvent(); break; case 0x1F: mapMemoryBlock(); break; case 0x21: createAddressArbiter(); break; @@ -57,6 +58,7 @@ void Kernel::deleteObjectData(KernelObject& object) { void Kernel::reset() { handleCounter = 0; + threadCount = 0; for (auto& object : objects) { deleteObjectData(object); @@ -68,6 +70,9 @@ void Kernel::reset() { // Allocate handle #0 to a dummy object and make a main process object makeObject(KernelObjectType::Dummy); currentProcess = makeProcess(); + // 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 + currentThread = makeThread(0, 0, 0x30, 0); // Create global service manager port makePort("srv:"); diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index e69de29b..57e422f2 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -0,0 +1,33 @@ +#include "kernel.hpp" +#include "resource_limits.hpp" + +// Internal OS function to spawn a thread +Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, u32 id) { + if (threadCount >= appResourceLimits.maxThreads) { + Helpers::panic("Overflowed the number of threads"); + } + threadCount++; + + // TODO: Actually create the thread + return makeObject(KernelObjectType::Thread); +} + +// Result CreateThread(s32 priority, ThreadFunc entrypoint, u32 arg, u32 stacktop, s32 threadPriority, s32 processorID) +void Kernel::createThread() { + u32 priority = regs[0]; + u32 entrypoint = regs[1]; + u32 initialSP = regs[3] & ~7; // SP is force-aligned to 8 bytes + u32 id = regs[4]; + + printf("CreateThread(entry = %08X, stacktop = %08X, priority = %X, processor ID = %d)\n", entrypoint, + initialSP, priority, id); + + if (!(priority <= 0x3F)) [[unlikely]] { + Helpers::panic("Created thread with bad priority value %X", priority); + regs[0] = SVCResult::BadThreadPriority; + return; + } + + regs[0] = SVCResult::Success; + regs[1] = makeThread(entrypoint, initialSP, priority, id); +} \ No newline at end of file diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 3d7caf46..535af09c 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -58,9 +58,9 @@ void GPUService::registerInterruptRelayQueue(u32 messagePointer) { printf("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle); mem.write32(messagePointer + 4, Result::SuccessRegisterIRQ); - mem.write32(messagePointer + 8, 79797979); // TODO: GSP module thread index + mem.write32(messagePointer + 8, 0); // TODO: GSP module thread index mem.write32(messagePointer + 12, 0); // Translation descriptor - mem.write32(messagePointer + 16, KernelHandles::GSPSharedMemHandle); // TODO: GSP shared memory handle + mem.write32(messagePointer + 16, KernelHandles::GSPSharedMemHandle); } void GPUService::writeHwRegs(u32 messagePointer) { diff --git a/src/emulator.cpp b/src/emulator.cpp index bc343fef..8eb36ba1 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -5,6 +5,8 @@ void Emulator::reset() { cpu.reset(); kernel.reset(); + // Reloading r13 and r15 needs to happen after everything has been reset + // Otherwise resetting the kernel or cpu might nuke them cpu.setReg(13, VirtualAddrs::StackTop); // Set initial SP if (romType == ROMType::ELF) { // Reload ELF if we're using one loadELF(loadedROM); diff --git a/src/main.cpp b/src/main.cpp index 668be366..c1934ff3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,7 @@ int main (int argc, char *argv[]) { Helpers::panic("Failed to initialize OpenGL"); } - auto elfPath = std::filesystem::current_path() / (argc > 1 ? argv[1] : "sm64.elf"); + auto elfPath = std::filesystem::current_path() / (argc > 1 ? argv[1] : "SimplerTri.elf"); if (!emu.loadELF(elfPath)) { Helpers::panic("Failed to load ELF file: %s", elfPath.c_str()); }