diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index d9b01aee..05f614fd 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -90,6 +90,7 @@ class Kernel { void createEvent(); void createThread(); void controlMemory(); + void duplicateHandle(); void mapMemoryBlock(); void queryMemory(); void getProcessInfo(); @@ -97,6 +98,7 @@ class Kernel { void getResourceLimitLimitValues(); void getResourceLimitCurrentValues(); void getSystemTick(); + void getThreadID(); void sendSyncRequest(); void svcCloseHandle(); void connectToPort(); diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index b772bed9..debd0d36 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -102,9 +102,11 @@ struct Thread { u32 initialSP; // Initial r13 value u32 entrypoint; // Initial r15 value u32 priority; + u32 arg; s32 processorID; ThreadStatus status; Handle handle; // OS handle for this thread + int index; // Index of the thread. 0 for the first thread, 1 for the second, and so on // The waiting address for threads that are waiting on an AddressArbiter u32 waitingAddress; diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 1a475c73..a3cf16f9 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -9,6 +9,7 @@ Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu) portHandles.reserve(32); for (int i = 0; i < threads.size(); i++) { + threads[i].index = i; threads[i].tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize; threads[i].status = ThreadStatus::Dead; } @@ -28,10 +29,12 @@ void Kernel::serviceSVC(u32 svc) { case 0x22: arbitrateAddress(); break; case 0x23: svcCloseHandle(); break; case 0x24: waitSynchronization1(); break; + case 0x27: duplicateHandle(); break; case 0x28: getSystemTick(); break; case 0x2B: getProcessInfo(); break; case 0x2D: connectToPort(); break; case 0x32: sendSyncRequest(); break; + case 0x37: getThreadID(); break; case 0x38: getResourceLimit(); break; case 0x39: getResourceLimitLimitValues(); break; case 0x3A: getResourceLimitCurrentValues(); break; @@ -101,7 +104,7 @@ void Kernel::reset() { // 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, // which is thankfully not used. Maybe we should prevent this - mainThread = makeThread(0, 0, 0x30, -2, 0, ThreadStatus::Running); + mainThread = makeThread(0, VirtualAddrs::StackTop, 0x30, -2, 0, ThreadStatus::Running); currentThreadIndex = 0; // Create global service manager port @@ -139,6 +142,7 @@ void Kernel::outputDebugString() { regs[0] = SVCResult::Success; } +// Result GetProcessInfo(s64* out, Handle process, ProcessInfoType type) void Kernel::getProcessInfo() { const auto pid = regs[1]; const auto type = regs[2]; @@ -163,6 +167,21 @@ void Kernel::getProcessInfo() { regs[0] = SVCResult::Success; } +// Result GetThreadId(u32* threadId, Handle thread) +void Kernel::duplicateHandle() { + Handle original = regs[1]; + printf("DuplicateHandle(handle = %X)\n", original); + + if (original == KernelHandles::CurrentThread) { + printf("[Warning] Duplicated current thread. This might be horribly broken!\n"); + const auto& t = threads[currentThreadIndex]; + regs[0] = SVCResult::Success; + regs[1] = makeThread(t.entrypoint, t.initialSP, t.priority, t.processorID, t.arg, t.status); + } else { + Helpers::panic("DuplicateHandle: unimplemented handle type"); + } +} + std::string Kernel::getProcessName(u32 pid) { if (pid == KernelHandles::CurrentProcess) { return "current"; diff --git a/src/core/kernel/memory_management.cpp b/src/core/kernel/memory_management.cpp index 7c986187..1db536b6 100644 --- a/src/core/kernel/memory_management.cpp +++ b/src/core/kernel/memory_management.cpp @@ -70,16 +70,11 @@ void Kernel::controlMemory() { } // Result QueryMemory(MemoryInfo* memInfo, PageInfo* pageInfo, u32 addr) -// TODO: Is this SVC supposed to write to memory or...? void Kernel::queryMemory() { const u32 memInfo = regs[0]; const u32 pageInfo = regs[1]; const u32 addr = regs[2]; - if (!isAligned(addr)) [[unlikely]] { - Helpers::panic("QueryMemory: Address not page aligned\n"); - } - printf("QueryMemory(mem info pointer = %08X, page info pointer = %08X, addr = %08X)\n", memInfo, pageInfo, addr); const auto info = mem.queryMemory(addr); diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index 837898b0..812b06a1 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -46,6 +46,7 @@ Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, s32 id, u t.gprs.fill(0); t.fprs.fill(0); + t.arg = arg; t.initialSP = initialSP; t.entrypoint = entrypoint; @@ -93,4 +94,25 @@ void Kernel::sleepThreadOnArbiter(u32 waitingAddress) { t.status = ThreadStatus::WaitArbiter; t.waitingAddress = waitingAddress; switchThread(1); // TODO: Properly change threads +} + + +void Kernel::getThreadID() { + Handle handle = regs[1]; + printf("GetThreadID(handle = %X)\n", handle); + + if (handle == KernelHandles::CurrentThread) { + regs[0] = SVCResult::Success; + regs[1] = currentThreadIndex; + return; + } + + const auto thread = getObject(handle, KernelObjectType::Thread); + if (thread == nullptr) [[unlikely]] { + regs[0] = SVCResult::BadHandle; + return; + } + + regs[0] = SVCResult::Success; + regs[1] = thread->getData()->index; } \ No newline at end of file