#pragma once #include #include #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 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 ThreadList; typedef COsStructManager MemoryBlockList; typedef COsStructManager SemaphoreList; typedef COsStructManager EventFlagList; typedef COsStructManager IntrHandlerList; typedef COsStructManager MessageBoxList; typedef COsStructManager VplList; typedef COsStructManager LoadedModuleList; typedef std::map IopModuleMapType; typedef std::pair 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 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 IopBiosPtr;