diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index c602d480..a986271c 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -48,6 +48,7 @@ class Kernel { public: Handle makeMutex(bool locked = false); // Needs to be public to be accessible to the APT/DSP services + Handle makeSemaphore(u32 initialCount, u32 maximumCount); // Needs to be public to be accessible to the service manager port private: void signalArbiter(u32 waitingAddress, s32 threadCount); diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index ab8a1af8..93a1f47d 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -118,7 +118,7 @@ struct Thread { u32 waitingAddress; // The nanoseconds until a thread wakes up from being asleep or from timing out while waiting on an arbiter - s64 waitingNanoseconds; + u64 waitingNanoseconds; // The tick this thread went to sleep on u64 sleepTick; // For WaitSynchronization: A vector of objects this thread is waiting for @@ -157,6 +157,13 @@ struct Mutex { Mutex(bool lock = false) : locked(lock) {} }; +struct Semaphore { + u32 initialCount; + u32 maximumCount; + + Semaphore(u32 initialCount, u32 maximumCount) : initialCount(initialCount), maximumCount(maximumCount) {} +}; + // Generic kernel object class struct KernelObject { Handle handle = 0; // A u32 the OS will use to identify objects diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index 7480df86..d9903372 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -1,6 +1,7 @@ #pragma once #include -#include "helpers.hpp" +#include +#include "kernel_types.hpp" #include "logger.hpp" #include "memory.hpp" #include "services/apt.hpp" @@ -15,11 +16,16 @@ #include "services/ndm.hpp" #include "services/ptm.hpp" +// More circular dependencies!! class Kernel; class ServiceManager { std::array& regs; Memory& mem; + Kernel& kernel; + + std::optional notificationSemaphore; + MAKE_LOG_FUNCTION(log, srvLogger) APTService apt; diff --git a/src/core/kernel/events.cpp b/src/core/kernel/events.cpp index a914865f..c7ab1c92 100644 --- a/src/core/kernel/events.cpp +++ b/src/core/kernel/events.cpp @@ -73,7 +73,7 @@ void Kernel::waitSynchronization1() { const auto object = getObject(handle); if (object == nullptr) [[unlikely]] { - Helpers::panic("WaitSynchronization1: Bad event handle"); + Helpers::panic("WaitSynchronization1: Bad event handle %X\n", handle); regs[0] = SVCResult::BadHandle; return; } @@ -104,7 +104,7 @@ void Kernel::waitSynchronizationN() { s32 pointer = regs[5]; s64 ns = s64(ns1) | (s64(ns2) << 32); - logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d)\n", handles, handleCount); + logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d, timeout = %lld)\n", handles, handleCount, ns); ThreadStatus newStatus = waitAll ? ThreadStatus::WaitSyncAll : ThreadStatus::WaitSync1; auto& t = threads[currentThreadIndex]; @@ -118,7 +118,7 @@ void Kernel::waitSynchronizationN() { auto object = getObject(handle); if (object == nullptr) [[unlikely]] { - Helpers::panic("WaitSynchronizationN: Bad object handle"); + Helpers::panic("WaitSynchronizationN: Bad object handle %X\n", handle); regs[0] = SVCResult::BadHandle; return; } @@ -131,5 +131,6 @@ void Kernel::waitSynchronizationN() { regs[0] = SVCResult::Success; t.status = newStatus; t.waitingNanoseconds = ns; + t.sleepTick = cpu.getTicks(); switchToNextThread(); } \ No newline at end of file diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index ae697e48..99c1acb5 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -82,7 +82,8 @@ void Kernel::switchToNextThread() { std::optional newThreadIndex = getNextThread(); if (!newThreadIndex.has_value()) { - Helpers::panic("Kernel tried to switch to the next thread but none found"); + Helpers::warn("Kernel tried to switch to the next thread but none found. Switching to thread 0\n"); + switchThread(0); } else { switchThread(newThreadIndex.value()); } @@ -149,6 +150,13 @@ Handle Kernel::makeMutex(bool locked) { return ret; } +Handle Kernel::makeSemaphore(u32 initialCount, u32 maximumCount) { + Handle ret = makeObject(KernelObjectType::Semaphore); + objects[ret].data = new Semaphore(initialCount, maximumCount); + + return ret; +} + void Kernel::sleepThreadOnArbiter(u32 waitingAddress) { Thread& t = threads[currentThreadIndex]; t.status = ThreadStatus::WaitArbiter; diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index 3a701852..d27e6ce1 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -1,8 +1,11 @@ #include "services/service_manager.hpp" +#include "kernel.hpp" ServiceManager::ServiceManager(std::array& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) - : regs(regs), mem(mem), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), hid(mem), fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), - gsp_lcd(mem), mic(mem), ndm(mem), ptm(mem) {} + : regs(regs), mem(mem), kernel(kernel), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), hid(mem), + fs(mem, kernel), gsp_gpu(mem, gpu, currentPID), gsp_lcd(mem), mic(mem), ndm(mem), ptm(mem) {} + +static constexpr int MAX_NOTIFICATION_COUNT = 16; void ServiceManager::reset() { apt.reset(); @@ -16,6 +19,8 @@ void ServiceManager::reset() { mic.reset(); ndm.reset(); ptm.reset(); + + notificationSemaphore = std::nullopt; } // Match IPC messages to a "srv:" command based on their header @@ -109,12 +114,17 @@ void ServiceManager::getServiceHandle(u32 messagePointer) { } void ServiceManager::enableNotification(u32 messagePointer) { - log("srv::EnableNotification() (STUBBED)\n"); + log("srv::EnableNotification()\n"); + + // Make a semaphore for notifications if none exists currently + if (!notificationSemaphore.has_value() || kernel.getObject(notificationSemaphore.value(), KernelObjectType::Semaphore) == nullptr) { + notificationSemaphore = kernel.makeSemaphore(0, MAX_NOTIFICATION_COUNT); + } mem.write32(messagePointer + 4, Result::Success); // Result code mem.write32(messagePointer + 8, 0); // Translation descriptor - // TODO: Unstub. Handle to semaphore signaled on process notification - mem.write32(messagePointer + 12, 0x69696979); + // Handle to semaphore signaled on process notification + mem.write32(messagePointer + 12, notificationSemaphore.value()); } void ServiceManager::receiveNotification(u32 messagePointer) {