Play-/Source/ee/PS2OS.h

484 lines
10 KiB
C
Raw Permalink Normal View History

#pragma once
#include <string>
#include <memory>
2019-10-16 20:51:11 -04:00
#include "filesystem_def.h"
2019-08-26 13:16:36 -04:00
#include "signal/Signal.h"
#include "../ELF.h"
#include "../MIPS.h"
#include "../BiosDebugInfoProvider.h"
#include "../OsStructManager.h"
#include "../OsVariableWrapper.h"
#include "../OsStructQueue.h"
#include "../gs/GSHandler.h"
#include "SIF.h"
#include "Ee_IdleEvaluator.h"
2020-03-25 08:02:59 -04:00
#include "Ee_LibMc2.h"
#define INTERRUPTS_ENABLED_MASK (CMIPS::STATUS_IE | CMIPS::STATUS_EIE)
class CIopBios;
class CPS2OS : public CBiosDebugInfoProvider
{
public:
typedef std::vector<std::string> ArgumentList;
2019-06-20 00:40:28 +01:00
typedef Framework::CSignal<void(const char*, const ArgumentList&)> RequestLoadExecutableEvent;
2018-04-30 21:01:23 +01:00
CPS2OS(CMIPS&, uint8*, uint8*, uint8*, CGSHandler*&, CSIF&, CIopBios&);
virtual ~CPS2OS();
void Initialize(uint32);
2018-04-30 21:01:23 +01:00
void Release();
2018-04-30 21:01:23 +01:00
bool IsIdle() const;
2019-10-16 20:51:11 -04:00
void BootFromFile(const fs::path&);
2018-04-30 21:01:23 +01:00
void BootFromVirtualPath(const char*, const ArgumentList&);
void BootFromCDROM();
CELF32* GetELF();
2018-04-30 21:01:23 +01:00
const char* GetExecutableName() const;
std::pair<uint32, uint32> GetExecutableRange() const;
uint32 LoadExecutable(const char*, const char*);
Ee::CLibMc2& GetLibMc2();
void HandleInterrupt(int32);
2018-04-30 21:01:23 +01:00
void HandleSyscall();
void HandleReturnFromException();
void HandleTLBException();
2018-04-30 21:01:23 +01:00
bool CheckVBlankFlag();
uint32 SuspendCurrentThread();
void ResumeThread(uint32);
uint8* GetStructPtr(uint32) const;
void UpdateTLBEnabledState();
2018-04-30 21:01:23 +01:00
static uint32 TranslateAddress(CMIPS*, uint32);
static uint32 TranslateAddressTLB(CMIPS*, uint32);
static uint32 CheckTLBExceptions(CMIPS*, uint32, uint32);
#ifdef DEBUGGER_INCLUDED
2018-04-30 21:01:23 +01:00
BiosDebugModuleInfoArray GetModulesDebugInfo() const override;
BiosDebugObjectInfoMap GetBiosObjectsDebugInfo() const override;
BiosDebugObjectArray GetBiosObjects(uint32) const override;
#endif
2019-06-20 00:40:28 +01:00
Framework::CSignal<void()> OnExecutableChange;
Framework::CSignal<void()> OnExecutableUnloading;
Framework::CSignal<void()> OnRequestInstructionCacheFlush;
2018-04-30 21:01:23 +01:00
RequestLoadExecutableEvent OnRequestLoadExecutable;
2019-06-20 00:40:28 +01:00
Framework::CSignal<void()> OnRequestExit;
2021-02-24 16:04:10 -05:00
Framework::CSignal<void()> OnCrtModeChange;
private:
enum
{
BIOS_SIFDMA_COUNT = 0x20,
};
struct BIOS_STATE
{
uint32 padding[4];
uint32 idleThreadId;
uint32 currentThreadId;
uint32 vsyncFlagValue1Ptr;
uint32 vsyncFlagValue2Ptr;
uint32 threadScheduleBase;
uint32 intcHandlerQueueBase;
uint32 dmacHandlerQueueBase;
uint32 tlblExceptionHandler;
uint32 tlbsExceptionHandler;
uint32 trapExceptionHandler;
uint32 allocateThreadNextId;
uint32 sifDmaNextIdx;
uint32 sifDmaTimes[BIOS_SIFDMA_COUNT];
};
static_assert((sizeof(BIOS_STATE) & 0xF) == 0, "Size of BIOS_STATE must be a multiple of 16.");
struct SEMAPHOREPARAM
{
2018-04-30 21:01:23 +01:00
uint32 count;
uint32 maxCount;
uint32 initCount;
uint32 waitThreads;
uint32 attributes;
uint32 option;
};
struct THREADPARAM
{
2018-04-30 21:01:23 +01:00
uint32 status;
uint32 threadProc;
uint32 stackBase;
uint32 stackSize;
uint32 gp;
uint32 initPriority;
uint32 currPriority;
uint32 attr;
uint32 option;
};
struct THREADSTATUS : public THREADPARAM
{
2018-04-30 21:01:23 +01:00
uint32 waitType;
uint32 waitId;
uint32 wakeupCount;
};
static_assert(sizeof(THREADSTATUS) == 0x30, "Thread status must be 48 bytes long.");
struct SEMAPHORE
{
2018-04-30 21:01:23 +01:00
uint32 isValid;
uint32 count;
uint32 maxCount;
uint32 waitCount;
2021-07-22 19:11:29 -04:00
uint32 waitNextId;
uint32 option;
};
struct THREAD
{
2018-04-30 21:01:23 +01:00
uint32 isValid;
uint32 nextId;
uint32 status;
uint32 contextPtr;
uint32 stackBase;
uint32 heapBase;
uint32 threadProc;
uint32 epc;
uint32 gp;
uint32 initPriority;
uint32 currPriority;
uint32 semaWait;
uint32 wakeUpCount;
uint32 stackSize;
};
enum STACKRES
{
STACKRES = 0x2A0,
2016-10-26 21:53:27 -04:00
STACK_FRAME_RESERVE_SIZE = 0x20
};
//Castlevania: CoD relies on the fact that the GPRs are stored
//in order starting from R0 all the way up to RA because it read/writes
//values directly in the thread context
struct THREADCONTEXT
{
2018-04-30 21:01:23 +01:00
uint128 gpr[0x20];
uint32 cop1[0x20];
uint32 fcsr;
uint32 cop1a;
uint32 unknown[6];
};
static_assert(sizeof(THREADCONTEXT) == STACKRES, "Size of THREADCONTEXT must be STACKRES");
struct DMACHANDLER
{
2018-04-30 21:01:23 +01:00
uint32 isValid;
uint32 nextId;
uint32 channel;
uint32 address;
uint32 arg;
uint32 gp;
};
struct INTCHANDLER
{
2018-04-30 21:01:23 +01:00
uint32 isValid;
uint32 nextId;
uint32 cause;
uint32 address;
uint32 arg;
uint32 gp;
};
struct DECI2HANDLER
{
uint32 isValid;
2018-04-30 21:01:23 +01:00
uint32 device;
uint32 bufferAddr;
};
//I have no idea about this, purely speculative
struct DECI2BUFFER
{
uint32 unknown0;
int32 status0;
int32 unknown1;
uint32 status1;
uint32 dataAddr;
};
static_assert(sizeof(DECI2BUFFER) == 0x14);
struct DECI2SEND
{
uint32 size;
uint32 unknown[2];
uint8 data[];
};
static_assert(offsetof(DECI2SEND, data) == 0x0C);
struct ALARM
{
2018-04-30 21:01:23 +01:00
uint32 isValid;
uint32 delay;
uint32 compare;
2018-04-30 21:01:23 +01:00
uint32 callback;
uint32 callbackParam;
uint32 gp;
};
enum class OSD_VERSION
{
V1,
V2,
V2_EXT,
};
enum class OSD_LANGUAGE
{
JAPANESE,
ENGLISH,
FRENCH,
SPANISH,
GERMAN,
ITALIAN,
DUTCH,
PORTUGUESE,
RUSSIAN,
KOREAN,
CHINESE_TRADITIONAL,
CHINESE_SIMPLIFIED
};
2020-12-17 17:46:02 -05:00
enum class OSD_SCREENTYPE
{
RATIO_4_3,
FULLSCREEN,
RATIO_16_9,
};
struct OSDCONFIGPARAM : public convertible<uint32>
{
uint32 spdifMode : 1;
uint32 screenType : 2;
uint32 videoOutput : 1;
uint32 jpLanguage : 1;
uint32 ps1drvConfig : 8;
uint32 version : 3;
uint32 language : 5;
uint32 timezoneOffset : 11;
};
#ifdef DEBUGGER_INCLUDED
struct SYSCALL_NAME
{
2018-04-30 21:01:23 +01:00
uint32 id;
const char* name;
};
#endif
enum SYSCALL_REGS
{
SC_RETURN = 2,
SC_PARAM0 = 4,
SC_PARAM1 = 5,
SC_PARAM2 = 6,
SC_PARAM3 = 7,
SC_PARAM4 = 8
};
enum MAX
{
2018-04-30 21:01:23 +01:00
MAX_THREAD = 256,
MAX_SEMAPHORE = 256,
MAX_DMACHANDLER = 128,
MAX_INTCHANDLER = 128,
MAX_DECI2HANDLER = 32,
MAX_ALARM = 4,
};
//TODO: Use "refer" status enum values
enum THREAD_STATUS
{
2018-04-30 21:01:23 +01:00
THREAD_RUNNING = 0x01,
THREAD_SLEEPING = 0x02,
THREAD_WAITING = 0x03,
THREAD_SUSPENDED = 0x04,
THREAD_SUSPENDED_WAITING = 0x05,
THREAD_SUSPENDED_SLEEPING = 0x06,
THREAD_ZOMBIE = 0x07,
};
enum THREAD_STATUS_REFER
{
2018-04-30 21:01:23 +01:00
THS_RUN = 0x01,
THS_READY = 0x02,
THS_WAIT = 0x04,
THS_SUSPEND = 0x08,
THS_DORMANT = 0x10,
};
typedef COsStructManager<DECI2HANDLER> Deci2HandlerList;
typedef COsStructManager<THREAD> ThreadList;
typedef COsStructManager<SEMAPHORE> SemaphoreList;
typedef COsStructManager<INTCHANDLER> IntcHandlerList;
typedef COsStructManager<DMACHANDLER> DmacHandlerList;
typedef COsStructManager<ALARM> AlarmList;
typedef COsStructQueue<THREAD> ThreadQueue;
typedef COsStructQueue<INTCHANDLER> IntcHandlerQueue;
typedef COsStructQueue<DMACHANDLER> DmacHandlerQueue;
typedef void (CPS2OS::*SystemCallHandler)();
2023-04-26 13:33:32 -04:00
void LoadELF(Framework::CStream*, const char*, const ArgumentList&);
2018-04-30 21:01:23 +01:00
void LoadExecutableInternal();
void UnloadExecutable();
2025-01-13 18:15:07 -05:00
void ApplyGameConfig();
2018-04-30 21:01:23 +01:00
void DisassembleSysCall(uint8);
std::string GetSysCallDescription(uint8);
2018-04-30 21:01:23 +01:00
static SystemCallHandler m_sysCall[0x80];
2018-04-30 21:01:23 +01:00
void AssembleCustomSyscallHandler();
void AssembleInterruptHandler();
void AssembleDmacHandler();
void AssembleIntcHandler();
void AssembleAlarmHandler();
void AssembleThreadEpilog();
void AssembleIdleThreadProc();
2018-04-30 21:01:23 +01:00
uint32* GetCustomSyscallTable();
2018-04-30 21:01:23 +01:00
void CreateIdleThread();
void LinkThread(uint32);
void UnlinkThread(uint32);
void ThreadShakeAndBake();
void ThreadSwitchContext(uint32);
void ThreadSaveContext(THREAD*, bool);
void ThreadLoadContext(THREAD*, bool);
2018-04-30 21:01:23 +01:00
void ThreadReset(uint32);
void CheckLivingThreads();
2021-07-22 19:11:29 -04:00
void SemaLinkThread(uint32, uint32);
void SemaUnlinkThread(uint32, uint32);
2021-07-22 19:11:29 -04:00
void SemaReleaseSingleThread(uint32, bool);
void AlarmUpdateCompare();
2018-04-30 21:01:23 +01:00
std::pair<uint32, uint32> GetVsyncFlagPtrs() const;
void SetVsyncFlagPtrs(uint32, uint32);
//Various system calls
2018-04-30 21:01:23 +01:00
void sc_GsSetCrt();
void sc_Exit();
void sc_LoadExecPS2();
void sc_ExecPS2();
2018-08-27 07:31:18 -04:00
void sc_SetVTLBRefillHandler();
void sc_SetVCommonHandler();
2018-04-30 21:01:23 +01:00
void sc_AddIntcHandler();
void sc_RemoveIntcHandler();
void sc_AddDmacHandler();
void sc_RemoveDmacHandler();
void sc_EnableIntc();
void sc_DisableIntc();
void sc_EnableDmac();
void sc_DisableDmac();
void sc_SetAlarm();
void sc_ReleaseAlarm();
void sc_CreateThread();
void sc_DeleteThread();
void sc_StartThread();
void sc_ExitThread();
void sc_ExitDeleteThread();
void sc_TerminateThread();
void sc_ChangeThreadPriority();
void sc_RotateThreadReadyQueue();
void sc_ReleaseWaitThread();
2018-04-30 21:01:23 +01:00
void sc_GetThreadId();
void sc_ReferThreadStatus();
void sc_SleepThread();
void sc_WakeupThread();
void sc_CancelWakeupThread();
void sc_SuspendThread();
void sc_ResumeThread();
void sc_SetupThread();
void sc_SetupHeap();
void sc_EndOfHeap();
void sc_CreateSema();
void sc_DeleteSema();
void sc_SignalSema();
void sc_WaitSema();
void sc_PollSema();
void sc_ReferSemaStatus();
void sc_GetOsdConfigParam();
2023-09-21 09:05:03 -04:00
void sc_GetCop0();
2018-04-30 21:01:23 +01:00
void sc_FlushCache();
void sc_GsGetIMR();
void sc_GsPutIMR();
void sc_SetVSyncFlag();
void sc_SetSyscall();
void sc_SifDmaStat();
void sc_SifSetDma();
void sc_SifSetDChain();
void sc_SifSetReg();
void sc_SifGetReg();
void sc_Deci2Call();
void sc_MachineType();
void sc_GetMemorySize();
void sc_Unhandled();
2023-05-02 08:56:25 -04:00
CMIPS& m_ee;
CGSHandler*& m_gs;
2018-04-30 21:01:23 +01:00
uint8* m_ram = nullptr;
uint32 m_ramSize = 0;
2018-04-30 21:01:23 +01:00
uint8* m_bios = nullptr;
uint8* m_spr = nullptr;
2023-05-02 08:56:25 -04:00
CSIF& m_sif;
Ee::CLibMc2 m_libMc2;
CIopBios& m_iopBios;
std::unique_ptr<CELF32> m_elf;
Deci2HandlerList m_deci2Handlers;
2018-04-30 21:01:23 +01:00
ThreadList m_threads;
SemaphoreList m_semaphores;
IntcHandlerList m_intcHandlers;
DmacHandlerList m_dmacHandlers;
AlarmList m_alarms;
BIOS_STATE* m_state = nullptr;
2018-04-30 21:01:23 +01:00
OsVariableWrapper<uint32> m_currentThreadId;
OsVariableWrapper<uint32> m_idleThreadId;
OsVariableWrapper<uint32> m_tlblExceptionHandler;
OsVariableWrapper<uint32> m_tlbsExceptionHandler;
2022-03-23 15:43:29 -04:00
OsVariableWrapper<uint32> m_trapExceptionHandler;
OsVariableWrapper<uint32> m_sifDmaNextIdx;
uint32* m_sifDmaTimes = nullptr;
2018-04-30 21:01:23 +01:00
ThreadQueue m_threadSchedule;
IntcHandlerQueue m_intcHandlerQueue;
DmacHandlerQueue m_dmacHandlerQueue;
ArgumentList m_currentArguments;
//For display purposes only
2018-04-30 21:01:23 +01:00
std::string m_executableName;
Ee::CIdleEvaluator m_idleEvaluator;
#ifdef DEBUGGER_INCLUDED
2018-04-30 21:01:23 +01:00
static const SYSCALL_NAME g_syscallNames[];
#endif
};