mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 22:55:40 +12:00
Semaphores v0.1
This commit is contained in:
parent
3c55d88fab
commit
7b8cac8d43
6 changed files with 44 additions and 11 deletions
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue