mirror of
https://github.com/libretro/Play-.git
synced 2025-01-21 07:56:18 +00:00
562 lines
14 KiB
C++
562 lines
14 KiB
C++
#pragma once
|
|
|
|
#include <memory>
|
|
#include <list>
|
|
#include "../MIPSAssembler.h"
|
|
#include "../MIPS.h"
|
|
#include "../ELF.h"
|
|
#include "../OsStructManager.h"
|
|
#include "../OsVariableWrapper.h"
|
|
#include "Iop_BiosBase.h"
|
|
#include "Iop_BiosStructs.h"
|
|
#include "Iop_SifMan.h"
|
|
#include "Iop_SifCmd.h"
|
|
#include "Iop_Ioman.h"
|
|
#include "Iop_Cdvdman.h"
|
|
#include "Iop_Stdio.h"
|
|
#include "Iop_Sysmem.h"
|
|
#include "Iop_Modload.h"
|
|
#include "Iop_Loadcore.h"
|
|
#include "Iop_LibSd.h"
|
|
#ifdef _IOP_EMULATE_MODULES
|
|
#include "Iop_FileIo.h"
|
|
#include "Iop_PadMan.h"
|
|
#include "Iop_MtapMan.h"
|
|
#include "Iop_Cdvdfsv.h"
|
|
#endif
|
|
|
|
class CMipsExecutor;
|
|
|
|
class CIopBios : public Iop::CBiosBase
|
|
{
|
|
public:
|
|
enum KERNEL_RESULT_CODES
|
|
{
|
|
KERNEL_RESULT_OK = 0,
|
|
KERNEL_RESULT_ERROR = -1,
|
|
KERNEL_RESULT_ERROR_ILLEGAL_CONTEXT = -100,
|
|
KERNEL_RESULT_ERROR_ILLEGAL_INTRCODE = -101,
|
|
KERNEL_RESULT_ERROR_FOUND_HANDLER = -104,
|
|
KERNEL_RESULT_ERROR_NOTFOUND_HANDLER = -105,
|
|
KERNEL_RESULT_ERROR_NO_MEMORY = -400,
|
|
KERNEL_RESULT_ERROR_ILLEGAL_ATTR = -401,
|
|
KERNEL_RESULT_ERROR_ILLEGAL_ENTRY = -402,
|
|
KERNEL_RESULT_ERROR_ILLEGAL_PRIORITY = -403,
|
|
KERNEL_RESULT_ERROR_ILLEGAL_THID = -406,
|
|
KERNEL_RESULT_ERROR_UNKNOWN_THID = -407,
|
|
KERNEL_RESULT_ERROR_UNKNOWN_EVFID = -409,
|
|
KERNEL_RESULT_ERROR_UNKNOWN_MBXID = -410,
|
|
KERNEL_RESULT_ERROR_UNKNOWN_VPLID = -411,
|
|
KERNEL_RESULT_ERROR_NOT_DORMANT = -414,
|
|
KERNEL_RESULT_ERROR_NOT_WAIT = -416,
|
|
KERNEL_RESULT_ERROR_SEMA_ZERO = -419,
|
|
KERNEL_RESULT_ERROR_EVF_CONDITION = -421,
|
|
KERNEL_RESULT_ERROR_EVF_ILLEGAL_PAT = -423,
|
|
KERNEL_RESULT_ERROR_MBX_NOMSG = -424,
|
|
KERNEL_RESULT_ERROR_ILLEGAL_MEMSIZE = -427,
|
|
};
|
|
|
|
enum CONTROL_BLOCK
|
|
{
|
|
CONTROL_BLOCK_START = 0x100,
|
|
CONTROL_BLOCK_END = 0x10000,
|
|
};
|
|
|
|
struct THREADCONTEXT
|
|
{
|
|
uint32 gpr[0x20];
|
|
uint32 epc;
|
|
uint32 delayJump;
|
|
};
|
|
|
|
struct THREAD
|
|
{
|
|
uint32 isValid;
|
|
uint32 id;
|
|
uint32 initPriority;
|
|
uint32 priority;
|
|
uint32 optionData;
|
|
uint32 attributes;
|
|
uint32 threadProc;
|
|
THREADCONTEXT context;
|
|
uint32 status;
|
|
uint32 waitSemaphore;
|
|
uint32 waitEventFlag;
|
|
uint32 waitEventFlagMode;
|
|
uint32 waitEventFlagMask;
|
|
uint32 waitEventFlagResultPtr;
|
|
uint32 waitMessageBox;
|
|
uint32 waitMessageBoxResultPtr;
|
|
uint32 wakeupCount;
|
|
uint32 stackBase;
|
|
uint32 stackSize;
|
|
uint32 nextThreadId;
|
|
uint64 nextActivateTime;
|
|
};
|
|
|
|
enum THREAD_STATUS
|
|
{
|
|
THREAD_STATUS_DORMANT = 1,
|
|
THREAD_STATUS_RUNNING = 2,
|
|
THREAD_STATUS_SLEEPING = 3,
|
|
THREAD_STATUS_WAITING_SEMAPHORE = 4,
|
|
THREAD_STATUS_WAITING_EVENTFLAG = 5,
|
|
THREAD_STATUS_WAITING_MESSAGEBOX = 6,
|
|
THREAD_STATUS_WAIT_VBLANK_START = 7,
|
|
THREAD_STATUS_WAIT_VBLANK_END = 8,
|
|
};
|
|
|
|
struct THREAD_INFO
|
|
{
|
|
uint32 attributes;
|
|
uint32 option;
|
|
uint32 status;
|
|
uint32 entryPoint;
|
|
uint32 stackAddr;
|
|
uint32 stackSize;
|
|
uint32 gp;
|
|
uint32 initPriority;
|
|
uint32 currentPriority;
|
|
uint32 waitType;
|
|
uint32 waitId;
|
|
uint32 wakeupCount;
|
|
uint32 regContextAddr;
|
|
uint32 reserved[4];
|
|
};
|
|
|
|
CIopBios(CMIPS&, CMipsExecutor&, uint8*, uint32, uint8*);
|
|
virtual ~CIopBios();
|
|
|
|
int32 LoadModule(const char*);
|
|
int32 LoadModule(uint32);
|
|
int32 LoadModuleFromHost(uint8*);
|
|
int32 UnloadModule(uint32);
|
|
int32 StartModule(uint32, const char*, const char*, uint32);
|
|
int32 StopModule(uint32);
|
|
bool IsModuleHle(uint32) const;
|
|
int32 SearchModuleByName(const char*) const;
|
|
void ProcessModuleReset(const std::string&);
|
|
|
|
bool TryGetImageVersionFromPath(const std::string&, unsigned int*);
|
|
bool TryGetImageVersionFromContents(const std::string&, unsigned int*);
|
|
|
|
void HandleException() override;
|
|
void HandleInterrupt() override;
|
|
|
|
void Reschedule();
|
|
|
|
void CountTicks(uint32) override;
|
|
uint64 GetCurrentTime();
|
|
uint64 MilliSecToClock(uint32);
|
|
uint64 MicroSecToClock(uint32);
|
|
uint64 ClockToMicroSec(uint64);
|
|
|
|
void NotifyVBlankStart() override;
|
|
void NotifyVBlankEnd() override;
|
|
|
|
void Reset(const Iop::SifManPtr&);
|
|
|
|
void SaveState(Framework::CZipArchiveWriter&) override;
|
|
void LoadState(Framework::CZipArchiveReader&) override;
|
|
|
|
bool IsIdle() override;
|
|
|
|
Iop::CIoman* GetIoman();
|
|
Iop::CCdvdman* GetCdvdman();
|
|
Iop::CLoadcore* GetLoadcore();
|
|
#ifdef _IOP_EMULATE_MODULES
|
|
Iop::CPadMan* GetPadman();
|
|
Iop::CCdvdfsv* GetCdvdfsv();
|
|
#endif
|
|
bool RegisterModule(const Iop::ModulePtr&);
|
|
|
|
uint32 CreateThread(uint32, uint32, uint32, uint32, uint32);
|
|
int32 DeleteThread(uint32);
|
|
int32 StartThread(uint32, uint32);
|
|
int32 StartThreadArgs(uint32, uint32, uint32);
|
|
void ExitThread();
|
|
uint32 TerminateThread(uint32);
|
|
int32 DelayThread(uint32);
|
|
void DelayThreadTicks(uint32);
|
|
uint32 SetAlarm(uint32, uint32, uint32);
|
|
uint32 CancelAlarm(uint32, uint32);
|
|
THREAD* GetThread(uint32);
|
|
int32 GetCurrentThreadId();
|
|
int32 GetCurrentThreadIdRaw() const;
|
|
int32 ChangeThreadPriority(uint32, uint32);
|
|
uint32 ReferThreadStatus(uint32, uint32, bool);
|
|
int32 SleepThread();
|
|
uint32 WakeupThread(uint32, bool);
|
|
int32 CancelWakeupThread(uint32, bool);
|
|
int32 ReleaseWaitThread(uint32, bool);
|
|
|
|
void SleepThreadTillVBlankStart();
|
|
void SleepThreadTillVBlankEnd();
|
|
|
|
uint32 CreateSemaphore(uint32, uint32);
|
|
uint32 DeleteSemaphore(uint32);
|
|
uint32 SignalSemaphore(uint32, bool);
|
|
uint32 WaitSemaphore(uint32);
|
|
uint32 PollSemaphore(uint32);
|
|
uint32 ReferSemaphoreStatus(uint32, uint32);
|
|
|
|
uint32 CreateEventFlag(uint32, uint32, uint32);
|
|
uint32 DeleteEventFlag(uint32);
|
|
uint32 SetEventFlag(uint32, uint32, bool);
|
|
uint32 ClearEventFlag(uint32, uint32);
|
|
uint32 WaitEventFlag(uint32, uint32, uint32, uint32);
|
|
uint32 PollEventFlag(uint32, uint32, uint32, uint32);
|
|
uint32 ReferEventFlagStatus(uint32, uint32);
|
|
bool ProcessEventFlag(uint32, uint32&, uint32, uint32*);
|
|
|
|
uint32 CreateMessageBox();
|
|
uint32 DeleteMessageBox(uint32);
|
|
uint32 SendMessageBox(uint32, uint32, bool);
|
|
uint32 ReceiveMessageBox(uint32, uint32);
|
|
uint32 PollMessageBox(uint32, uint32);
|
|
uint32 ReferMessageBoxStatus(uint32, uint32);
|
|
|
|
uint32 CreateVpl(uint32);
|
|
uint32 DeleteVpl(uint32);
|
|
uint32 pAllocateVpl(uint32, uint32);
|
|
uint32 FreeVpl(uint32, uint32);
|
|
uint32 ReferVplStatus(uint32, uint32);
|
|
uint32 GetVplFreeSize(uint32);
|
|
|
|
int32 RegisterIntrHandler(uint32, uint32, uint32, uint32);
|
|
int32 ReleaseIntrHandler(uint32);
|
|
|
|
void TriggerCallback(uint32 address, uint32 arg0, uint32 arg1);
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
|
void LoadDebugTags(Framework::Xml::CNode*) override;
|
|
void SaveDebugTags(Framework::Xml::CNode*) override;
|
|
|
|
BiosDebugModuleInfoArray GetModulesDebugInfo() const override;
|
|
BiosDebugThreadInfoArray GetThreadsDebugInfo() const override;
|
|
#endif
|
|
|
|
typedef boost::signals2::signal<void (uint32)> ModuleStartedEvent;
|
|
|
|
ModuleStartedEvent OnModuleStarted;
|
|
|
|
private:
|
|
enum DEFAULT_STACKSIZE
|
|
{
|
|
DEFAULT_STACKSIZE = 0x4000,
|
|
};
|
|
|
|
enum DEFAULT_PRIORITY
|
|
{
|
|
DEFAULT_PRIORITY = 64,
|
|
};
|
|
|
|
enum MODULE_INIT_PRIORITY
|
|
{
|
|
MODULE_INIT_PRIORITY = 8,
|
|
};
|
|
|
|
enum class MODULE_STATE : uint32
|
|
{
|
|
STOPPED,
|
|
STARTED,
|
|
HLE,
|
|
};
|
|
|
|
enum class MODULE_RESIDENT_STATE : uint32
|
|
{
|
|
RESIDENT_END = 0,
|
|
NO_RESIDENT_END = 1,
|
|
REMOVABLE_RESIDENT_END = 2,
|
|
};
|
|
|
|
enum
|
|
{
|
|
MAX_THREAD = 128,
|
|
MAX_MEMORYBLOCK = 256,
|
|
MAX_SEMAPHORE = 128,
|
|
MAX_EVENTFLAG = 64,
|
|
MAX_INTRHANDLER = 32,
|
|
MAX_MESSAGEBOX = 32,
|
|
MAX_VPL = 16,
|
|
MAX_MODULESTARTREQUEST = 32,
|
|
MAX_LOADEDMODULE = 32,
|
|
};
|
|
|
|
enum WEF_FLAGS
|
|
{
|
|
WEF_AND = 0x00,
|
|
WEF_OR = 0x01,
|
|
WEF_CLEAR = 0x10,
|
|
};
|
|
|
|
struct SEMAPHORE
|
|
{
|
|
uint32 isValid;
|
|
uint32 id;
|
|
uint32 count;
|
|
uint32 maxCount;
|
|
uint32 waitCount;
|
|
};
|
|
|
|
struct SEMAPHORE_STATUS
|
|
{
|
|
uint32 attrib;
|
|
uint32 option;
|
|
uint32 initCount;
|
|
uint32 maxCount;
|
|
uint32 currentCount;
|
|
uint32 numWaitThreads;
|
|
};
|
|
|
|
struct EVENTFLAG
|
|
{
|
|
uint32 isValid;
|
|
uint32 id;
|
|
uint32 attributes;
|
|
uint32 options;
|
|
uint32 value;
|
|
};
|
|
|
|
struct EVENTFLAGINFO
|
|
{
|
|
uint32 attributes;
|
|
uint32 options;
|
|
uint32 initBits;
|
|
uint32 currBits;
|
|
uint32 numThreads;
|
|
};
|
|
|
|
struct INTRHANDLER
|
|
{
|
|
uint32 isValid;
|
|
uint32 line;
|
|
uint32 mode;
|
|
uint32 handler;
|
|
uint32 arg;
|
|
};
|
|
|
|
struct MESSAGEBOX
|
|
{
|
|
uint32 isValid;
|
|
uint32 nextMsgPtr;
|
|
uint32 numMessage;
|
|
};
|
|
|
|
struct MESSAGEBOX_STATUS
|
|
{
|
|
uint32 attr;
|
|
uint32 option;
|
|
uint32 numWaitThread;
|
|
uint32 numMessage;
|
|
uint32 messagePtr;
|
|
uint32 unused[2];
|
|
};
|
|
|
|
struct MESSAGE_HEADER
|
|
{
|
|
uint32 nextMsgPtr;
|
|
uint8 priority;
|
|
uint8 unused[3];
|
|
};
|
|
|
|
struct VPL
|
|
{
|
|
uint32 isValid;
|
|
uint32 attr;
|
|
uint32 option;
|
|
uint32 poolPtr;
|
|
uint32 size;
|
|
uint32 headBlockId;
|
|
};
|
|
|
|
enum VPL_ATTR
|
|
{
|
|
VPL_ATTR_THFIFO = 0x000,
|
|
VPL_ATTR_THPRI = 0x001,
|
|
VPL_ATTR_THMODE_MASK = 0x001,
|
|
VPL_ATTR_MEMBTM = 0x200,
|
|
VPL_ATTR_MEMMODE_MASK = 0x200,
|
|
VPL_ATTR_VALID_MASK = (VPL_ATTR_THMODE_MASK | VPL_ATTR_MEMMODE_MASK)
|
|
};
|
|
|
|
struct VPL_PARAM
|
|
{
|
|
uint32 attr;
|
|
uint32 option;
|
|
uint32 size;
|
|
};
|
|
|
|
struct VPL_STATUS
|
|
{
|
|
uint32 attr;
|
|
uint32 option;
|
|
uint32 size;
|
|
uint32 freeSize;
|
|
uint32 numWaitThreads;
|
|
uint32 unused[3];
|
|
};
|
|
|
|
struct MODULESTARTREQUEST
|
|
{
|
|
enum
|
|
{
|
|
MAX_PATH_SIZE = 256,
|
|
MAX_ARGS_SIZE = 256
|
|
};
|
|
|
|
uint32 nextPtr;
|
|
uint32 moduleId;
|
|
uint32 stopRequest;
|
|
char path[MAX_PATH_SIZE];
|
|
uint32 argsLength;
|
|
char args[MAX_ARGS_SIZE];
|
|
};
|
|
|
|
struct LOADEDMODULE
|
|
{
|
|
enum
|
|
{
|
|
MAX_NAME_SIZE = 0x100,
|
|
};
|
|
|
|
uint32 isValid;
|
|
char name[MAX_NAME_SIZE];
|
|
uint32 start;
|
|
uint32 end;
|
|
uint32 entryPoint;
|
|
uint32 gp;
|
|
MODULE_STATE state;
|
|
MODULE_RESIDENT_STATE residentState;
|
|
};
|
|
|
|
struct IOPMOD
|
|
{
|
|
uint32 module;
|
|
uint32 startAddress;
|
|
uint32 gp;
|
|
uint32 textSectionSize;
|
|
uint32 dataSectionSize;
|
|
uint32 bssSectionSize;
|
|
uint16 moduleStructAttr;
|
|
char moduleName[256];
|
|
};
|
|
|
|
enum
|
|
{
|
|
IOPMOD_SECTION_ID = 0x70000080,
|
|
};
|
|
|
|
enum
|
|
{
|
|
ET_SCE_IOPRELEXEC = 0xFF80,
|
|
ET_SCE_IOPRELEXEC2 = 0xFF81
|
|
};
|
|
|
|
enum
|
|
{
|
|
R_MIPSSCE_MHI16 = 0xFA,
|
|
R_MIPSSCE_ADDEND = 0xFB
|
|
};
|
|
|
|
typedef COsStructManager<THREAD> ThreadList;
|
|
typedef COsStructManager<Iop::MEMORYBLOCK> MemoryBlockList;
|
|
typedef COsStructManager<SEMAPHORE> SemaphoreList;
|
|
typedef COsStructManager<EVENTFLAG> EventFlagList;
|
|
typedef COsStructManager<INTRHANDLER> IntrHandlerList;
|
|
typedef COsStructManager<MESSAGEBOX> MessageBoxList;
|
|
typedef COsStructManager<VPL> VplList;
|
|
typedef COsStructManager<LOADEDMODULE> LoadedModuleList;
|
|
typedef std::map<std::string, Iop::ModulePtr> IopModuleMapType;
|
|
typedef std::pair<uint32, uint32> ExecutableRange;
|
|
|
|
void LoadThreadContext(uint32);
|
|
void SaveThreadContext(uint32);
|
|
uint32 GetNextReadyThread();
|
|
void ReturnFromException();
|
|
|
|
uint32 FindIntrHandler(uint32);
|
|
|
|
void LinkThread(uint32);
|
|
void UnlinkThread(uint32);
|
|
|
|
uint32& ThreadLinkHead() const;
|
|
uint64& CurrentTime() const;
|
|
uint32& ModuleStartRequestHead() const;
|
|
uint32& ModuleStartRequestFree() const;
|
|
|
|
int32 LoadModule(CELF&, const char*);
|
|
uint32 LoadExecutable(CELF&, ExecutableRange&);
|
|
unsigned int GetElfProgramToLoad(CELF&);
|
|
void RelocateElf(CELF&, uint32);
|
|
std::string ReadModuleName(uint32);
|
|
void DeleteModules();
|
|
|
|
int32 LoadHleModule(const Iop::ModulePtr&);
|
|
|
|
uint32 AssembleThreadFinish(CMIPSAssembler&);
|
|
uint32 AssembleReturnFromException(CMIPSAssembler&);
|
|
uint32 AssembleIdleFunction(CMIPSAssembler&);
|
|
uint32 AssembleModuleStarterThreadProc(CMIPSAssembler&);
|
|
uint32 AssembleAlarmThreadProc(CMIPSAssembler&);
|
|
|
|
void InitializeModuleStarter();
|
|
void ProcessModuleStart();
|
|
void FinishModuleStart();
|
|
void RequestModuleStart(bool, uint32, const char*, const char*, unsigned int);
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
|
void PrepareModuleDebugInfo(CELF&, const ExecutableRange&, const std::string&, const std::string&);
|
|
BiosDebugModuleInfoIterator FindModuleDebugInfo(const std::string&);
|
|
BiosDebugModuleInfoIterator FindModuleDebugInfo(uint32, uint32);
|
|
#endif
|
|
|
|
CMIPS& m_cpu;
|
|
CMipsExecutor& m_cpuExecutor;
|
|
uint8* m_ram = nullptr;
|
|
uint32 m_ramSize;
|
|
uint8* m_spr = nullptr;
|
|
uint32 m_threadFinishAddress;
|
|
uint32 m_returnFromExceptionAddress;
|
|
uint32 m_idleFunctionAddress;
|
|
uint32 m_moduleStarterThreadProcAddress;
|
|
uint32 m_alarmThreadProcAddress;
|
|
|
|
uint32 m_moduleStarterThreadId;
|
|
|
|
bool m_rescheduleNeeded = false;
|
|
LoadedModuleList m_loadedModules;
|
|
ThreadList m_threads;
|
|
MemoryBlockList m_memoryBlocks;
|
|
SemaphoreList m_semaphores;
|
|
EventFlagList m_eventFlags;
|
|
IntrHandlerList m_intrHandlers;
|
|
MessageBoxList m_messageBoxes;
|
|
VplList m_vpls;
|
|
|
|
IopModuleMapType m_modules;
|
|
|
|
OsVariableWrapper<uint32> m_currentThreadId;
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
|
BiosDebugModuleInfoArray m_moduleTags;
|
|
#endif
|
|
Iop::SifManPtr m_sifMan;
|
|
Iop::SifCmdPtr m_sifCmd;
|
|
Iop::StdioPtr m_stdio;
|
|
Iop::IomanPtr m_ioman;
|
|
Iop::CdvdmanPtr m_cdvdman;
|
|
Iop::SysmemPtr m_sysmem;
|
|
Iop::ModloadPtr m_modload;
|
|
Iop::LoadcorePtr m_loadcore;
|
|
Iop::ModulePtr m_libsd;
|
|
#ifdef _IOP_EMULATE_MODULES
|
|
Iop::FileIoPtr m_fileIo;
|
|
Iop::PadManPtr m_padman;
|
|
Iop::MtapManPtr m_mtapman;
|
|
Iop::CdvdfsvPtr m_cdvdfsv;
|
|
#endif
|
|
};
|
|
|
|
typedef std::shared_ptr<CIopBios> IopBiosPtr;
|