diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index 9fedd161..8e924c4d 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -61,7 +61,7 @@ class Kernel { 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); + Handle makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg,ThreadStatus status = ThreadStatus::Dormant); Handle makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission); public: @@ -126,6 +126,7 @@ private: void exitThread(); void mapMemoryBlock(); void queryMemory(); + void getCurrentProcessorNumber(); void getProcessID(); void getProcessInfo(); void getResourceLimit(); diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index 56bed359..6f32bad4 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -34,6 +34,16 @@ enum class ArbitrationType { DecrementAndWaitIfLessTimeout = 4 }; +enum class ProcessorID : s32 { + AllCPUs = -1, + Default = -2, + + AppCore = 0, + Syscore = 1, + New3DSExtra1 = 2, + New3DSExtra2 = 3 +}; + struct AddressArbiter {}; struct ResourceLimits { @@ -95,7 +105,7 @@ struct Thread { u32 entrypoint; // Initial r15 value u32 priority; u32 arg; - s32 processorID; + ProcessorID 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 diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 837d20dd..677a0d5f 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -35,6 +35,7 @@ void Kernel::serviceSVC(u32 svc) { case 0x0A: svcSleepThread(); break; case 0x0B: getThreadPriority(); break; case 0x0C: setThreadPriority(); break; + case 0x11: getCurrentProcessorNumber(); break; case 0x13: svcCreateMutex(); break; case 0x14: svcReleaseMutex(); break; case 0x15: svcCreateSemaphore(); break; @@ -158,7 +159,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, VirtualAddrs::StackTop, 0x30, -2, 0, ThreadStatus::Running); + mainThread = makeThread(0, VirtualAddrs::StackTop, 0x30, ProcessorID::Default, 0, ThreadStatus::Running); currentThreadIndex = 0; setupIdleThread(); diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index 440045d3..2f6a27b9 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -106,7 +106,7 @@ void Kernel::rescheduleThreads() { } // Internal OS function to spawn a thread -Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, s32 id, u32 arg, ThreadStatus status) { +Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg, ThreadStatus status) { int index; // Index of the created thread in the threads array if (threadCount < appResourceLimits.maxThreads) [[likely]] { // If we have not yet created over too many threads @@ -389,8 +389,12 @@ void Kernel::createThread() { return; } + if (id < -2 || id > 3) { + Helpers::panic("Invalid processor ID in CreateThread"); + } + regs[0] = Result::Success; - regs[1] = makeThread(entrypoint, initialSP, priority, id, arg, ThreadStatus::Ready); + regs[1] = makeThread(entrypoint, initialSP, priority, static_cast(id), arg, ThreadStatus::Ready); requireReschedule(); } @@ -468,6 +472,32 @@ void Kernel::setThreadPriority() { requireReschedule(); } +void Kernel::getCurrentProcessorNumber() { + const ProcessorID id = threads[currentThreadIndex].processorID; + s32 ret; + + // Until we properly implement per-core schedulers, return whatever processor ID passed to svcCreateThread + switch (id) { + // TODO: This is picked from exheader + case ProcessorID::Default: + ret = static_cast(ProcessorID::AppCore); + break; + + case ProcessorID::AllCPUs: + ret = static_cast(ProcessorID::AppCore); + Helpers::warn("GetCurrentProcessorNumber on thread created to run on all CPUs...?\n"); + break; + + default: ret = static_cast(id); break; + } + + if (ret != static_cast(ProcessorID::AppCore)) { + Helpers::warn("GetCurrentProcessorNumber: Thread not running on appcore\n"); + } + + regs[0] = static_cast(ret); +} + void Kernel::exitThread() { logSVC("ExitThread\n");