Files

253 lines
8.3 KiB
C++
Raw Permalink Normal View History

2022-09-16 03:16:38 +03:00
#pragma once
#include <array>
2023-04-18 20:42:17 +03:00
#include <cassert>
2022-09-16 03:16:38 +03:00
#include <limits>
#include <span>
2022-09-16 03:16:38 +03:00
#include <string>
#include <vector>
2023-08-18 22:17:33 +03:00
#include "config.hpp"
2022-09-16 03:16:38 +03:00
#include "helpers.hpp"
#include "kernel_types.hpp"
2022-09-24 02:45:57 +03:00
#include "logger.hpp"
2022-09-16 03:16:38 +03:00
#include "memory.hpp"
2022-09-20 15:30:41 +03:00
#include "resource_limits.hpp"
2022-09-17 19:51:30 +03:00
#include "services/service_manager.hpp"
2022-09-16 03:16:38 +03:00
class CPU;
2024-07-02 15:30:38 +03:00
struct Scheduler;
2022-09-16 03:16:38 +03:00
class Kernel {
using Handle = HorizonHandle;
std::span<u32, 16> regs;
CPU& cpu;
2022-09-16 03:16:38 +03:00
Memory& mem;
// The handle number for the next kernel object to be created
u32 handleCounter;
2023-04-18 20:42:17 +03:00
// A list of our OS threads, the max number of which depends on the resource limit (hardcoded 32 per process on retail it seems).
// We have an extra thread for when no thread is capable of running. This thread is called the "idle thread" in our code
// This thread is set up in setupIdleThread and just yields in a loop to see if any other thread has woken up
std::array<Thread, appResourceLimits.maxThreads + 1> threads;
static constexpr int idleThreadIndex = appResourceLimits.maxThreads;
// Our waitlist system uses a bitfield of 64 bits to show which threads are waiting on an object.
// That means we can have a maximum of 63 threads + 1 idle thread. This assert should never trigger because the max thread # is 32
// But we have it here for safety purposes
static_assert(appResourceLimits.maxThreads <= 63, "The waitlist system is built on the premise that <= 63 threads max can be active");
2022-09-16 03:16:38 +03:00
std::vector<KernelObject> objects;
std::vector<Handle> portHandles;
std::vector<Handle> mutexHandles;
2023-11-04 18:28:28 +02:00
std::vector<Handle> timerHandles;
2022-09-16 03:16:38 +03:00
// Thread indices, sorted by priority
std::vector<int> threadIndices;
2022-09-19 16:29:50 +03:00
Handle currentProcess;
2022-09-19 22:19:36 +03:00
Handle mainThread;
2022-09-20 15:30:41 +03:00
int currentThreadIndex;
2022-09-19 22:19:36 +03:00
Handle srvHandle; // Handle for the special service manager port "srv:"
2022-10-05 00:29:29 +03:00
Handle errorPortHandle; // Handle for the err:f port used for displaying errors
u32 arbiterCount;
u32 threadCount; // How many threads in our thread pool have been used as of now (Up to 32)
u32 aliveThreadCount; // How many of these threads are actually alive?
2022-09-17 19:51:30 +03:00
ServiceManager serviceManager;
2022-09-16 03:16:38 +03:00
// Top 8 bits are the major version, bottom 8 are the minor version
u16 kernelVersion = 0;
// Shows whether a reschedule will be need
bool needReschedule = false;
Handle makeArbiter();
2022-10-05 00:29:29 +03:00
Handle makeProcess(u32 id);
Handle makePort(const char* name);
2022-09-17 19:51:30 +03:00
Handle makeSession(Handle port);
2023-08-20 01:51:24 +03:00
Handle makeThread(u32 entrypoint, u32 initialSP, u32 priority, ProcessorID id, u32 arg,ThreadStatus status = ThreadStatus::Dormant);
2023-01-29 16:29:45 +02:00
Handle makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission);
2022-11-17 00:29:02 +02:00
public:
// Needs to be public to be accessible to the APT/HID services
Handle makeEvent(ResetType resetType, Event::CallbackType callback = Event::CallbackType::None);
// 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 service manager port
Handle makeSemaphore(u32 initialCount, u32 maximumCount);
2023-08-13 03:35:41 +03:00
Handle makeTimer(ResetType resetType);
2024-01-22 04:04:05 +02:00
void pollTimers();
2022-11-17 00:29:02 +02:00
2023-04-21 01:08:13 +03:00
// Signals an event, returns true on success or false if the event does not exist
bool signalEvent(Handle e);
// Run the callback for "special" events that have callbacks
void runEventCallback(Event::CallbackType callback);
2023-09-09 01:56:39 +03:00
void clearEvent(Handle e) {
KernelObject* object = getObject(e, KernelObjectType::Event);
if (object != nullptr) {
object->getData<Event>()->fired = false;
}
}
private:
void signalArbiter(u32 waitingAddress, s32 threadCount);
2022-10-11 22:45:25 +03:00
void sleepThread(s64 ns);
2022-09-20 16:50:20 +03:00
void sleepThreadOnArbiter(u32 waitingAddress);
2022-09-20 15:30:41 +03:00
void switchThread(int newThreadIndex);
void sortThreads();
std::optional<int> getNextThread();
void rescheduleThreads();
bool canThreadRun(const Thread& t);
2022-12-07 02:08:18 +02:00
bool shouldWaitOnObject(KernelObject* object);
2023-04-20 22:24:36 +03:00
void releaseMutex(Mutex* moo);
2023-08-14 15:13:37 +03:00
void cancelTimer(Timer* timer);
void signalTimer(Handle timerHandle, Timer* timer);
2024-01-27 01:58:21 +02:00
u64 getWakeupTick(s64 ns);
2022-09-20 15:30:41 +03:00
2023-04-29 01:45:30 +03:00
// Wake up the thread with the highest priority out of all threads in the waitlist
// Returns the index of the woken up thread
// Do not call this function with an empty waitlist!!!
int wakeupOneThread(u64 waitlist, Handle handle);
void wakeupAllThreads(u64 waitlist, Handle handle);
std::optional<Handle> getPortHandle(const char* name);
void deleteObjectData(KernelObject& object);
2022-09-16 03:16:38 +03:00
KernelObject* getProcessFromPID(Handle handle);
s32 getCurrentResourceValue(const KernelObject* limit, u32 resourceName);
u32 getMaxForResource(const KernelObject* limit, u32 resourceName);
2022-09-17 19:51:30 +03:00
u32 getTLSPointer();
2023-04-18 20:42:17 +03:00
void setupIdleThread();
2023-04-20 22:00:51 +03:00
void acquireSyncObject(KernelObject* object, const Thread& thread);
2022-11-16 22:02:52 +02:00
bool isWaitable(const KernelObject* object);
2022-10-05 00:29:29 +03:00
// Functions for the err:f port
void handleErrorSyncRequest(u32 messagePointer);
void throwError(u32 messagePointer);
std::string getProcessName(u32 pid);
const char* resetTypeToString(u32 type);
2022-09-16 03:16:38 +03:00
2022-09-24 02:45:57 +03:00
MAKE_LOG_FUNCTION(log, kernelLogger)
MAKE_LOG_FUNCTION(logSVC, svcLogger)
MAKE_LOG_FUNCTION(logThread, threadLogger)
2022-10-05 00:29:29 +03:00
MAKE_LOG_FUNCTION(logError, errorLogger)
2022-10-09 18:28:45 +03:00
MAKE_LOG_FUNCTION(logFileIO, fileIOLogger)
2023-07-27 17:16:45 +03:00
MAKE_LOG_FUNCTION_USER(logDebugString, debugStringLogger)
2022-09-24 02:45:57 +03:00
// SVC implementations
void arbitrateAddress();
2022-09-16 03:16:38 +03:00
void createAddressArbiter();
2023-01-29 02:39:17 +02:00
void createMemoryBlock();
2022-09-19 16:29:50 +03:00
void createThread();
2022-09-18 18:17:41 +03:00
void controlMemory();
void duplicateHandle();
void exitThread();
void mapMemoryBlock();
2024-01-24 19:04:55 +02:00
void unmapMemoryBlock();
void queryMemory();
2023-08-20 01:51:24 +03:00
void getCurrentProcessorNumber();
2022-10-05 00:29:29 +03:00
void getProcessID();
void getProcessInfo();
2022-09-16 03:16:38 +03:00
void getResourceLimit();
void getResourceLimitLimitValues();
void getResourceLimitCurrentValues();
void getSystemInfo();
2022-09-21 00:48:51 +03:00
void getSystemTick();
2024-01-02 17:18:47 +02:00
void getThreadContext();
void getThreadID();
2023-08-20 03:43:26 +03:00
void getThreadIdealProcessor();
2022-10-16 01:01:09 +03:00
void getThreadPriority();
2022-09-17 04:55:15 +03:00
void sendSyncRequest();
2022-10-16 01:21:33 +03:00
void setThreadPriority();
2023-08-13 03:35:41 +03:00
void svcCancelTimer();
2023-04-21 01:08:13 +03:00
void svcClearEvent();
2023-08-13 03:35:41 +03:00
void svcClearTimer();
2022-09-16 16:18:12 +03:00
void svcCloseHandle();
2023-04-21 01:08:13 +03:00
void svcCreateEvent();
2023-04-20 22:24:36 +03:00
void svcCreateMutex();
2023-05-07 18:02:51 +03:00
void svcCreateSemaphore();
2023-08-13 03:35:41 +03:00
void svcCreateTimer();
2023-04-20 22:24:36 +03:00
void svcReleaseMutex();
2023-05-07 18:02:51 +03:00
void svcReleaseSemaphore();
2023-04-21 01:08:13 +03:00
void svcSignalEvent();
2023-08-13 03:35:41 +03:00
void svcSetTimer();
2022-10-11 22:45:25 +03:00
void svcSleepThread();
void connectToPort();
void outputDebugString();
void waitSynchronization1();
void waitSynchronizationN();
2022-09-16 03:16:38 +03:00
2022-10-09 15:59:09 +03:00
// File operations
void handleFileOperation(u32 messagePointer, Handle file);
2022-10-09 18:28:45 +03:00
void closeFile(u32 messagePointer, Handle file);
void flushFile(u32 messagePointer, Handle file);
2022-10-09 15:59:09 +03:00
void readFile(u32 messagePointer, Handle file);
void writeFile(u32 messagePointer, Handle file);
2023-01-14 02:40:24 +02:00
void getFileSize(u32 messagePointer, Handle file);
2023-03-10 01:04:04 +02:00
void openLinkFile(u32 messagePointer, Handle file);
2023-04-11 01:11:20 +03:00
void setFileSize(u32 messagePointer, Handle file);
2023-03-10 01:27:30 +02:00
void setFilePriority(u32 messagePointer, Handle file);
2022-10-09 15:59:09 +03:00
2023-03-29 00:23:55 +03:00
// Directory operations
void handleDirectoryOperation(u32 messagePointer, Handle directory);
void closeDirectory(u32 messagePointer, Handle directory);
void readDirectory(u32 messagePointer, Handle directory);
2022-09-16 03:16:38 +03:00
public:
2023-08-18 22:17:33 +03:00
Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config);
2023-01-23 02:35:10 +02:00
void initializeFS() { return serviceManager.initializeFS(); }
void setVersion(u8 major, u8 minor);
2022-09-16 03:16:38 +03:00
void serviceSVC(u32 svc);
void reset();
2022-09-24 02:45:57 +03:00
void requireReschedule() { needReschedule = true; }
2023-08-02 19:18:15 +03:00
void evalReschedule() {
if (needReschedule) {
needReschedule = false;
rescheduleThreads();
}
}
2022-10-09 15:59:09 +03:00
Handle makeObject(KernelObjectType type) {
if (handleCounter > KernelHandles::Max) [[unlikely]] {
Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
}
objects.push_back(KernelObject(handleCounter, type));
log("Created %s object with handle %d\n", kernelObjectTypeToString(type), handleCounter);
return handleCounter++;
}
std::vector<KernelObject>& getObjects() {
return objects;
}
// Get pointer to the object with the specified handle
KernelObject* getObject(Handle handle) {
// Accessing an object that has not been created
if (handle >= objects.size()) [[unlikely]] {
return nullptr;
}
return &objects[handle];
}
// Get pointer to the object with the specified handle and type
KernelObject* getObject(Handle handle, KernelObjectType type) {
if (handle >= objects.size() || objects[handle].type != type) [[unlikely]] {
return nullptr;
}
return &objects[handle];
}
2023-06-05 15:28:44 +03:00
ServiceManager& getServiceManager() { return serviceManager; }
2024-07-02 15:30:38 +03:00
Scheduler& getScheduler();
2023-06-05 13:25:06 +02:00
2023-06-05 15:28:44 +03:00
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
void clearInstructionCache();
2022-09-16 03:16:38 +03:00
};