Semaphores v0.1

This commit is contained in:
wheremyfoodat 2022-11-17 22:14:56 +02:00
parent 3c55d88fab
commit 7b8cac8d43
6 changed files with 44 additions and 11 deletions

View file

@ -48,6 +48,7 @@ class Kernel {
public: public:
Handle makeMutex(bool locked = false); // Needs to be public to be accessible to the APT/DSP services 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: private:
void signalArbiter(u32 waitingAddress, s32 threadCount); void signalArbiter(u32 waitingAddress, s32 threadCount);

View file

@ -118,7 +118,7 @@ struct Thread {
u32 waitingAddress; u32 waitingAddress;
// The nanoseconds until a thread wakes up from being asleep or from timing out while waiting on an arbiter // 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 // The tick this thread went to sleep on
u64 sleepTick; u64 sleepTick;
// For WaitSynchronization: A vector of objects this thread is waiting for // For WaitSynchronization: A vector of objects this thread is waiting for
@ -157,6 +157,13 @@ struct Mutex {
Mutex(bool lock = false) : locked(lock) {} 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 // Generic kernel object class
struct KernelObject { struct KernelObject {
Handle handle = 0; // A u32 the OS will use to identify objects Handle handle = 0; // A u32 the OS will use to identify objects

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include "helpers.hpp" #include <optional>
#include "kernel_types.hpp"
#include "logger.hpp" #include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
#include "services/apt.hpp" #include "services/apt.hpp"
@ -15,11 +16,16 @@
#include "services/ndm.hpp" #include "services/ndm.hpp"
#include "services/ptm.hpp" #include "services/ptm.hpp"
// More circular dependencies!!
class Kernel; class Kernel;
class ServiceManager { class ServiceManager {
std::array<u32, 16>& regs; std::array<u32, 16>& regs;
Memory& mem; Memory& mem;
Kernel& kernel;
std::optional<Handle> notificationSemaphore;
MAKE_LOG_FUNCTION(log, srvLogger) MAKE_LOG_FUNCTION(log, srvLogger)
APTService apt; APTService apt;

View file

@ -73,7 +73,7 @@ void Kernel::waitSynchronization1() {
const auto object = getObject(handle); const auto object = getObject(handle);
if (object == nullptr) [[unlikely]] { if (object == nullptr) [[unlikely]] {
Helpers::panic("WaitSynchronization1: Bad event handle"); Helpers::panic("WaitSynchronization1: Bad event handle %X\n", handle);
regs[0] = SVCResult::BadHandle; regs[0] = SVCResult::BadHandle;
return; return;
} }
@ -104,7 +104,7 @@ void Kernel::waitSynchronizationN() {
s32 pointer = regs[5]; s32 pointer = regs[5];
s64 ns = s64(ns1) | (s64(ns2) << 32); 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; ThreadStatus newStatus = waitAll ? ThreadStatus::WaitSyncAll : ThreadStatus::WaitSync1;
auto& t = threads[currentThreadIndex]; auto& t = threads[currentThreadIndex];
@ -118,7 +118,7 @@ void Kernel::waitSynchronizationN() {
auto object = getObject(handle); auto object = getObject(handle);
if (object == nullptr) [[unlikely]] { if (object == nullptr) [[unlikely]] {
Helpers::panic("WaitSynchronizationN: Bad object handle"); Helpers::panic("WaitSynchronizationN: Bad object handle %X\n", handle);
regs[0] = SVCResult::BadHandle; regs[0] = SVCResult::BadHandle;
return; return;
} }
@ -131,5 +131,6 @@ void Kernel::waitSynchronizationN() {
regs[0] = SVCResult::Success; regs[0] = SVCResult::Success;
t.status = newStatus; t.status = newStatus;
t.waitingNanoseconds = ns; t.waitingNanoseconds = ns;
t.sleepTick = cpu.getTicks();
switchToNextThread(); switchToNextThread();
} }

View file

@ -82,7 +82,8 @@ void Kernel::switchToNextThread() {
std::optional<int> newThreadIndex = getNextThread(); std::optional<int> newThreadIndex = getNextThread();
if (!newThreadIndex.has_value()) { 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 { } else {
switchThread(newThreadIndex.value()); switchThread(newThreadIndex.value());
} }
@ -149,6 +150,13 @@ Handle Kernel::makeMutex(bool locked) {
return ret; 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) { void Kernel::sleepThreadOnArbiter(u32 waitingAddress) {
Thread& t = threads[currentThreadIndex]; Thread& t = threads[currentThreadIndex];
t.status = ThreadStatus::WaitArbiter; t.status = ThreadStatus::WaitArbiter;

View file

@ -1,8 +1,11 @@
#include "services/service_manager.hpp" #include "services/service_manager.hpp"
#include "kernel.hpp"
ServiceManager::ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) ServiceManager::ServiceManager(std::array<u32, 16>& 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), : regs(regs), mem(mem), kernel(kernel), apt(mem, kernel), cecd(mem), cfg(mem), dsp(mem), hid(mem),
gsp_lcd(mem), mic(mem), ndm(mem), ptm(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() { void ServiceManager::reset() {
apt.reset(); apt.reset();
@ -16,6 +19,8 @@ void ServiceManager::reset() {
mic.reset(); mic.reset();
ndm.reset(); ndm.reset();
ptm.reset(); ptm.reset();
notificationSemaphore = std::nullopt;
} }
// Match IPC messages to a "srv:" command based on their header // 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) { 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 + 4, Result::Success); // Result code
mem.write32(messagePointer + 8, 0); // Translation descriptor mem.write32(messagePointer + 8, 0); // Translation descriptor
// TODO: Unstub. Handle to semaphore signaled on process notification // Handle to semaphore signaled on process notification
mem.write32(messagePointer + 12, 0x69696979); mem.write32(messagePointer + 12, notificationSemaphore.value());
} }
void ServiceManager::receiveNotification(u32 messagePointer) { void ServiceManager::receiveNotification(u32 messagePointer) {