From 09e3562a32a8e09af3e0311bb15eba83212173f7 Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Sun, 7 Jul 2024 13:24:14 -0400 Subject: [PATCH] Copy dolphin/os progress from TP decomp --- configure.py | 14 +- include/DynamicLink.h | 5 +- include/dolphin/dsp.h | 23 + include/dolphin/dvd/dvdfs.h | 3 + include/dolphin/exi/EXIBios.h | 109 ++++ include/dolphin/exi/EXIUart.h | 5 + include/dolphin/os/OS.h | 22 +- include/dolphin/os/OSExec.h | 17 +- include/dolphin/os/OSFont.h | 40 +- include/dolphin/os/OSInterrupt.h | 37 +- include/dolphin/os/OSLink.h | 129 ++-- include/dolphin/os/OSMemory.h | 2 +- include/dolphin/os/OSMessage.h | 4 + include/dolphin/os/OSReset.h | 2 +- include/dolphin/os/OSResetSW.h | 3 +- include/dolphin/os/OSThread.h | 2 +- include/dolphin/os/__ppc_eabi_init.h | 5 - include/dolphin/pad/Pad.h | 2 + include/dolphin/si/SIBios.h | 6 +- src/DynamicLink.cpp | 65 +- src/JSystem/JUtility/JUTException.cpp | 16 +- src/dolphin/gba/GBA.c | 4 +- src/dolphin/os/OS.c | 661 +++++++++++++++++++ src/dolphin/os/OSAlarm.c | 228 +++++++ src/dolphin/os/OSAlloc.c | 127 ++++ src/dolphin/os/OSArena.c | 31 + src/dolphin/os/OSAudioSystem.c | 105 +++ src/dolphin/os/OSCache.c | 432 ++++++++++++ src/dolphin/os/OSContext.c | 611 +++++++++++++++++ src/dolphin/os/OSError.c | 227 +++++++ src/dolphin/os/OSExec.c | 299 +++++++++ src/dolphin/os/OSFont.c | 303 +++++++++ src/dolphin/os/OSInterrupt.c | 430 ++++++++++++ src/dolphin/os/OSLink.c | 474 ++++++++++++++ src/dolphin/os/OSMemory.c | 210 ++++++ src/dolphin/os/OSMessage.c | 87 +++ src/dolphin/os/OSMutex.c | 231 +++++++ src/dolphin/os/OSReboot.c | 29 + src/dolphin/os/OSReset.c | 210 ++++++ src/dolphin/os/OSResetSW.c | 92 +++ src/dolphin/os/OSRtc.c | 251 +++++++ src/dolphin/os/OSSync.c | 32 + src/dolphin/os/OSThread.c | 901 ++++++++++++++++++++++++++ src/dolphin/os/OSTime.c | 138 ++++ src/dolphin/os/__ppc_eabi_init.cpp | 49 ++ src/dolphin/os/__start.c | 160 +++++ src/m_Do/m_Do_printf.cpp | 16 +- 47 files changed, 6696 insertions(+), 153 deletions(-) create mode 100644 include/dolphin/exi/EXIBios.h create mode 100644 include/dolphin/exi/EXIUart.h delete mode 100644 include/dolphin/os/__ppc_eabi_init.h create mode 100644 src/dolphin/os/OS.c create mode 100644 src/dolphin/os/OSAlarm.c create mode 100644 src/dolphin/os/OSAlloc.c create mode 100644 src/dolphin/os/OSArena.c create mode 100644 src/dolphin/os/OSAudioSystem.c create mode 100644 src/dolphin/os/OSCache.c create mode 100644 src/dolphin/os/OSContext.c create mode 100644 src/dolphin/os/OSError.c create mode 100644 src/dolphin/os/OSExec.c create mode 100644 src/dolphin/os/OSFont.c create mode 100644 src/dolphin/os/OSInterrupt.c create mode 100644 src/dolphin/os/OSLink.c create mode 100644 src/dolphin/os/OSMemory.c create mode 100644 src/dolphin/os/OSMessage.c create mode 100644 src/dolphin/os/OSMutex.c create mode 100644 src/dolphin/os/OSReboot.c create mode 100644 src/dolphin/os/OSReset.c create mode 100644 src/dolphin/os/OSResetSW.c create mode 100644 src/dolphin/os/OSRtc.c create mode 100644 src/dolphin/os/OSSync.c create mode 100644 src/dolphin/os/OSThread.c create mode 100644 src/dolphin/os/OSTime.c create mode 100644 src/dolphin/os/__ppc_eabi_init.cpp create mode 100644 src/dolphin/os/__start.c diff --git a/configure.py b/configure.py index e2b1595bb..e3d9bc02b 100644 --- a/configure.py +++ b/configure.py @@ -965,22 +965,22 @@ def JSystemLib(lib_name, objects): Object(NonMatching, "dolphin/os/OS.c"), Object(NonMatching, "dolphin/os/OSAlarm.c"), Object(NonMatching, "dolphin/os/OSAlloc.c"), - Object(NonMatching, "dolphin/os/OSArena.c"), - Object(NonMatching, "dolphin/os/OSAudioSystem.c"), + Object(Matching, "dolphin/os/OSArena.c"), + Object(Matching, "dolphin/os/OSAudioSystem.c"), Object(NonMatching, "dolphin/os/OSCache.c"), Object(NonMatching, "dolphin/os/OSContext.c"), Object(NonMatching, "dolphin/os/OSError.c"), Object(NonMatching, "dolphin/os/OSFont.c"), - Object(NonMatching, "dolphin/os/OSInterrupt.c"), - Object(NonMatching, "dolphin/os/OSLink.c"), - Object(NonMatching, "dolphin/os/OSMessage.c"), + Object(Matching, "dolphin/os/OSInterrupt.c"), + Object(Matching, "dolphin/os/OSLink.c"), + Object(Matching, "dolphin/os/OSMessage.c"), Object(NonMatching, "dolphin/os/OSMemory.c"), - Object(NonMatching, "dolphin/os/OSMutex.c"), + Object(Matching, "dolphin/os/OSMutex.c"), Object(NonMatching, "dolphin/os/OSReboot.c"), Object(NonMatching, "dolphin/os/OSReset.c"), Object(NonMatching, "dolphin/os/OSResetSW.c"), Object(NonMatching, "dolphin/os/OSRtc.c"), - Object(NonMatching, "dolphin/os/OSSync.c"), + Object(Matching, "dolphin/os/OSSync.c"), Object(NonMatching, "dolphin/os/OSThread.c"), Object(NonMatching, "dolphin/os/OSTime.c"), Object(NonMatching, "dolphin/os/__ppc_eabi_init.cpp"), diff --git a/include/DynamicLink.h b/include/DynamicLink.h index 6d82b2676..c90ea8091 100644 --- a/include/DynamicLink.h +++ b/include/DynamicLink.h @@ -1,9 +1,8 @@ #ifndef DYNAMICLINK_H #define DYNAMICLINK_H -#include "dolphin/types.h" +#include "dolphin/os/OS.h" -typedef struct OSModuleInfo OSModuleInfo; class JKRArchive; class JKRFileCache; class mDoDvdThd_callback_c; @@ -57,7 +56,7 @@ struct DynamicModuleControl : DynamicModuleControlBase { static bool initialize(); static bool callback(void*); - /* 0x10 */ OSModuleInfo* mModule; + /* 0x10 */ OSModuleHeader* mModule; /* 0x14 */ void* mBss; /* 0x18 */ u32 unk_24; /* 0x1c */ const char* mName; diff --git a/include/dolphin/dsp.h b/include/dolphin/dsp.h index f408874f6..a0b295351 100644 --- a/include/dolphin/dsp.h +++ b/include/dolphin/dsp.h @@ -20,6 +20,29 @@ extern "C" { #define DSP_TASK_STATE_YIELD 2 #define DSP_TASK_STATE_DONE 3 +#define DSP_MAILBOX_IN_HI (0) +#define DSP_MAILBOX_IN_LO (1) +#define DSP_MAILBOX_OUT_HI (2) +#define DSP_MAILBOX_OUT_LO (3) +#define DSP_CONTROL_STATUS (5) + +#define DSP_ARAM_SIZE (9) +#define DSP_ARAM_MODE (11) +#define DSP_ARAM_REFRESH (13) +#define DSP_ARAM_DMA_MM_HI (16) // Main mem address +#define DSP_ARAM_DMA_MM_LO (17) +#define DSP_ARAM_DMA_ARAM_HI (18) // ARAM address +#define DSP_ARAM_DMA_ARAM_LO (19) +#define DSP_ARAM_DMA_SIZE_HI (20) // DMA buffer size +#define DSP_ARAM_DMA_SIZE_LO (21) + +#define DSP_DMA_START_HI (24) // DMA start address +#define DSP_DMA_START_LO (25) +#define DSP_DMA_CONTROL_LEN (27) +#define DSP_DMA_BYTES_LEFT (29) + +#define DSP_DMA_START_FLAG (0x8000) // set to start DSP + typedef void (*DSPCallback)(void* task); typedef struct STRUCT_DSP_TASK { diff --git a/include/dolphin/dvd/dvdfs.h b/include/dolphin/dvd/dvdfs.h index d4fb3c471..aeeec2fe0 100644 --- a/include/dolphin/dvd/dvdfs.h +++ b/include/dolphin/dvd/dvdfs.h @@ -1,5 +1,8 @@ #ifndef DVDFS_H #define DVDFS_H +#include "dolphin/types.h" + +extern u32 __DVDLongFileNameFlag; #endif /* DVDFS_H */ diff --git a/include/dolphin/exi/EXIBios.h b/include/dolphin/exi/EXIBios.h new file mode 100644 index 000000000..00099f62b --- /dev/null +++ b/include/dolphin/exi/EXIBios.h @@ -0,0 +1,109 @@ +#ifndef EXIBIOS_H +#define EXIBIOS_H + +#include "dolphin/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OSContext OSContext; + +vu32 __EXIRegs[16] : 0xCC006800; + +#define EXI_MEMORY_CARD_59 0x00000004 +#define EXI_MEMORY_CARD_123 0x00000008 +#define EXI_MEMORY_CARD_251 0x00000010 +#define EXI_MEMORY_CARD_507 0x00000020 + +#define EXI_MEMORY_CARD_1019 0x00000040 +#define EXI_MEMORY_CARD_2043 0x00000080 + +#define EXI_MEMORY_CARD_1019A 0x00000140 +#define EXI_MEMORY_CARD_1019B 0x00000240 +#define EXI_MEMORY_CARD_1019C 0x00000340 +#define EXI_MEMORY_CARD_1019D 0x00000440 +#define EXI_MEMORY_CARD_1019E 0x00000540 +#define EXI_MEMORY_CARD_1019F 0x00000640 +#define EXI_MEMORY_CARD_1019G 0x00000740 + +#define EXI_MEMORY_CARD_2043A 0x00000180 +#define EXI_MEMORY_CARD_2043B 0x00000280 +#define EXI_MEMORY_CARD_2043C 0x00000380 +#define EXI_MEMORY_CARD_2043D 0x00000480 +#define EXI_MEMORY_CARD_2043E 0x00000580 +#define EXI_MEMORY_CARD_2043F 0x00000680 +#define EXI_MEMORY_CARD_2043G 0x00000780 + +#define EXI_USB_ADAPTER 0x01010000 +#define EXI_NPDP_GDEV 0x01020000 + +#define EXI_MODEM 0x02020000 +#define EXI_ETHER 0x04020200 +#define EXI_ETHER_VIEWER 0x04220001 +#define EXI_STREAM_HANGER 0x04130000 + +#define EXI_MARLIN 0x03010000 + +#define EXI_IS_VIEWER 0x05070000 + +#define EXI_FREQ_1M 0 +#define EXI_FREQ_2M 1 +#define EXI_FREQ_4M 2 +#define EXI_FREQ_8M 3 +#define EXI_FREQ_16M 4 +#define EXI_FREQ_32M 5 + +#define EXI_READ 0 +#define EXI_WRITE 1 + +#define EXI_STATE_IDLE 0x00 +#define EXI_STATE_DMA 0x01 +#define EXI_STATE_IMM 0x02 +#define EXI_STATE_BUSY (EXI_STATE_DMA | EXI_STATE_IMM) +#define EXI_STATE_SELECTED 0x04 +#define EXI_STATE_ATTACHED 0x08 +#define EXI_STATE_LOCKED 0x10 + +typedef void (*EXICallback)(s32 chan, OSContext* context); + +typedef struct EXIControl { + EXICallback exiCallback; + EXICallback tcCallback; + EXICallback extCallback; + vu32 state; + int immLen; + u8* immBuf; + u32 dev; + u32 id; + s32 idTime; + int items; + struct { + u32 dev; + EXICallback callback; + } queue[3]; +} EXIControl; + +s32 EXIImm(s32 chan, void* buf, s32 len, u32 type, EXICallback callback); +s32 EXIImmEx(s32 chan, void* buf, s32 len, u32 mode); +BOOL EXIDma(s32 chan, void* buf, s32 len, u32 type, EXICallback callback); +BOOL EXISync(s32 chan); +EXICallback EXISetExiCallback(s32 chan, EXICallback exiCallback); +BOOL EXIProbe(s32 chan); +s32 EXIProbeEx(s32 chan); +BOOL EXIAttach(s32 chan, EXICallback extCallback); +BOOL EXIDetach(s32 chan); +BOOL EXISelect(s32 chan, u32 dev, u32 freq); +BOOL EXIDeselect(s32 chan); +void EXIInit(void); +BOOL EXILock(s32 chan, u32 dev, EXICallback unlockedCallback); +BOOL EXIUnlock(s32 chan); +u32 EXIGetState(s32 chan); +static void UnlockedHandler(s32 chan, OSContext* context); +s32 EXIGetID(s32 chan, u32 dev, u32* id); + +#ifdef __cplusplus +}; +#endif + +#endif /* EXIBIOS_H */ diff --git a/include/dolphin/exi/EXIUart.h b/include/dolphin/exi/EXIUart.h new file mode 100644 index 000000000..53ebe6ea6 --- /dev/null +++ b/include/dolphin/exi/EXIUart.h @@ -0,0 +1,5 @@ +#ifndef EXIUART_H +#define EXIUART_H + + +#endif /* EXIUART_H */ diff --git a/include/dolphin/os/OS.h b/include/dolphin/os/OS.h index 391843c82..f9a91d8b3 100644 --- a/include/dolphin/os/OS.h +++ b/include/dolphin/os/OS.h @@ -88,11 +88,16 @@ extern u8 __OSReport_Warning_disable; extern u8 __OSReport_System_disable; extern u8 __OSReport_enable; +extern BOOL __OSIsGcam; + +extern u32 BOOT_REGION_START : 0x8044babc; +extern u32 BOOT_REGION_END : 0x812FDFEC; + void OSReportInit__Fv(void); // needed for inline asm u8* OSGetStackPointer(void); void __OSFPRInit(void); -static void InquiryCallback(u32 param_0, DVDCommandBlock* param_1); +static void InquiryCallback(s32 param_0, DVDCommandBlock* param_1); void OSInit(void); static void OSExceptionInit(void); void __OSDBIntegrator(void); @@ -147,7 +152,7 @@ inline void OSf32tou8(f32* f, u8* out) { *out = __OSf32tou8(*f); } -inline void OSInitFastCast(void) { +static inline void OSInitFastCast(void) { // clang-format off asm { li r3, 4 @@ -178,16 +183,6 @@ typedef struct OSBootInfo { /* 0x3C */ u32 fst_max_length; } OSBootInfo; -typedef struct { - BOOL valid; - u32 restartCode; - u32 bootDol; - void* regionStart; - void* regionEnd; - BOOL argsUseDefault; - void* argsAddr; // valid only when argsUseDefault = FALSE -} OSExecParams; - typedef struct BI2Debug { /* 0x00 */ s32 debugMonSize; /* 0x04 */ s32 simMemSize; @@ -234,7 +229,7 @@ struct GLOBAL_MEMORY { u8 padding_0x30e0[4]; u32 field_0x30e4; /* __OSPADButton */ u8 padding_0x30ec[8]; - u32 field_0x30f0; /* DOL Execute Parameters */ + OSExecParams* field_0x30f0; /* DOL Execute Parameters */ u8 padding_0x30f4[12]; u32 field_0x3100; /* Physical MEM1 size */ u32 field_0x3104; /* Simulated MEM1 size */ @@ -292,6 +287,7 @@ struct GLOBAL_MEMORY { #define OSUncachedToCached(ucaddr) ((void*)((u8*)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED))) extern OSTime __OSStartTime; +extern BOOL __OSInIPL; #ifdef __cplusplus }; diff --git a/include/dolphin/os/OSExec.h b/include/dolphin/os/OSExec.h index cb6a2a9d6..d2878e800 100644 --- a/include/dolphin/os/OSExec.h +++ b/include/dolphin/os/OSExec.h @@ -7,14 +7,23 @@ extern "C" { #endif +typedef struct { + /* 0x00 */ BOOL valid; + /* 0x04 */ u32 restartCode; + /* 0x08 */ u32 bootDol; + /* 0x0C */ void* regionStart; + /* 0x10 */ void* regionEnd; + /* 0x18 */ BOOL argsUseDefault; + /* 0x14 */ void* argsAddr; // valid only when argsUseDefault = FALSE +} OSExecParams; + static s32 PackArgs(void* param_0, u32 param_1, void* param_2); -static void Run(void); +static void Run(int param_0); static void ReadDisc(void* param_0, s32 param_1, s32 param_2); static void Callback(void); -void __OSGetExecParams(void* param_0); -static void GetApploaderPosition(void); +void __OSGetExecParams(OSExecParams* param_0); void __OSBootDolSimple(u32 param_0, u32 param_1, void* param_2, void* param_3, s32 param_4, u32 param_5, void* param_6); -void __OSBootDol(s32 param_0, u32 param_1, s32 param_2); +void __OSBootDol(s32 param_0, u32 param_1, char** param_2); #ifdef __cplusplus }; diff --git a/include/dolphin/os/OSFont.h b/include/dolphin/os/OSFont.h index cc29b5039..c83f57304 100644 --- a/include/dolphin/os/OSFont.h +++ b/include/dolphin/os/OSFont.h @@ -7,9 +7,45 @@ extern "C" { #endif -static u32 GetFontCode(s16 param_0, u32 param_1); +typedef enum { + OS_FONT_ENCODE_ANSI, + OS_FONT_ENCODE_SJIS, + OS_FONT_ENCODE_2, + OS_FONT_ENCODE_UTF8, + OS_FONT_ENCODE_UTF16, + OS_FONT_ENCODE_UTF32, + OS_FONT_ENCODE_MAX +} OSFontEncode; + +typedef struct OSFontHeader { + /* 0x00 */ u16 type; + /* 0x02 */ u16 firstChar; + /* 0x04 */ u16 lastChar; + /* 0x06 */ u16 invalidChar; + /* 0x08 */ u16 ascent; + /* 0x0A */ u16 descent; + /* 0x0C */ u16 width; + /* 0x0E */ u16 leading; + /* 0x10 */ u16 cellWidth; + /* 0x12 */ u16 cellHeight; + /* 0x14 */ u32 sheetSize; + /* 0x18 */ u16 sheetFormat; + /* 0x1A */ u16 sheetNumCol; + /* 0x1C */ u16 sheetNumRow; + /* 0x1E */ u16 sheetWidth; + /* 0x20 */ u16 sheetHeight; + /* 0x22 */ u16 widthTableOfs; + /* 0x24 */ u32 sheetImageOfs; + /* 0x28 */ u32 sheetFullSize; + /* 0x2C */ u8 c0; + /* 0x2D */ u8 c1; + /* 0x2E */ u8 c2; + /* 0x2F */ u8 c3; +} OSFontHeader; + +static u32 GetFontCode(u16 param_0, u16 param_1); u16 OSGetFontEncode(void); -static char* ParseStringS(s16 param_0, char* param_1, void* param_2, u32* param_3, u32 param_4, void* param_5); +static const u8* ParseStringS(u16 encode, const u8* str, OSFontHeader** fontOut, u32* codeOut); #ifdef __cplusplus }; diff --git a/include/dolphin/os/OSInterrupt.h b/include/dolphin/os/OSInterrupt.h index 5726d44c6..34b68a1ee 100644 --- a/include/dolphin/os/OSInterrupt.h +++ b/include/dolphin/os/OSInterrupt.h @@ -53,15 +53,18 @@ typedef enum { #define OS_INTERRUPTMASK_MEM_2 OS_INTERRUPTMASK(OS_INTR_MEM_2) #define OS_INTERRUPTMASK_MEM_3 OS_INTERRUPTMASK(OS_INTR_MEM_3) #define OS_INTERRUPTMASK_MEM_ADDRESS OS_INTERRUPTMASK(OS_INTR_MEM_ADDRESS) +#define OS_INTERRUPTMASK_MEM_RESET \ + (OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | \ + OS_INTERRUPTMASK_MEM_3) #define OS_INTERRUPTMASK_MEM \ - (OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | \ - OS_INTERRUPTMASK_MEM_3 | OS_INTERRUPTMASK_MEM_ADDRESS) + (OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | \ + OS_INTERRUPTMASK_MEM_3 | OS_INTERRUPTMASK_MEM_ADDRESS) #define OS_INTERRUPTMASK_DSP_AI OS_INTERRUPTMASK(OS_INTR_DSP_AI) #define OS_INTERRUPTMASK_DSP_ARAM OS_INTERRUPTMASK(OS_INTR_DSP_ARAM) #define OS_INTERRUPTMASK_DSP_DSP OS_INTERRUPTMASK(OS_INTR_DSP_DSP) #define OS_INTERRUPTMASK_DSP \ - (OS_INTERRUPTMASK_DSP_AI | OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP) + (OS_INTERRUPTMASK_DSP_AI | OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP) #define OS_INTERRUPTMASK_AI_AI OS_INTERRUPTMASK(OS_INTR_AI_AI) #define OS_INTERRUPTMASK_AI (OS_INTERRUPTMASK_AI_AI) @@ -70,21 +73,21 @@ typedef enum { #define OS_INTERRUPTMASK_EXI_0_TC OS_INTERRUPTMASK(OS_INTR_EXI_0_TC) #define OS_INTERRUPTMASK_EXI_0_EXT OS_INTERRUPTMASK(OS_INTR_EXI_0_EXT) #define OS_INTERRUPTMASK_EXI_0 \ - (OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT) + (OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT) #define OS_INTERRUPTMASK_EXI_1_EXI OS_INTERRUPTMASK(OS_INTR_EXI_1_EXI) #define OS_INTERRUPTMASK_EXI_1_TC OS_INTERRUPTMASK(OS_INTR_EXI_1_TC) #define OS_INTERRUPTMASK_EXI_1_EXT OS_INTERRUPTMASK(OS_INTR_EXI_1_EXT) #define OS_INTERRUPTMASK_EXI_1 \ - (OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT) + (OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT) #define OS_INTERRUPTMASK_EXI_2_EXI OS_INTERRUPTMASK(OS_INTR_EXI_2_EXI) #define OS_INTERRUPTMASK_EXI_2_TC OS_INTERRUPTMASK(OS_INTR_EXI_2_TC) #define OS_INTERRUPTMASK_EXI_2 (OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC) #define OS_INTERRUPTMASK_EXI \ - (OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT | \ - OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT | \ - OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC) + (OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT | \ + OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT | \ + OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC) #define OS_INTERRUPTMASK_PI_PE_TOKEN OS_INTERRUPTMASK(OS_INTR_PI_PE_TOKEN) #define OS_INTERRUPTMASK_PI_PE_FINISH OS_INTERRUPTMASK(OS_INTR_PI_PE_FINISH) @@ -99,27 +102,27 @@ typedef enum { #define OS_INTERRUPTMASK_PI_DEBUG OS_INTERRUPTMASK(OS_INTR_PI_DEBUG) #define OS_INTERRUPTMASK_PI_HSP OS_INTERRUPTMASK(OS_INTR_PI_HSP) #define OS_INTERRUPTMASK_PI \ - (OS_INTERRUPTMASK_PI_CP | OS_INTERRUPTMASK_PI_SI | OS_INTERRUPTMASK_PI_DI | \ - OS_INTERRUPTMASK_PI_RSW | OS_INTERRUPTMASK_PI_ERROR | OS_INTERRUPTMASK_PI_VI | \ - OS_INTERRUPTMASK_PI_PE_TOKEN | OS_INTERRUPTMASK_PI_PE_FINISH | OS_INTERRUPTMASK_PI_DEBUG | \ - OS_INTERRUPTMASK_PI_HSP) + (OS_INTERRUPTMASK_PI_CP | OS_INTERRUPTMASK_PI_SI | OS_INTERRUPTMASK_PI_DI | \ + OS_INTERRUPTMASK_PI_RSW | OS_INTERRUPTMASK_PI_ERROR | OS_INTERRUPTMASK_PI_VI | \ + OS_INTERRUPTMASK_PI_PE_TOKEN | OS_INTERRUPTMASK_PI_PE_FINISH | OS_INTERRUPTMASK_PI_DEBUG | \ + OS_INTERRUPTMASK_PI_HSP) -typedef s16 OSInterrupt; +typedef s16 __OSInterrupt; typedef u32 OSInterruptMask; -typedef void (*OSInterruptHandler)(OSInterrupt interrupt, OSContext* context); +typedef void (*__OSInterruptHandler)(__OSInterrupt interrupt, OSContext* context); BOOL OSDisableInterrupts(void); void __RAS_OSDisableInterrupts_end(void); BOOL OSEnableInterrupts(void); BOOL OSRestoreInterrupts(BOOL enable); -OSInterruptHandler __OSSetInterruptHandler(OSInterrupt interrupt, OSInterruptHandler handler); -OSInterruptHandler __OSGetInterruptHandler(s16 index); +__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler); +__OSInterruptHandler __OSGetInterruptHandler(s16 index); void __OSInterruptInit(void); static OSInterruptMask SetInterruptMask(OSInterruptMask param_0, OSInterruptMask param_1); OSInterruptMask __OSMaskInterrupts(OSInterruptMask mask); OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask mask); void __OSDispatchInterrupt(u8 interrupt, OSContext* context); -static void ExternalInterruptHandler(OSInterrupt interrupt, OSContext* context); +static void ExternalInterruptHandler(__OSInterrupt interrupt, OSContext* context); void __RAS_OSDisableInterrupts_begin(void); void __RAS_OSDisableInterrupts_end(void); diff --git a/include/dolphin/os/OSLink.h b/include/dolphin/os/OSLink.h index 06f1bb301..55e63d5e2 100644 --- a/include/dolphin/os/OSLink.h +++ b/include/dolphin/os/OSLink.h @@ -1,61 +1,106 @@ #ifndef OSLINK_H #define OSLINK_H -#include "dolphin/types.h" #ifdef __cplusplus extern "C" { #endif -typedef struct OSModuleQueue { - int* first; - int* last; -} OSModuleQueue; +#define OS_MODULE_VERSION 3 + +typedef struct OSModuleHeader OSModuleHeader; + +typedef u32 OSModuleID; +typedef struct OSModuleQueue OSModuleQueue; +typedef struct OSModuleLink OSModuleLink; +typedef struct OSModuleInfo OSModuleInfo; +typedef struct OSSectionInfo OSSectionInfo; +typedef struct OSImportInfo OSImportInfo; +typedef struct OSRel OSRel; OSModuleQueue __OSModuleList : 0x800030C8; void* __OSStringTable : 0x800030D0; -typedef struct OSSectionInfo { - u32 mOffset; - u32 mSize; -} OSSectionInfo; - -typedef struct OSModuleInfo { - u32 mId; - u32 mNext; - u32 mPrev; - u32 mNumSections; - struct { // Needed to get an assert correct; very likely bigger - u32 sectionInfoOffset; - } info; - u32 mModuleNameOffset; - u32 mModuleNameSize; - u32 mModuleVersion; - u32 mBssSize; - u32 mRelocationTableOffset; - u32 mImportTableOffset; - u32 mImportTableSize; - u8 mPrologSection; - u8 mEpilogSection; - u8 mUnresolvedSection; - u8 mBssSection; - u32 prolog; - u32 epilog; - u32 mUnresolvedFuncOffset; - u32 mModuleAlignment; - u32 mBssAlignment; +struct OSModuleQueue { + OSModuleInfo* head; + OSModuleInfo* tail; +}; + +struct OSModuleLink { + OSModuleInfo* next; + OSModuleInfo* prev; +}; + +struct OSSectionInfo { + u32 offset; + u32 size; +}; + +struct OSModuleInfo { + OSModuleID id; // unique identifier for the module + OSModuleLink link; // doubly linked list of modules + u32 numSections; // # of sections + u32 sectionInfoOffset; // offset to section info table + u32 nameOffset; // offset to module name + u32 nameSize; // size of module name + u32 version; // version number +}; + +struct OSModuleHeader { + // CAUTION: info must be the 1st member + OSModuleInfo info; + + // OS_MODULE_VERSION == 1 + u32 bssSize; // total size of bss sections in bytes + u32 relOffset; + u32 impOffset; + u32 impSize; // size in bytes + u8 prologSection; // section # for prolog function + u8 epilogSection; // section # for epilog function + u8 unresolvedSection; // section # for unresolved function + u8 bssSection; // section # for bss section (set at run-time) + u32 prolog; // prolog function offset + u32 epilog; // epilog function offset + u32 unresolved; // unresolved function offset + + // OS_MODULE_VERSION == 2 +#if (2 <= OS_MODULE_VERSION) + u32 align; // module alignment constraint + u32 bssAlign; // bss alignment constraint +#endif + + // OS_MODULE_VERSION == 3 +#if (3 <= OS_MODULE_VERSION) u32 fixSize; -} OSModuleInfo; +#endif +}; + +#define OSGetSectionInfo(module) ((OSSectionInfo*)(((OSModuleInfo*)(module))->sectionInfoOffset)) + +#define OS_SECTIONINFO_EXEC 0x1 +#define OS_SECTIONINFO_OFFSET(offset) ((offset) & ~0x1) + +struct OSImportInfo { + OSModuleID id; // external module id + u32 offset; // offset to OSRel instructions +}; + +struct OSRel { + u16 offset; // byte offset from the previous entry + u8 type; + u8 section; + u32 addend; +}; + +#define R_DOLPHIN_NOP 201 // C9h current offset += OSRel.offset +#define R_DOLPHIN_SECTION 202 // CAh current section = OSRel.section +#define R_DOLPHIN_END 203 // CBh +#define R_DOLPHIN_MRKREF 204 // CCh -BOOL OSLink(OSModuleInfo* module); -BOOL OSLinkFixed(OSModuleInfo* module, u32 param_1); +BOOL OSLink(OSModuleInfo* newModule, void* bss); +BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss); BOOL OSUnlink(OSModuleInfo* module); -static void OSNotifyLink(void); -static void OSNotifyUnlink(void); void OSSetStringTable(void* string_table); -static BOOL Relocate(OSModuleInfo* param_0, OSModuleInfo* param_1); -static BOOL Link(OSModuleInfo* module, u32 param_1); -static BOOL Undo(OSModuleInfo* param_0, OSModuleInfo* param_1); void __OSModuleInit(void); #ifdef __cplusplus diff --git a/include/dolphin/os/OSMemory.h b/include/dolphin/os/OSMemory.h index dbd0e22f2..a022f6c5a 100644 --- a/include/dolphin/os/OSMemory.h +++ b/include/dolphin/os/OSMemory.h @@ -18,7 +18,7 @@ extern "C" { #define OS_PROTECT_CONTROL_RDWR (OS_PROTECT_CONTROL_READ | OS_PROTECT_CONTROL_WRITE) u32 OSGetConsoleSimulatedMemSize(); -static void MEMIntrruptHandler(OSInterrupt interrupt, struct OSContext* context); +static void MEMIntrruptHandler(__OSInterrupt interrupt, struct OSContext* context); void OSProtectRange(u32 channel, void* address, u32 nBytes, u32 control); static void Config24MB(void); static void Config48MB(void); diff --git a/include/dolphin/os/OSMessage.h b/include/dolphin/os/OSMessage.h index a6447ec9c..25f153616 100644 --- a/include/dolphin/os/OSMessage.h +++ b/include/dolphin/os/OSMessage.h @@ -22,6 +22,10 @@ typedef struct OSMessageQueue { #define OS_MESSAGE_NOBLOCK 0 #define OS_MESSAGE_BLOCK 1 +typedef enum { + OS_MSG_PERSISTENT = (1 << 0), +} OSMessageFlags; + void OSInitMessageQueue(OSMessageQueue* queue, OSMessage* msgArray, s32 msgCount); BOOL OSSendMessage(OSMessageQueue* queue, OSMessage msg, s32 flags); BOOL OSReceiveMessage(OSMessageQueue* queue, OSMessage* msg, s32 flags); diff --git a/include/dolphin/os/OSReset.h b/include/dolphin/os/OSReset.h index 5ecf9b7b2..54678e53d 100644 --- a/include/dolphin/os/OSReset.h +++ b/include/dolphin/os/OSReset.h @@ -28,7 +28,7 @@ vu32 __PIRegs[12] : 0xCC003000; #define OS_RESET_PRIO_GX 127 #define OS_RESET_PRIO_ALARM 4294967295 -typedef s32 (*OSResetFunction)(s32); +typedef BOOL (*OSResetFunction)(BOOL final); typedef struct OSResetFunctionInfo { /* 0x0 */ OSResetFunction func; diff --git a/include/dolphin/os/OSResetSW.h b/include/dolphin/os/OSResetSW.h index 4ac78009a..e0205387e 100644 --- a/include/dolphin/os/OSResetSW.h +++ b/include/dolphin/os/OSResetSW.h @@ -1,7 +1,7 @@ #ifndef OSRESETSW_H #define OSRESETSW_H -#include "dolphin/types.h" +#include "dolphin/os/OSInterrupt.h" #ifdef __cplusplus extern "C" { @@ -11,6 +11,7 @@ typedef void (*OSResetCallback)(void); static BOOL OSGetResetButtonState(void); BOOL OSGetResetSwitchState(void); +void __OSResetSWInterruptHandler(__OSInterrupt interrupt, OSContext* context); #ifdef __cplusplus }; diff --git a/include/dolphin/os/OSThread.h b/include/dolphin/os/OSThread.h index 4e3cf308a..5052dd23c 100644 --- a/include/dolphin/os/OSThread.h +++ b/include/dolphin/os/OSThread.h @@ -68,7 +68,7 @@ struct OSThread { OSMutexQueue owned_mutexes; OSThreadLink active_threads_link; u8* stack_base; - u8* stack_end; + u32* stack_end; u8* error_code; void* data[2]; }; diff --git a/include/dolphin/os/__ppc_eabi_init.h b/include/dolphin/os/__ppc_eabi_init.h deleted file mode 100644 index 5d116bc33..000000000 --- a/include/dolphin/os/__ppc_eabi_init.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef __PPC_EABI_INIT_H -#define __PPC_EABI_INIT_H - - -#endif /* __PPC_EABI_INIT_H */ diff --git a/include/dolphin/pad/Pad.h b/include/dolphin/pad/Pad.h index 229e6457d..169222cc2 100644 --- a/include/dolphin/pad/Pad.h +++ b/include/dolphin/pad/Pad.h @@ -76,6 +76,8 @@ static void PADProbeCallback(s32 chan, u32 error, OSContext* context); static void PADTypeAndStatusCallback(s32 chan, u32 type); static void PADReceiveCheckCallback(s32 chan, u32 type); +extern u32 __PADSpec; + #ifdef __cplusplus }; #endif diff --git a/include/dolphin/si/SIBios.h b/include/dolphin/si/SIBios.h index 4e7efc629..b5f10067d 100644 --- a/include/dolphin/si/SIBios.h +++ b/include/dolphin/si/SIBios.h @@ -102,10 +102,10 @@ typedef union SIComm_u { BOOL SIBusy(void); BOOL SIIsChanBusy(s32 chan); -static void SIInterruptHandler(OSInterrupt interrupt, OSContext* context); +static void SIInterruptHandler(__OSInterrupt interrupt, OSContext* context); static BOOL SIEnablePollingInterrupt(BOOL enable); -BOOL SIRegisterPollingHandler(OSInterruptHandler handler); -BOOL SIUnregisterPollingHandler(OSInterruptHandler handler); +BOOL SIRegisterPollingHandler(__OSInterruptHandler handler); +BOOL SIUnregisterPollingHandler(__OSInterruptHandler handler); void SIInit(void); u32 SIGetStatus(s32 chan); void SISetCommand(s32 chan, u32 command); diff --git a/src/DynamicLink.cpp b/src/DynamicLink.cpp index 1a572c599..17ef7b21a 100644 --- a/src/DynamicLink.cpp +++ b/src/DynamicLink.cpp @@ -4,14 +4,12 @@ */ #include "DynamicLink.h" -#include "JSystem/JKernel/JKRArchive.h" #include "JSystem/JKernel/JKRDvdRipper.h" #include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRFileCache.h" #include "JSystem/JUtility/JUTAssert.h" #include "JSystem/JUtility/JUTConsole.h" #include "stdio.h" -#include "REL/executor.h" #include "m_Do/m_Do_dvd_thread.h" #include "m_Do/m_Do_ext.h" #include "m_Do/m_Do_printf.h" @@ -51,8 +49,6 @@ DynamicModuleControlBase::DynamicModuleControlBase() { mLast = this; } -extern OSThread mainThread; - BOOL DynamicModuleControlBase::link() { OSThread* thread = OSGetCurrentThread(); if (thread != &mainThread) { @@ -64,12 +60,12 @@ BOOL DynamicModuleControlBase::link() { if (do_link() == false) { return false; } - if (mDoLinkCount < 65535) { + if (mDoLinkCount < 0xFFFF) { mDoLinkCount++; } } JUT_ASSERT(100, mLinkCount < 65535); - if (mLinkCount < 65535) { + if (mLinkCount < 0xFFFF) { mLinkCount++; } return true; @@ -212,19 +208,19 @@ bool DynamicModuleControl::do_load() { snprintf(buffer, 64, "%s.rel", mName); if (mModule == NULL && sArchive != NULL) { if (mModule == NULL) { - mModule = (OSModuleInfo*)JKRGetResource('MMEM', buffer, sArchive); + mModule = (OSModuleHeader*)JKRGetResource('MMEM', buffer, sArchive); if (mModule != NULL) { mResourceType = 1; } } if (mModule == NULL) { - mModule = (OSModuleInfo*)JKRGetResource('AMEM', buffer, sArchive); + mModule = (OSModuleHeader*)JKRGetResource('AMEM', buffer, sArchive); if (mModule != NULL) { mResourceType = 2; } } if (mModule == NULL) { - mModule = (OSModuleInfo*)JKRGetResource('DMEM', buffer, sArchive); + mModule = (OSModuleHeader*)JKRGetResource('DMEM', buffer, sArchive); if (mModule != NULL) { mResourceType = 3; } @@ -236,7 +232,7 @@ bool DynamicModuleControl::do_load() { } else { if (mModule == NULL) { snprintf(buffer, 64, "/rels/%s.rel", mName); - mModule = (OSModuleInfo*)JKRDvdToMainRam( + mModule = (OSModuleHeader*)JKRDvdToMainRam( buffer, NULL, EXPAND_SWITCH_UNKNOWN1, NULL, archiveHeap, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 0, NULL); if (mModule != NULL) { @@ -245,7 +241,7 @@ bool DynamicModuleControl::do_load() { } } if (mModule == NULL && sFileCache != NULL) { - mModule = (OSModuleInfo*)sFileCache->getResource('rels', buffer); + mModule = (OSModuleHeader*)sFileCache->getResource('rels', buffer); if (mModule != NULL) { mSize = 0; mResourceType = 11; @@ -254,7 +250,7 @@ bool DynamicModuleControl::do_load() { } } if (mModule == NULL) { - // "DynamicModuleControl::do_load() Resource loading failure [%s]\n" + // "DynamicModuleControl::do_load() Resource load failure [%s]\n" OSReport_Error("DynamicModuleControl::do_load() リソース読み込み失敗 [%s]\n", mName); return false; } @@ -297,8 +293,7 @@ BOOL DynamicModuleControl::do_load_async() { if (mModule != NULL) { return true; } - mAsyncLoadCallback = mDoDvdThd_callback_c::create( - (mDoDvdThd_callback_func)DynamicModuleControl::callback, this); + mAsyncLoadCallback = mDoDvdThd_callback_c::create((mDoDvdThd_callback_func)DynamicModuleControl::callback, this); if (mAsyncLoadCallback == NULL) { OSReport_Error( // "DynamicModuleControl::do_load_async() async load callback entry failure [%s]\n" @@ -326,9 +321,9 @@ bool DynamicModuleControl::do_unload() { void DynamicModuleControl::dump2() { if (mModule != NULL) { OSSectionInfo* section = (OSSectionInfo*)mModule->info.sectionInfoOffset; - OSReport("mModule=%08x %08x %08x %08x %08x\n", mModule, section[1].mOffset & ~1, - section[1].mSize, mModule->mImportTableOffset - mModule->mRelocationTableOffset, - mModule->mImportTableSize); + OSReport("mModule=%08x %08x %08x %08x %08x\n", mModule, section[1].offset & ~1, + section[1].size, mModule->impOffset - mModule->relOffset, + mModule->impSize); } } @@ -342,57 +337,57 @@ BOOL DynamicModuleControl::do_link() { JUT_ASSERT(615, (u32)mModule + mModule->fixSize < 0x82000000); OSGetTime(); OSGetTime(); - if (mModule->mModuleVersion >= 3) { + if (mModule->info.version >= 3) { u32 fixSizePtr; u32 fixSize = mModule->fixSize; u32 fixSize2 = (fixSize + 0x1f) & ~0x1f; fixSizePtr = (u32)mModule + fixSize2; s32 size = JKRGetMemBlockSize(NULL, mModule); if (size < 0) { - void* bss = JKRAlloc(mModule->mBssSize, 0x20); + void* bss = JKRAlloc(mModule->bssSize, 0x20); if (bss == NULL) { // "BSS Memory allocation failed\n" OSReport_Error("BSSメモリ確保失敗\n", bss); goto error; } mBss = bss; - BOOL linkResult = OSLink(mModule); + BOOL linkResult = OSLink(&mModule->info, bss); if (linkResult == FALSE) { // "link failed\n" OSReport_Error("リンク失敗\n"); goto error; } } else { - if (fixSize2 + mModule->mBssSize < size) { - BOOL linkResult = OSLinkFixed(mModule, fixSizePtr); + if (fixSize2 + mModule->bssSize < size) { + BOOL linkResult = OSLinkFixed(&mModule->info, (void*)fixSizePtr); if (linkResult == FALSE) { // "link failed\n" OSReport_Error("リンク失敗\n"); goto error; } - s32 result = JKRResizeMemBlock(NULL, mModule, fixSize2 + mModule->mBssSize); + s32 result = JKRResizeMemBlock(NULL, mModule, fixSize2 + mModule->bssSize); if (result < 0) { // "Module size (resize) failed\n" OSReport_Error("モジュールリサイズ(縮小)失敗\n"); } } else { - s32 result = JKRResizeMemBlock(NULL, mModule, fixSize2 + mModule->mBssSize); + s32 result = JKRResizeMemBlock(NULL, mModule, fixSize2 + mModule->bssSize); if (result > 0) { - BOOL linkResult = OSLinkFixed(mModule, fixSizePtr); + BOOL linkResult = OSLinkFixed(&mModule->info, (void*)fixSizePtr); if (linkResult == FALSE) { // "link failed\n" OSReport_Error("リンク失敗\n"); goto error; } } else { - void* bss = JKRAlloc(mModule->mBssSize, 0x20); + void* bss = JKRAlloc(mModule->bssSize, 0x20); if (bss == NULL) { // "BSS Memory allocation failure [%x]\n" - OSReport_Error("BSSメモリ確保失敗 [%x]\n", mModule->mBssSize); + OSReport_Error("BSSメモリ確保失敗 [%x]\n", mModule->bssSize); goto error; } mBss = bss; - BOOL linkResult = OSLinkFixed(mModule, (u32)bss); + BOOL linkResult = OSLinkFixed(&mModule->info, bss); if (linkResult == FALSE) { // "link failed\n" OSReport_Error("リンク失敗\n"); @@ -434,7 +429,7 @@ bool DynamicModuleControl::do_unlink() { OSTime time1 = OSGetTime(); ((void (*)())mModule->epilog)(); OSTime time2 = OSGetTime(); - BOOL unklink = OSUnlink(mModule); + BOOL unklink = OSUnlink(&mModule->info); OSTime time3 = OSGetTime(); if (unklink == FALSE) { // "Unlink failed mModule=%08x mBss=%08x\n" @@ -456,7 +451,7 @@ int DynamicModuleControl::getModuleSize() const { if (mBss != NULL) { JKRGetMemBlockSize(NULL, mBss); } - return size + mModule->mBssSize; + return size + mModule->bssSize; } else { return 0; } @@ -467,15 +462,15 @@ const char* DynamicModuleControl::getModuleTypeString() const { return strings[mResourceType & 3]; } -void ModuleProlog() { +extern "C" void ModuleProlog() { /* empty function */ } -void ModuleEpilog() { +extern "C" void ModuleEpilog() { /* empty function */ } -void ModuleUnresolved() { +extern "C" void ModuleUnresolved() { // "\nError: Unlinked function was called.\n" OSReport_Error("\nError: リンクされていない関数が呼び出されました.\n"); OSReport_Error("Address: Back Chain LR Save\n"); @@ -488,7 +483,7 @@ void ModuleUnresolved() { OSReport_Error("\n"); } -void ModuleConstructorsX(const VoidFunc* _ctors) { +extern "C" void ModuleConstructorsX(void (**_ctors)()) { JUT_ASSERT(850, _ctors); while (*_ctors != 0) { (**_ctors)(); @@ -496,7 +491,7 @@ void ModuleConstructorsX(const VoidFunc* _ctors) { } } -void ModuleDestructorsX(const VoidFunc* _dtors) { +extern "C" void ModuleDestructorsX(void (**_dtors)()) { JUT_ASSERT(864, _dtors); while (*_dtors != 0) { (**_dtors)(); diff --git a/src/JSystem/JUtility/JUTException.cpp b/src/JSystem/JUtility/JUTException.cpp index 3ca3d0936..a087dd41c 100644 --- a/src/JSystem/JUtility/JUTException.cpp +++ b/src/JSystem/JUtility/JUTException.cpp @@ -265,20 +265,20 @@ bool JUTException::searchPartialModule(u32 address, u32* module_id, u32* section } OSModuleInfo* module = *(OSModuleInfo**)0x800030C8; - for (; module != NULL; module = (OSModuleInfo*)module->mNext) { - OSSectionInfo* section = (OSSectionInfo*)module->info.sectionInfoOffset; - for (u32 i = 0; i < module->mNumSections; section++, i++) { - if (section->mSize != 0) { - u32 addr = section->mOffset & ~0x01; - if ((addr <= address) && (address < addr + section->mSize)) { + for (; module != NULL; module = (OSModuleInfo*)module->link.next) { + OSSectionInfo* section = (OSSectionInfo*)module->sectionInfoOffset; + for (u32 i = 0; i < module->numSections; section++, i++) { + if (section->size != 0) { + u32 addr = section->offset & ~0x01; + if ((addr <= address) && (address < addr + section->size)) { if (module_id) - *module_id = module->mId; + *module_id = module->id; if (section_id) *section_id = i; if (section_offset) *section_offset = address - addr; if (name_offset) - *name_offset = module->mModuleNameOffset; + *name_offset = module->nameOffset; return true; } } diff --git a/src/dolphin/gba/GBA.c b/src/dolphin/gba/GBA.c index f2dd2c8b8..2c90e981a 100644 --- a/src/dolphin/gba/GBA.c +++ b/src/dolphin/gba/GBA.c @@ -4,7 +4,7 @@ static GBASecParam SecParams[4]; GBAControl __GBA[4]; BOOL __GBAReset = FALSE; -static s32 OnReset(s32); +static BOOL OnReset(BOOL final); static OSResetFunctionInfo ResetFunctionInfo = {OnReset, 127}; @@ -87,7 +87,7 @@ s32 GBAReset(s32 chan, u8* status) { return __GBASync(chan); } -s32 OnReset(s32) { +BOOL OnReset(BOOL final) { __GBAReset = TRUE; return TRUE; } \ No newline at end of file diff --git a/src/dolphin/os/OS.c b/src/dolphin/os/OS.c new file mode 100644 index 000000000..e63e395bd --- /dev/null +++ b/src/dolphin/os/OS.c @@ -0,0 +1,661 @@ +// +// OS +// + +#include "dolphin/os/OS.h" +#include "dolphin/base/PPCArch.h" +// #include "dolphin/db.h" +#include "dolphin/pad/Pad.h" +#include "dolphin/dvd/dvdfs.h" +// #include "TRK_MINNOW_DOLPHIN/Os/dolphin/dolphin_trk.h" + +#define OS_BI2_DEBUG_ADDRESS 0x800000F4 +#define OS_BI2_DEBUGFLAG_OFFSET 0xC +#define PAD3_BUTTON_ADDR 0x800030E4 +#define OS_DVD_DEVICECODE 0x800030E6 +#define DEBUGFLAG_ADDR 0x800030E8 +#define OS_DEBUG_ADDRESS_2 0x800030E9 +#define DB_EXCEPTIONRET_OFFSET 0xC +#define DB_EXCEPTIONDEST_OFFSET 0x8 + +#define OS_EXCEPTIONTABLE_ADDR 0x3000 +#define OS_DBJUMPPOINT_ADDR 0x60 +#define OS_CURRENTCONTEXT_PADDR 0xC0 + +// +// External References: +// + +void _epilog(); + +static OSBootInfo* BootInfo; + +static volatile u32* BI2DebugFlag; + +static u32* BI2DebugFlagHolder; + +OSTime __OSStartTime; + +BOOL __OSInIPL; + +extern OSExceptionHandler* OSExceptionTable; +OSExceptionHandler* OSExceptionTable; + +extern BOOL AreWeInitialized; +BOOL AreWeInitialized; + +extern f64 ZeroPS; +f64 ZeroPS; + +extern f64 ZeroF; +f64 ZeroF; + +BOOL __OSIsGcam; + +asm void __OSFPRInit(void) { + // clang-format off + nofralloc + + mfmsr r3 + ori r3, r3, 0x2000 + mtmsr r3 + + mfspr r3, 0x398 + rlwinm. r3, r3, 3, 0x1f, 0x1f + beq skip_ps_init + + lis r3, ZeroPS@ha + addi r3, r3, ZeroPS@l + psq_l f0, 0(r3), 0, 0 + ps_mr f1, f0 + ps_mr f2, f0 + ps_mr f3, f0 + ps_mr f4, f0 + ps_mr f5, f0 + ps_mr f6, f0 + ps_mr f7, f0 + ps_mr f8, f0 + ps_mr f9, f0 + ps_mr f10, f0 + ps_mr f11, f0 + ps_mr f12, f0 + ps_mr f13, f0 + ps_mr f14, f0 + ps_mr f15, f0 + ps_mr f16, f0 + ps_mr f17, f0 + ps_mr f18, f0 + ps_mr f19, f0 + ps_mr f20, f0 + ps_mr f21, f0 + ps_mr f22, f0 + ps_mr f23, f0 + ps_mr f24, f0 + ps_mr f25, f0 + ps_mr f26, f0 + ps_mr f27, f0 + ps_mr f28, f0 + ps_mr f29, f0 + ps_mr f30, f0 + ps_mr f31, f0 + +skip_ps_init: + lfd f0, ZeroF(r13) + fmr f1, f0 + fmr f2, f0 + fmr f3, f0 + fmr f4, f0 + fmr f5, f0 + fmr f6, f0 + fmr f7, f0 + fmr f8, f0 + fmr f9, f0 + fmr f10, f0 + fmr f11, f0 + fmr f12, f0 + fmr f13, f0 + fmr f14, f0 + fmr f15, f0 + fmr f16, f0 + fmr f17, f0 + fmr f18, f0 + fmr f19, f0 + fmr f20, f0 + fmr f21, f0 + fmr f22, f0 + fmr f23, f0 + fmr f24, f0 + fmr f25, f0 + fmr f26, f0 + fmr f27, f0 + fmr f28, f0 + fmr f29, f0 + fmr f30, f0 + fmr f31, f0 + + mtfsf 0xff, f0 + blr + // clang-format on +} + +u32 OSGetConsoleType(void) { + if (BootInfo == NULL || BootInfo->console_type == 0) { + return OS_CONSOLE_ARTHUR; + } + + return BootInfo->console_type; +} + +static DVDDriveInfo DriveInfo; + +void* __OSSavedRegionStart; +void* __OSSavedRegionEnd; + +extern OSExecParams __OSRebootParams; + +static inline void ClearArena(void) { + BOOL var_r0; + if (OSGetResetCode() & 0x80000000) { + var_r0 = TRUE; + } else { + var_r0 = FALSE; + } + + if (!var_r0) { + memset(OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + + if (*(u32*)&__OSRebootParams.regionStart == 0U) { + memset(OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + + if ((u32)OSGetArenaLo() < *(u32*)&__OSRebootParams.regionStart) { + if ((u32)OSGetArenaHi() <= *(u32*)&__OSRebootParams.regionStart) { + memset((u32)OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + + memset(OSGetArenaLo(), 0U, *(u32*)&__OSRebootParams.regionStart - (u32)OSGetArenaLo()); + + if ((u32)OSGetArenaHi() > *(u32*)&__OSRebootParams.regionEnd) { + memset(*(u32*)&__OSRebootParams.regionEnd, 0, + (u32)OSGetArenaHi() - *(u32*)&__OSRebootParams.regionEnd); + } + } +} + +static void InquiryCallback(s32 result, DVDCommandBlock* block) { + switch (block->state) { + case 0: + __OSDeviceCode = (u16)(0x8000 | DriveInfo.device_code); + break; + default: + __OSDeviceCode = 1; + break; + } +} + +static u8 DriveBlock[48]; + +OSExecParams __OSRebootParams; + +static const char* __OSVersion = "<< Dolphin SDK - OS release build: Nov 10 2004 06:26:41 (0x2301) >>"; + +extern u8 __ArenaHi[]; +extern u8 __ArenaLo[]; +extern void* _stack_end; +extern char _db_stack_end[]; + +void OSInit(void) { + /* + Initializes the Dolphin operating system. + - most of the main operations get farmed out to other functions + - loading debug info and setting up heap bounds largely happen here + - a lot of OS reporting also gets controlled here + */ + + BI2Debug* DebugInfo; + void* debugArenaLo; + u32 inputConsoleType; + u32 tdev; + + if ((BOOL)AreWeInitialized == FALSE) { + AreWeInitialized = TRUE; + + // SYSTEM // + __OSStartTime = __OSGetSystemTime(); + OSDisableInterrupts(); + + __OSGetExecParams(&__OSRebootParams); + PPCMtmmcr0(0); + PPCMtmmcr1(0); + PPCMtpmc1(0); + PPCMtpmc2(0); + PPCMtpmc3(0); + PPCMtpmc4(0); + PPCDisableSpeculation(); + PPCSetFpNonIEEEMode(); + + // DEBUG // + BI2DebugFlag = 0; // debug flag from the DVD BI2 header + BootInfo = (OSBootInfo*)OS_BASE_CACHED; // set pointer to BootInfo + + __DVDLongFileNameFlag = + (u32)0; // flag to tell us whether we make it through the debug loading + + // time to grab a bunch of debug info from the DVD + // the address for where the BI2 debug info is, is stored at OS_BI2_DEBUG_ADDRESS + DebugInfo = (BI2Debug*)*((u32*)OS_BI2_DEBUG_ADDRESS); + + if (DebugInfo != NULL) { + BI2DebugFlag = &DebugInfo->debugFlag; // debug flag from DVD BI2 + __PADSpec = (u32)DebugInfo->padSpec; // some other info from DVD BI2 + *((u8*)DEBUGFLAG_ADDR) = (u8)*BI2DebugFlag; // store flag in mem + *((u8*)OS_DEBUG_ADDRESS_2) = (u8)__PADSpec; // store other info in mem + } else if (BootInfo->arena_hi) { + BI2DebugFlagHolder = + (u32*)*((u8*)DEBUGFLAG_ADDR); // grab whatever's stored at 0x800030E8 + BI2DebugFlag = (u32*)&BI2DebugFlagHolder; // flag is then address of flag holder + __PADSpec = (u32) * ((u8*)OS_DEBUG_ADDRESS_2); // pad spec is whatever's at 0x800030E9 + } + + __DVDLongFileNameFlag = 1; + + // HEAP // + OSSetArenaLo((BootInfo->arena_lo == NULL) ? __ArenaLo : BootInfo->arena_lo); + + // if the input arenaLo is null, and debug flag location exists (and flag is < 2), + // set arenaLo to just past the end of the db stack + if ((BootInfo->arena_lo == NULL) && (BI2DebugFlag != 0) && (*BI2DebugFlag < 2)) { + debugArenaLo = (char*)(((u32)_db_stack_end + 0x1f) & ~0x1f); + OSSetArenaLo(debugArenaLo); + } + + OSSetArenaHi((BootInfo->arena_hi == NULL) ? __ArenaHi : BootInfo->arena_hi); + + // OS INIT AND REPORT // + OSExceptionInit(); + __OSInitSystemCall(); + OSInitAlarm(); + __OSModuleInit(); + __OSInterruptInit(); + __OSSetInterruptHandler(OS_INTR_PI_RSW, (void*)__OSResetSWInterruptHandler); + __OSContextInit(); + __OSCacheInit(); + EXIInit(); + SIInit(); + __OSInitSram(); + __OSThreadInit(); + __OSInitAudioSystem(); + PPCMthid2(PPCMfhid2() & 0xBFFFFFFF); + if ((BOOL)__OSInIPL == FALSE) { + __OSInitMemoryProtection(); + } + + OSReport("\nDolphin OS\n"); + OSReport("Kernel built : %s %s\n", "Nov 10 2004", "06:26:41"); + OSReport("Console Type : "); + + if (BootInfo == NULL || (inputConsoleType = BootInfo->console_type) == 0) { + inputConsoleType = OS_CONSOLE_ARTHUR; // default console type + } else { + inputConsoleType = BootInfo->console_type; + } + + switch (inputConsoleType & 0xF0000000) { + case OS_CONSOLE_RETAIL: + OSReport("Retail %d\n", inputConsoleType); + break; + case OS_CONSOLE_DEVELOPMENT: + case OS_CONSOLE_TDEV: + switch (inputConsoleType & 0x0FFFFFFF) { + case OS_CONSOLE_EMULATOR: + OSReport("Mac Emulator\n"); + break; + case OS_CONSOLE_PC_EMULATOR: + OSReport("PC Emulator\n"); + break; + case OS_CONSOLE_ARTHUR: + OSReport("EPPC Arthur\n"); + break; + case OS_CONSOLE_MINNOW: + OSReport("EPPC Minnow\n"); + break; + default: + tdev = (u32)inputConsoleType & 0x0FFFFFFF; + OSReport("Development HW%d (%08x)\n", tdev - 3, inputConsoleType); + break; + } + break; + default: + OSReport("%08x\n", inputConsoleType); + break; + } + + OSReport("Memory %d MB\n", (u32)BootInfo->memory_size >> 0x14U); + OSReport("Arena : 0x%x - 0x%x\n", OSGetArenaLo(), OSGetArenaHi()); + OSRegisterVersion(__OSVersion); + + if (BI2DebugFlag && ((*BI2DebugFlag) >= 2)) { + EnableMetroTRKInterrupts(); + } + + ClearArena(); + OSEnableInterrupts(); + + if ((BOOL)__OSInIPL == FALSE) { + DVDInit(); + if ((BOOL)__OSIsGcam) { + __OSDeviceCode = 0x9000; + return; + } + DCInvalidateRange(&DriveInfo, sizeof(DriveInfo)); + DVDInquiryAsync((DVDCommandBlock*)&DriveBlock, &DriveInfo, InquiryCallback); + } + } +} + +static u32 __OSExceptionLocations[] = { + 0x00000100, // 0 System reset + 0x00000200, // 1 Machine check + 0x00000300, // 2 DSI - seg fault or DABR + 0x00000400, // 3 ISI + 0x00000500, // 4 External interrupt + 0x00000600, // 5 Alignment + 0x00000700, // 6 Program + 0x00000800, // 7 FP Unavailable + 0x00000900, // 8 Decrementer + 0x00000C00, // 9 System call + 0x00000D00, // 10 Trace + 0x00000F00, // 11 Performance monitor + 0x00001300, // 12 Instruction address breakpoint. + 0x00001400, // 13 System management interrupt + 0x00001700 // 14 Thermal interrupt +}; + +// dummy entry points to the OS Exception vector +void __OSEVStart(void); +void __OSDBINTSTART(void); +void __OSDBINTEND(void); +void __OSDBJUMPSTART(void); +void __OSDBJUMPEND(void); + +#define NOP 0x60000000 + +static void OSExceptionInit(void) { + __OSException exception; + void* destAddr; + + // These two vars help us change the exception number embedded + // in the exception handler code. + u32* opCodeAddr; + u32 oldOpCode; + + // Address range of the actual code to be copied. + u8* handlerStart; + u32 handlerSize; + + // Install the first level exception vector. + opCodeAddr = (u32*)__OSEVSetNumber; + oldOpCode = *opCodeAddr; + handlerStart = (u8*)__OSEVStart; + handlerSize = (u32)((u8*)__OSEVEnd - (u8*)__OSEVStart); + + // Install the DB integrator, only if we are the first OSInit to be run + destAddr = (void*)OSPhysicalToCached(OS_DBJUMPPOINT_ADDR); + if (*(u32*)destAddr == 0) // Lomem should be zero cleared only once by BS2 + { + DBPrintf("Installing OSDBIntegrator\n"); + memcpy(destAddr, (void*)__OSDBINTSTART, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + DCFlushRangeNoSync(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + __sync(); + ICInvalidateRange(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + } + + // Copy the right vector into the table + for (exception = 0; exception < 15; exception++) { + if (BI2DebugFlag && (*BI2DebugFlag >= 2) && __DBIsExceptionMarked(exception)) { + // this DBPrintf is suspicious. + DBPrintf(">>> OSINIT: exception %d commandeered by TRK\n", exception); + continue; + } + + // Modify the copy of code in text before transferring + // to the exception table. + *opCodeAddr = oldOpCode | exception; + + // Modify opcodes at __DBVECTOR if necessary + if (__DBIsExceptionMarked(exception)) { + DBPrintf(">>> OSINIT: exception %d vectored to debugger\n", exception); + memcpy((void*)__DBVECTOR, (void*)__OSDBJUMPSTART, + (u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART); + } else { + // make sure the opcodes are still nop + u32* ops = (u32*)__DBVECTOR; + int cb; + + for (cb = 0; cb < (u32)__OSDBJUMPEND - (u32)__OSDBJUMPSTART; cb += sizeof(u32)) { + *ops++ = NOP; + } + } + + // Install the modified handler. + destAddr = (void*)OSPhysicalToCached(__OSExceptionLocations[(u32)exception]); + memcpy(destAddr, handlerStart, handlerSize); + DCFlushRangeNoSync(destAddr, handlerSize); + __sync(); + ICInvalidateRange(destAddr, handlerSize); + } + + // initialize pointer to exception table + OSExceptionTable = OSPhysicalToCached(OS_EXCEPTIONTABLE_ADDR); + + // install default exception handlers + for (exception = 0; exception < 15; exception++) { + __OSSetExceptionHandler(exception, OSDefaultExceptionHandler); + } + + // restore the old opcode, so that we can re-start an application without + // downloading the text segments + *opCodeAddr = oldOpCode; + + DBPrintf("Exceptions initialized...\n"); +} + +asm void __OSDBIntegrator(void) { + // clang-format off + nofralloc + +entry __OSDBINTSTART + li r5, 0x40 + mflr r3 + stw r3, 0xc(r5) + lwz r3, 8(r5) + oris r3, r3, 0x8000 + mtlr r3 + li r3, 0x30 + mtmsr r3 + blr +entry __OSDBINTEND + // clang-format on +} + +asm void __OSDBJump(void){ + // clang-format off + nofralloc + +entry __OSDBJUMPSTART + bla 0x60 +entry __OSDBJUMPEND + // clang-format on +} + +OSExceptionHandler __OSSetExceptionHandler(__OSException exception, OSExceptionHandler handler) { + OSExceptionHandler old = OSExceptionTable[exception]; + OSExceptionTable[exception] = handler; + return old; +} + +OSExceptionHandler __OSGetExceptionHandler(__OSException exception) { + return OSExceptionTable[exception]; +} + +static asm void OSExceptionVector(void) { + // clang-format off + nofralloc + +entry __OSEVStart + // Save r4 into SPRG0 + mtsprg 0, r4 + + // Load current context physical address into r4 + lwz r4, OS_CURRENTCONTEXT_PADDR + + // Save r3 - r5 into the current context + stw r3, OS_CONTEXT_R3(r4) + mfsprg r3, 0 + stw r3, OS_CONTEXT_R4(r4) + stw r5, OS_CONTEXT_R5(r4) + + lhz r3, OS_CONTEXT_STATE(r4) + ori r3, r3, OS_CONTEXT_STATE_EXC + sth r3, OS_CONTEXT_STATE(r4) + + // Save misc registers + mfcr r3 + stw r3, OS_CONTEXT_CR(r4) + mflr r3 + stw r3, OS_CONTEXT_LR(r4) + mfctr r3 + stw r3, OS_CONTEXT_CTR(r4) + mfxer r3 + stw r3, OS_CONTEXT_XER(r4) + mfsrr0 r3 + stw r3, OS_CONTEXT_SRR0(r4) + mfsrr1 r3 + stw r3, OS_CONTEXT_SRR1(r4) + mr r5, r3 + +entry __DBVECTOR + nop + + // Set SRR1[IR|DR] to turn on address + // translation at the next RFI + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + // This lets us change the exception number based on the + // exception we're installing. +entry __OSEVSetNumber + li r3, 0 + + // Load current context virtual address into r4 + lwz r4, 0xd4(r0) + + // Check non-recoverable interrupt + rlwinm. r5, r5, 0, MSR_RI_BIT, MSR_RI_BIT + bne recoverable + lis r5, OSDefaultExceptionHandler@ha + addi r5, r5, OSDefaultExceptionHandler@l + mtsrr0 r5 + rfi + // NOT REACHED HERE + +recoverable: + // Locate exception handler. + rlwinm r5, r3, 2, 0x16, 0x1d // r5 contains exception*4 + lwz r5, OS_EXCEPTIONTABLE_ADDR(r5) + mtsrr0 r5 + + // Final state + // r3 - exception number + // r4 - pointer to context + // r5 - garbage + // srr0 - exception handler + // srr1 - address translation enabled, not yet recoverable + + rfi + // NOT REACHED HERE + // The handler will restore state + +entry __OSEVEnd + nop + // clang-format on +} + +static asm void OSDefaultExceptionHandler(register __OSException exception, + register OSContext* context) { + // clang-format off + nofralloc + + stw r0, 0(context) + stw r1, 4(context) + stw r2, 8(context) + stmw r6, 0x18(context) + mfspr r0, 0x391 + stw r0, 0x1a8(context) + mfspr r0, 0x392 + stw r0, 0x1ac(context) + mfspr r0, 0x393 + stw r0, 0x1b0(context) + mfspr r0, 0x394 + stw r0, 0x1b4(context) + mfspr r0, 0x395 + stw r0, 0x1b8(context) + mfspr r0, 0x396 + stw r0, 0x1bc(context) + mfspr r0, 0x397 + stw r0, 0x1c0(context) + + mfdsisr r5 + mfdar r6 + + stwu r1, -8(r1) + b __OSUnhandledException + // clang-format on +} + +asm void __OSPSInit(void){ + // clang-format off + nofralloc + + mflr r0 + stw r0, 4(r1) + stwu r1, -8(r1) + bl PPCMfhid2 + oris r3, r3, 0xa000 + bl PPCMthid2 + bl ICFlashInvalidate + sync + + li r3, 0 + mtspr 0x390, r3 + mtspr 0x391, r3 + mtspr 0x392, r3 + mtspr 0x393, r3 + mtspr 0x394, r3 + mtspr 0x395, r3 + mtspr 0x396, r3 + mtspr 0x397, r3 + + lwz r0, 0xc(r1) + addi r1, r1, 8 + mtlr r0 + blr + // clang-format on +} + +vu32 __DIRegs[16] : 0xCC006000; +#define DI_CONFIG_IDX 0x9 +#define DI_CONFIG_CONFIG_MASK 0xFF + +u32 __OSGetDIConfig(void) { + return (__DIRegs[DI_CONFIG_IDX] & DI_CONFIG_CONFIG_MASK); +} + +void OSRegisterVersion(const char* version) { + OSReport("%s\n", version); +} diff --git a/src/dolphin/os/OSAlarm.c b/src/dolphin/os/OSAlarm.c new file mode 100644 index 000000000..08808fd56 --- /dev/null +++ b/src/dolphin/os/OSAlarm.c @@ -0,0 +1,228 @@ +#include "dolphin/os/OSAlarm.h" +#include "dolphin/os/OS.h" + +static BOOL OnReset(BOOL final); +BOOL __DVDTestAlarm(OSAlarm* alarm); + +static OSResetFunctionInfo ResetFunctionInfo = { + OnReset, + 0xFFFFFFFF, +}; + +static OSAlarmQueue AlarmQueue; + +void OSInitAlarm(void) { + if (__OSGetExceptionHandler(8) != DecrementerExceptionHandler) { + AlarmQueue.head = AlarmQueue.tail = NULL; + __OSSetExceptionHandler(8, DecrementerExceptionHandler); + OSRegisterResetFunction(&ResetFunctionInfo); + } +} + +void OSCreateAlarm(OSAlarm* alarm) { + alarm->handler = NULL; + alarm->tag = 0; +} + +static inline SetTimer(OSAlarm* alarm) { + OSTime delta; + + delta = alarm->fire_time - __OSGetSystemTime(); + if (delta < 0) { + PPCMtdec(0); + } else if (delta < 0x80000000) { + PPCMtdec((u32)delta); + } else { + PPCMtdec(0x7fffffff); + } +} + +static void InsertAlarm(OSAlarm* alarm, OSTime fire, OSAlarmHandler handler) { + OSAlarm* next; + OSAlarm* prev; + + if (0 < alarm->period_time) { + OSTime time = __OSGetSystemTime(); + + fire = alarm->start_time; + if (alarm->start_time < time) { + fire += alarm->period_time * ((time - alarm->start_time) / alarm->period_time + 1); + } + } + + alarm->handler = handler; + alarm->fire_time = fire; + + for (next = AlarmQueue.head; next; next = next->link.next) { + if (next->fire_time <= fire) { + continue; + } + + alarm->link.prev = next->link.prev; + next->link.prev = alarm; + alarm->link.next = next; + prev = alarm->link.prev; + if (prev) { + prev->link.next = alarm; + } else { + AlarmQueue.head = alarm; + SetTimer(alarm); + } + return; + } + + alarm->link.next = 0; + prev = AlarmQueue.tail; + AlarmQueue.tail = alarm; + alarm->link.prev = prev; + + if (prev) { + prev->link.next = alarm; + } else { + AlarmQueue.head = AlarmQueue.tail = alarm; + SetTimer(alarm); + } +} + +void OSSetAlarm(OSAlarm* alarm, OSTime tick, OSAlarmHandler handler) { + BOOL enabled; + enabled = OSDisableInterrupts(); + alarm->period_time = 0; + InsertAlarm(alarm, __OSGetSystemTime() + tick, handler); + OSRestoreInterrupts(enabled); +} + +void OSSetPeriodicAlarm(OSAlarm* alarm, OSTime start, OSTime period, OSAlarmHandler handler) { + BOOL enabled; + enabled = OSDisableInterrupts(); + alarm->period_time = period; + alarm->start_time = __OSTimeToSystemTime(start); + InsertAlarm(alarm, 0, handler); + OSRestoreInterrupts(enabled); +} + +void OSCancelAlarm(OSAlarm* alarm) { + OSAlarm* next; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if (alarm->handler == 0) { + OSRestoreInterrupts(enabled); + return; + } + + next = alarm->link.next; + if (next == 0) { + AlarmQueue.tail = alarm->link.prev; + } else { + next->link.prev = alarm->link.prev; + } + if (alarm->link.prev) { + alarm->link.prev->link.next = next; + } else { + AlarmQueue.head = next; + if (next) { + SetTimer(next); + } + } + alarm->handler = 0; + + OSRestoreInterrupts(enabled); +} + +static void DecrementerExceptionCallback(register __OSException exception, + register OSContext* context) { + OSAlarm* alarm; + OSAlarm* next; + OSAlarmHandler handler; + OSTime time; + OSContext exceptionContext; + time = __OSGetSystemTime(); + alarm = AlarmQueue.head; + if (alarm == 0) { + OSLoadContext(context); + } + + if (time < alarm->fire_time) { + SetTimer(alarm); + OSLoadContext(context); + } + + next = alarm->link.next; + AlarmQueue.head = next; + if (next == 0) { + AlarmQueue.tail = 0; + } else { + next->link.prev = 0; + } + + handler = alarm->handler; + alarm->handler = 0; + if (0 < alarm->period_time) { + InsertAlarm(alarm, 0, handler); + } + + if (AlarmQueue.head) { + SetTimer(AlarmQueue.head); + } + + OSDisableScheduler(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + handler(alarm, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); +} + +static asm void DecrementerExceptionHandler(register __OSException exception, + register OSContext* context) { + // clang-format off + nofralloc + + stw r0, 0(context) + stw r1, 4(context) + stw r2, 8(context) + stmw r6, 0x18(context) + mfspr r0, 0x391 + stw r0, 0x1a8(context) + mfspr r0, 0x392 + stw r0, 0x1ac(context) + mfspr r0, 0x393 + stw r0, 0x1b0(context) + mfspr r0, 0x394 + stw r0, 0x1b4(context) + mfspr r0, 0x395 + stw r0, 0x1b8(context) + mfspr r0, 0x396 + stw r0, 0x1bc(context) + mfspr r0, 0x397 + stw r0, 0x1c0(context) + stwu r1, -8(r1) + b DecrementerExceptionCallback + // clang-format on +} + +static BOOL OnReset(BOOL final) { + OSAlarm* alarm; + OSAlarm* next; + + if (final != FALSE) { + alarm = AlarmQueue.head; + next = (alarm) ? alarm->link.next : NULL; + + while (alarm != NULL) { + if (__DVDTestAlarm(alarm) == FALSE) { + OSCancelAlarm(alarm); + } + + alarm = next; + next = (alarm) ? alarm->link.next : NULL; + } + } + + return TRUE; +} diff --git a/src/dolphin/os/OSAlloc.c b/src/dolphin/os/OSAlloc.c new file mode 100644 index 000000000..af668fe81 --- /dev/null +++ b/src/dolphin/os/OSAlloc.c @@ -0,0 +1,127 @@ +#include "dolphin/os/OSAlloc.h" + +static OSHeapCell* DLInsert(OSHeapCell* list, OSHeapCell* child) { + OSHeapCell* prev = NULL; + OSHeapCell* next = list; + + for (; next != NULL; prev = next, next = next->next) { + if ((char*)child <= (char*)next) { + break; + } + } + + child->next = next; + child->prev = prev; + + if (next != NULL) { + next->prev = child; + + if ((char*)child + child->size == (char*)next) { + child->size += next->size; + next = next->next; + child->next = next; + if (next != NULL) { + next->prev = child; + } + } + } + + if (prev != NULL) { + prev->next = child; + + if ((char*)prev + prev->size == (char*)child) { + prev->size += child->size; + prev->next = next; + if (next != NULL) { + next->prev = prev; + } + } + + return list; + } else { + return child; + } +} + +inline OSHeapCell* DLExtract(OSHeapCell* list, OSHeapCell* child) { + if (child->next != NULL) { + child->next->prev = child->prev; + } + + if (child->prev == NULL) { + return child->next; + } + + child->prev->next = child->next; + return list; +} + +static OSHeapDescriptor* HeapArray; + +void OSFreeToHeap(OSHeapHandle handle, void* ptr) { + OSHeapDescriptor* hd = &HeapArray[handle]; + OSHeapCell* cell = (OSHeapCell*)((char*)ptr - sizeof(OSHeapCell)); + hd->usedList = DLExtract(hd->usedList, cell); + hd->freeList = DLInsert(hd->freeList, cell); +} + +volatile s32 __OSCurrHeap = -1; + +s32 OSSetCurrentHeap(OSHeapHandle handle) { + s32 old = __OSCurrHeap; + __OSCurrHeap = handle; + return old; +} + +static s32 NumHeaps; + +static void* ArenaStart; + +static void* ArenaEnd; + +void* OSInitAlloc(void* lo, void* hi, s32 maxHeaps) { + u32 totalSize = maxHeaps * sizeof(OSHeapDescriptor); + int i; + + HeapArray = lo; + NumHeaps = maxHeaps; + + for (i = 0; i < NumHeaps; i++) { + OSHeapDescriptor* hd = &HeapArray[i]; + hd->size = -1; + + hd->freeList = hd->usedList = NULL; + } + + __OSCurrHeap = -1; + + lo = (u8*)HeapArray + totalSize; + lo = OSRoundUpPtr(lo, 0x20); + + ArenaStart = lo; + ArenaEnd = OSRoundDownPtr(hi, 0x20); + + return ArenaStart; +} + +OSHeapHandle OSCreateHeap(void* start, void* end) { + int i; + OSHeapCell* cell = OSRoundUpPtr(start, 0x20); + end = OSRoundDownPtr(end, 0x20); + + for (i = 0; i < NumHeaps; i++) { + OSHeapDescriptor* hd = &HeapArray[i]; + + if (hd->size < 0) { + hd->size = (u8*)end - (u8*)cell; + cell->prev = NULL; + cell->next = NULL; + cell->size = hd->size; + hd->freeList = cell; + hd->usedList = NULL; + return i; + } + } + + return -1; +} diff --git a/src/dolphin/os/OSArena.c b/src/dolphin/os/OSArena.c new file mode 100644 index 000000000..089262a8f --- /dev/null +++ b/src/dolphin/os/OSArena.c @@ -0,0 +1,31 @@ +#include "dolphin/os/OSArena.h" +#include "dolphin/os/OSAlloc.h" + +static void* __OSArenaHi; + +void* OSGetArenaHi(void) { + return __OSArenaHi; +} + +static void* __OSArenaLo = (void*)0xFFFFFFFF; + +void* OSGetArenaLo(void) { + return __OSArenaLo; +} + +void OSSetArenaHi(void* hi) { + __OSArenaHi = hi; +} + +void OSSetArenaLo(void* lo) { + __OSArenaLo = lo; +} + +void* OSAllocFromArenaLo(u32 size, s32 alignment) { + u8* blk_start = OSRoundUpPtr(__OSArenaLo, alignment); + u8* blk_end = blk_start + size; + blk_end = OSRoundUpPtr(blk_end, alignment); + + __OSArenaLo = blk_end; + return blk_start; +} diff --git a/src/dolphin/os/OSAudioSystem.c b/src/dolphin/os/OSAudioSystem.c new file mode 100644 index 000000000..404cf22e9 --- /dev/null +++ b/src/dolphin/os/OSAudioSystem.c @@ -0,0 +1,105 @@ +#include "dolphin/os/OSAudioSystem.h" +#include "dolphin/dsp.h" +#include "string.h" + +static u8 DSPInitCode[128] = { + 0x02, 0x9F, 0x00, 0x10, 0x02, 0x9F, 0x00, 0x33, 0x02, 0x9F, 0x00, 0x34, 0x02, 0x9F, 0x00, 0x35, + 0x02, 0x9F, 0x00, 0x36, 0x02, 0x9F, 0x00, 0x37, 0x02, 0x9F, 0x00, 0x38, 0x02, 0x9F, 0x00, 0x39, + 0x12, 0x06, 0x12, 0x03, 0x12, 0x04, 0x12, 0x05, 0x00, 0x80, 0x80, 0x00, 0x00, 0x88, 0xFF, 0xFF, + 0x00, 0x84, 0x10, 0x00, 0x00, 0x64, 0x00, 0x1D, 0x02, 0x18, 0x00, 0x00, 0x81, 0x00, 0x1C, 0x1E, + 0x00, 0x44, 0x1B, 0x1E, 0x00, 0x84, 0x08, 0x00, 0x00, 0x64, 0x00, 0x27, 0x19, 0x1E, 0x00, 0x00, + 0x00, 0xDE, 0xFF, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x28, 0x16, 0xFC, 0x00, 0x54, + 0x16, 0xFD, 0x43, 0x48, 0x00, 0x21, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, + 0x02, 0xFF, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#define __DSPWorkBuffer (void*)0x81000000 + +void __OSInitAudioSystem(void) { + u32 r28; + u16 r3; + + u32 padding; + + memcpy((void*)((u8*)OSGetArenaHi() - 128), __DSPWorkBuffer, 128); + memcpy(__DSPWorkBuffer, (void*)DSPInitCode, 128); + + DCFlushRange(__DSPWorkBuffer, 128); + + __DSPRegs[9] = 0x43; + __DSPRegs[5] = 0x8AC; + __DSPRegs[5] |= 1; + while (__DSPRegs[5] & 1) + ; + __DSPRegs[0] = 0; + while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000) + ; + *(u32*)&__DSPRegs[16] = 0x1000000; + *(u32*)&__DSPRegs[18] = 0; + *(u32*)&__DSPRegs[20] = 0x20; + + r3 = __DSPRegs[5]; + while (!(r3 & 0x20)) + r3 = __DSPRegs[5]; + __DSPRegs[5] = r3; + + r28 = OSGetTick(); + while ((s32)(OSGetTick() - r28) < 0x892) + ; + + *(u32*)&__DSPRegs[16] = 0x1000000; + *(u32*)&__DSPRegs[18] = 0; + *(u32*)&__DSPRegs[20] = 0x20; + + r3 = __DSPRegs[5]; + while (!(r3 & 0x20)) + r3 = __DSPRegs[5]; + __DSPRegs[5] = r3; + + __DSPRegs[5] &= ~0x800; + while ((__DSPRegs[5]) & 0x400) + ; + __DSPRegs[5] &= ~4; + + r3 = __DSPRegs[2]; + + while (!(r3 & 0x8000)) + r3 = __DSPRegs[2]; + + (void)__DSPRegs[3]; + r3 != 42069; + __DSPRegs[5] |= 4; + __DSPRegs[5] = 0x8AC; + __DSPRegs[5] |= 1; + while (__DSPRegs[5] & 1) + ; + memcpy(__DSPWorkBuffer, (void*)((u8*)OSGetArenaHi() - 128), 128); +} + +void __OSStopAudioSystem(void) { + u32 r28; + +#define waitUntil(load, mask) \ + r28 = (load); \ + while (r28 & (mask)) { \ + r28 = (load); \ + } + + __DSPRegs[5] = 0x804; + r28 = __DSPRegs[27]; + __DSPRegs[27] = r28 & ~0x8000; + waitUntil(__DSPRegs[5], 0x400); + waitUntil(__DSPRegs[5], 0x200); + __DSPRegs[5] = 0x8ac; + __DSPRegs[0] = 0; + + while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000) + ; + r28 = OSGetTick(); + while ((s32)(OSGetTick() - r28) < 0x2c) + ; + __DSPRegs[5] |= 1; + waitUntil(__DSPRegs[5], 0x001); + +#undef waitUntil +} diff --git a/src/dolphin/os/OSCache.c b/src/dolphin/os/OSCache.c new file mode 100644 index 000000000..81a28e465 --- /dev/null +++ b/src/dolphin/os/OSCache.c @@ -0,0 +1,432 @@ +#include "dolphin/os/OSCache.h" +#include "dolphin/base/PPCArch.h" +// #include "dolphin/db.h" +#include "dolphin/os/OS.h" + +static asm void DCEnable(void) { + // clang-format off + nofralloc + + sync + mfspr r3, 0x3F0 + ori r3, r3, 0x4000 + mtspr 0x3F0, r3 + + blr + // clang-format on +} + +asm void DCInvalidateRange(register void* start, register u32 nBytes) { + // clang-format off + nofralloc + + cmplwi nBytes, 0 + blelr + + clrlwi r5, start, 0x1B + add nBytes, nBytes, r5 + addi nBytes, nBytes, 0x1F + srwi nBytes, nBytes, 5 + mtctr nBytes + +do_invalidate: + dcbi 0, start + addi start, start, 0x20 + bdnz do_invalidate + + blr + // clang-format on +} + +asm void DCFlushRange(register void* start, register u32 nBytes) { + // clang-format off + nofralloc + + cmplwi nBytes, 0 + blelr + + clrlwi r5, start, 0x1B + add nBytes, nBytes, r5 + addi nBytes, nBytes, 0x1F + srwi nBytes, nBytes, 5 + mtctr nBytes + +do_flush: + dcbf 0, start + addi start, start, 0x20 + bdnz do_flush + sc + + blr + // clang-format on +} + +asm void DCStoreRange(register void* start, register u32 nBytes) { + // clang-format off + nofralloc + + cmplwi nBytes, 0 + blelr + + clrlwi r5, start, 0x1B + add nBytes, nBytes, r5 + addi nBytes, nBytes, 0x1F + srwi nBytes, nBytes, 5 + mtctr nBytes + +do_store: + dcbst 0, start + addi start, start, 0x20 + bdnz do_store + sc + + blr + // clang-format on +} + +asm void DCFlushRangeNoSync(register void* start, register u32 nBytes) { + // clang-format off + nofralloc + + cmplwi nBytes, 0 + blelr + + clrlwi r5, start, 0x1B + add nBytes, nBytes, r5 + addi nBytes, nBytes, 0x1F + srwi nBytes, nBytes, 5 + mtctr nBytes + +do_flush: + dcbf 0, start + addi start, start, 0x20 + bdnz do_flush + + blr + // clang-format on +} + +asm void DCStoreRangeNoSync(register void* start, register u32 nBytes) { + // clang-format off + nofralloc + + cmplwi nBytes, 0 + blelr + + clrlwi r5, start, 0x1B + add nBytes, nBytes, r5 + addi nBytes, nBytes, 0x1F + srwi nBytes, nBytes, 5 + mtctr nBytes + +do_store: + dcbst 0, start + addi start, start, 0x20 + bdnz do_store + + blr + // clang-format on +} + +asm void DCZeroRange(register void* start, register u32 nBytes) { + // clang-format off + nofralloc + + cmplwi nBytes, 0 + blelr + + clrlwi r5, start, 0x1B + add nBytes, nBytes, r5 + addi nBytes, nBytes, 0x1F + srwi nBytes, nBytes, 5 + mtctr nBytes + +do_zero: + dcbz 0, start + addi start, start, 0x20 + bdnz do_zero + + blr + // clang-format on +} + +asm void ICInvalidateRange(register void* start, register u32 nBytes) { + // clang-format off + nofralloc + + cmplwi nBytes, 0 + blelr + + clrlwi r5, start, 0x1B + add nBytes, nBytes, r5 + addi nBytes, nBytes, 0x1F + srwi nBytes, nBytes, 5 + mtctr nBytes + +do_invalidate: + icbi 0, start + addi start, start, 0x20 + bdnz do_invalidate + + sync + isync + + blr + // clang-format on +} + +asm void ICFlashInvalidate(void) { + // clang-format off + nofralloc + + mfspr r3, 0x3F0 + ori r3, r3, 0x800 + mtspr 0x3F0, r3 + + blr + // clang-format on +} + +static asm void ICEnable(void) { + // clang-format off + nofralloc + + isync + mfspr r3, 0x3F0 + ori r3, r3, 0x8000 + mtspr 0x3F0, r3 + + blr + // clang-format on +} + +asm void __LCEnable(void) { + // clang-format off + nofralloc + + mfmsr r5 + ori r5, r5, 0x1000 + mtmsr r5 + + lis r3, 0x8000 + li r4, 0x400 + mtctr r4 + +do_store: + dcbt 0, r3 + dcbst 0, r3 + addi r3, r3, 0x20 + bdnz do_store + + mfspr r4, 0x398 + oris r4, r4, 0x100F + mtspr 0x398, r4 + + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + lis r3, 0xE000 + ori r3, r3, 0x0002 + mtdbatl 3, r3 + ori r3, r3, 0x1FE + mtdbatu 3, r3 + isync + + lis r3, 0xE000 + li r6, 0x200 + mtctr r6 + li r6, 0 +do_load: + dcbz_l r6, r3 + addi r3, r3, 0x0020 + bdnz do_load + + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + blr + // clang-format on +} + +void LCEnable(void) { + BOOL interrupt = OSDisableInterrupts(); + __LCEnable(); + OSRestoreInterrupts(interrupt); +} + +asm void LCDisable(void) { + // clang-format off + nofralloc + + lis r3, 0xE000 + li r4, 0x200 + mtctr r4 +do_invalidate: + dcbi 0, r3 + addi r3, r3, 0x20 + bdnz do_invalidate + + mfspr r4, 0x398 + rlwinm r4, r4, 0, 4, 2 + mtspr 0x398, r4 + + blr + // clang-format on +} + +static asm void LCStoreBlocks(register void* destAddr, register void* srcAddr, + register u32 blockNum){ + // clang-format off + nofralloc + + rlwinm r6, blockNum, 0x1E, 0x1B, 0x1F + clrlwi destAddr, destAddr, 4 + or r6, r6, destAddr + mtspr 0x39A, r6 + rlwinm r6, blockNum, 2, 0x1C, 0x1D + or r6, r6, srcAddr + ori r6, r6, 2 + mtspr 0x39B, r6 + + blr + // clang-format on +} /* 8033B838-8033B8E4 336178 00AC+00 0/0 0/0 3/3 .text LCStoreData */ +u32 LCStoreData(void* destAddr, void* srcAddr, u32 nBytes) { + u32 blocks = (nBytes + 31) / 32; + u32 ret = (blocks + 127) / 128; + + while (blocks > 0) { + if (blocks < 128) { + LCStoreBlocks(destAddr, srcAddr, blocks); + blocks = 0; + } else { + LCStoreBlocks(destAddr, srcAddr, 0); + blocks -= 128; + + destAddr = (char*)destAddr + 0x1000; + srcAddr = (char*)srcAddr + 0x1000; + } + } + + return ret; +} + +asm void LCQueueWait(register u32 len) { + // clang-format off + nofralloc + + mfspr r4, 0x398 + rlwinm r4, r4, 8, 28, 31 + cmpw r4, len + bgt LCQueueWait + + blr + // clang-format on +} + +static void L2Disable(void) { + __sync(); + PPCMtl2cr(PPCMfl2cr() & ~0x80000000); + __sync(); +} + +void L2GlobalInvalidate(void) { + L2Disable(); + PPCMtl2cr(PPCMfl2cr() | 0x00200000); + while (PPCMfl2cr() & 0x00000001u) + ; + PPCMtl2cr(PPCMfl2cr() & ~0x00200000); + while (PPCMfl2cr() & 0x00000001u) { + DBPrintf(">>> L2 INVALIDATE : SHOULD NEVER HAPPEN\n"); + } +} + +void DMAErrorHandler(u16 error, OSContext* context, ...) { + u32 hid2 = PPCMfhid2(); + + OSReport("Machine check received\n"); + OSReport("HID2 = 0x%x SRR1 = 0x%x\n", hid2, context->srr1); + if (!(hid2 & (HID2_DCHERR | HID2_DNCERR | HID2_DCMERR | HID2_DQOERR)) || + !(context->srr1 & SRR1_DMA_BIT)) { + OSReport("Machine check was not DMA/locked cache related\n"); + OSDumpContext(context); + PPCHalt(); + } + + OSReport("DMAErrorHandler(): An error occurred while processing DMA.\n"); + OSReport("The following errors have been detected and cleared :\n"); + + if (hid2 & HID2_DCHERR) { + OSReport("\t- Requested a locked cache tag that was already in the cache\n"); + } + + if (hid2 & HID2_DNCERR) { + OSReport("\t- DMA attempted to access normal cache\n"); + } + + if (hid2 & HID2_DCMERR) { + OSReport("\t- DMA missed in data cache\n"); + } + + if (hid2 & HID2_DQOERR) { + OSReport("\t- DMA queue overflowed\n"); + } + + // write hid2 back to clear the error bits + PPCMthid2(hid2); +} + +static void L2Init(void) { + u32 oldMSR; + oldMSR = PPCMfmsr(); + __sync(); + PPCMtmsr(MSR_IR | MSR_DR); + __sync(); + L2Disable(); + L2GlobalInvalidate(); + PPCMtmsr(oldMSR); +} + +void L2Enable(void) { + PPCMtl2cr((PPCMfl2cr() | L2CR_L2E) & ~L2CR_L2I); +} + +void __OSCacheInit() { + if (!(PPCMfhid0() & HID0_ICE)) { + ICEnable(); + DBPrintf("L1 i-caches initialized\n"); + } + if (!(PPCMfhid0() & HID0_DCE)) { + DCEnable(); + DBPrintf("L1 d-caches initialized\n"); + } + + if (!(PPCMfl2cr() & L2CR_L2E)) { + L2Init(); + L2Enable(); + DBPrintf("L2 cache initialized\n"); + } + + OSSetErrorHandler(OS_ERROR_MACHINE_CHECK, DMAErrorHandler); + DBPrintf("Locked cache machine check handler installed\n"); +} diff --git a/src/dolphin/os/OSContext.c b/src/dolphin/os/OSContext.c new file mode 100644 index 000000000..9c9b75095 --- /dev/null +++ b/src/dolphin/os/OSContext.c @@ -0,0 +1,611 @@ +#include "dolphin/os/OSContext.h" +// #include "dolphin/db.h" +#include "dolphin/os/OS.h" + +volatile OSContext* __OSCurrentContext : (OS_BASE_CACHED | 0x00D4); +volatile OSContext* __OSFPUContext : (OS_BASE_CACHED | 0x00D8); + +asm void __OSLoadFPUContext(void) { + // clang-format off + nofralloc + + lhz r5, 0x1A2(r4) + clrlwi. r5, r5, 0x1f + beq exit + + lfd f0, 0x190(r4) + mtfsf 0xFF, f0 + mfspr r5, 0x398 + rlwinm. r5, r5, 3, 0x1F, 0x1F + beq load_fprs + + psq_l f0, 0x1C8(r4), 0, 0 + psq_l f1, 0x1D0(r4), 0, 0 + psq_l f2, 0x1D8(r4), 0, 0 + psq_l f3, 0x1E0(r4), 0, 0 + psq_l f4, 0x1E8(r4), 0, 0 + psq_l f5, 0x1F0(r4), 0, 0 + psq_l f6, 0x1F8(r4), 0, 0 + psq_l f7, 0x200(r4), 0, 0 + psq_l f8, 0x208(r4), 0, 0 + psq_l f9, 0x210(r4), 0, 0 + psq_l f10, 0x218(r4), 0, 0 + psq_l f11, 0x220(r4), 0, 0 + psq_l f12, 0x228(r4), 0, 0 + psq_l f13, 0x230(r4), 0, 0 + psq_l f14, 0x238(r4), 0, 0 + psq_l f15, 0x240(r4), 0, 0 + psq_l f16, 0x248(r4), 0, 0 + psq_l f17, 0x250(r4), 0, 0 + psq_l f18, 0x258(r4), 0, 0 + psq_l f19, 0x260(r4), 0, 0 + psq_l f20, 0x268(r4), 0, 0 + psq_l f21, 0x270(r4), 0, 0 + psq_l f22, 0x278(r4), 0, 0 + psq_l f23, 0x280(r4), 0, 0 + psq_l f24, 0x288(r4), 0, 0 + psq_l f25, 0x290(r4), 0, 0 + psq_l f26, 0x298(r4), 0, 0 + psq_l f27, 0x2A0(r4), 0, 0 + psq_l f28, 0x2A8(r4), 0, 0 + psq_l f29, 0x2B0(r4), 0, 0 + psq_l f30, 0x2B8(r4), 0, 0 + psq_l f31, 0x2C0(r4), 0, 0 + +load_fprs: + lfd f0, 0x90(r4) + lfd f1, 0x98(r4) + lfd f2, 0xA0(r4) + lfd f3, 0xA8(r4) + lfd f4, 0xB0(r4) + lfd f5, 0xB8(r4) + lfd f6, 0xC0(r4) + lfd f7, 0xC8(r4) + lfd f8, 0xD0(r4) + lfd f9, 0xD8(r4) + lfd f10, 0xE0(r4) + lfd f11, 0xE8(r4) + lfd f12, 0xF0(r4) + lfd f13, 0xF8(r4) + lfd f14, 0x100(r4) + lfd f15, 0x108(r4) + lfd f16, 0x110(r4) + lfd f17, 0x118(r4) + lfd f18, 0x120(r4) + lfd f19, 0x128(r4) + lfd f20, 0x130(r4) + lfd f21, 0x138(r4) + lfd f22, 0x140(r4) + lfd f23, 0x148(r4) + lfd f24, 0x150(r4) + lfd f25, 0x158(r4) + lfd f26, 0x160(r4) + lfd f27, 0x168(r4) + lfd f28, 0x170(r4) + lfd f29, 0x178(r4) + lfd f30, 0x180(r4) + lfd f31, 0x188(r4) + +exit: + blr + // clang-format on +} + +asm void __OSSaveFPUContext(s32 unused0, s32 unused1, register OSContext* context) { + // clang-format off + nofralloc + + lhz r3, 0x1A2(context) + ori r3, r3, 1 + sth r3, 0x1A2(context) + + stfd f0, 0x90(context) + stfd f1, 0x98(context) + stfd f2, 0xa0(context) + stfd f3, 0xa8(context) + stfd f4, 0xb0(context) + stfd f5, 0xb8(context) + stfd f6, 0xc0(context) + stfd f7, 0xc8(context) + stfd f8, 0xd0(context) + stfd f9, 0xd8(context) + stfd f10, 0xe0(context) + stfd f11, 0xe8(context) + stfd f12, 0xf0(context) + stfd f13, 0xf8(context) + stfd f14, 0x100(context) + stfd f15, 0x108(context) + stfd f16, 0x110(context) + stfd f17, 0x118(context) + stfd f18, 0x120(context) + stfd f19, 0x128(context) + stfd f20, 0x130(context) + stfd f21, 0x138(context) + stfd f22, 0x140(context) + stfd f23, 0x148(context) + stfd f24, 0x150(context) + stfd f25, 0x158(context) + stfd f26, 0x160(context) + stfd f27, 0x168(context) + stfd f28, 0x170(context) + stfd f29, 0x178(context) + stfd f30, 0x180(context) + stfd f31, 0x188(context) + + mffs f0 + stfd f0, 0x190(context) + lfd f0, 0x90(context) + mfspr r3, 0x398 + rlwinm. r3, r3, 3, 0x1f, 0x1f + beq exit + + psq_st f0, 456(context), 0, 0 + psq_st f1, 464(context), 0, 0 + psq_st f2, 472(context), 0, 0 + psq_st f3, 480(context), 0, 0 + psq_st f4, 488(context), 0, 0 + psq_st f5, 496(context), 0, 0 + psq_st f6, 504(context), 0, 0 + psq_st f7, 512(context), 0, 0 + psq_st f8, 520(context), 0, 0 + psq_st f9, 528(context), 0, 0 + psq_st f10, 536(context), 0, 0 + psq_st f11, 544(context), 0, 0 + psq_st f12, 552(context), 0, 0 + psq_st f13, 560(context), 0, 0 + psq_st f14, 568(context), 0, 0 + psq_st f15, 576(context), 0, 0 + psq_st f16, 584(context), 0, 0 + psq_st f17, 592(context), 0, 0 + psq_st f18, 600(context), 0, 0 + psq_st f19, 608(context), 0, 0 + psq_st f20, 616(context), 0, 0 + psq_st f21, 624(context), 0, 0 + psq_st f22, 632(context), 0, 0 + psq_st f23, 640(context), 0, 0 + psq_st f24, 648(context), 0, 0 + psq_st f25, 656(context), 0, 0 + psq_st f26, 664(context), 0, 0 + psq_st f27, 672(context), 0, 0 + psq_st f28, 680(context), 0, 0 + psq_st f29, 688(context), 0, 0 + psq_st f30, 696(context), 0, 0 + psq_st f31, 704(context), 0, 0 + +exit: + blr + // clang-format on +} + +asm void OSSaveFPUContext(register OSContext* context) { + // clang-format off + nofralloc + + addi r5, context, 0 + b __OSSaveFPUContext + // clang-format on +} + +asm void OSSetCurrentContext(register OSContext* context) { + // clang-format off + nofralloc + + lis r4, OS_CURRENT_CONTEXT@ha + stw context, OS_CURRENT_CONTEXT@l(r4) + clrlwi r5, context, 2 + stw r5, 0xc0(r4) + lwz r5, 0xd8(r4) + cmpw r5, context + bne lbl_800EE9AC + lwz r6, 0x19c(context) + ori r6, r6, 0x2000 + stw r6, 0x19c(context) + mfmsr r6 + ori r6, r6, 2 + mtmsr r6 + blr + +lbl_800EE9AC: + lwz r6, 0x19c(context) + rlwinm r6, r6, 0, 0x13, 0x11 + stw r6, 0x19c(context) + mfmsr r6 + rlwinm r6, r6, 0, 0x13, 0x11 + ori r6, r6, 2 + mtmsr r6 + isync + blr + // clang-format on +} + +OSContext* OSGetCurrentContext(void) { + return OS_CURRENT_CONTEXT; +} + +asm u32 OSSaveContext(register OSContext* context) { + // clang-format off + nofralloc + + stmw r13, 0x34(context) + + mfspr r0, GQR1 + stw r0, 0x1a8(context) + mfspr r0, GQR2 + stw r0, 0x1ac(context) + mfspr r0, GQR3 + stw r0, 0x1b0(context) + mfspr r0, GQR4 + stw r0, 0x1b4(context) + mfspr r0, GQR5 + stw r0, 0x1b8(context) + mfspr r0, GQR6 + stw r0, 0x1bc(context) + mfspr r0, GQR7 + stw r0, 0x1c0(context) + + mfcr r0 + stw r0, 0x80(context) + mflr r0 + stw r0, 0x84(context) + stw r0, 0x198(context) + mfmsr r0 + stw r0, 0x19c(context) + mfctr r0 + stw r0, 0x88(context) + mfxer r0 + stw r0, 0x8c(context) + + stw r1, 4(context) + stw r2, 8(context) + + li r0, 1 + stw r0, 0xc(context) + + li r3, 0 + blr + // clang-format on +} + +asm void OSLoadContext(register OSContext* context) { + // clang-format off + nofralloc + + lis r4, OSDisableInterrupts@ha + lwz r6, 0x198(context) + addi r5, r4, OSDisableInterrupts@l + cmplw r6, r5 + ble srr0_not_in_disableintr + lis r4, __RAS_OSDisableInterrupts_end@ha + addi r0, r4, __RAS_OSDisableInterrupts_end@l + cmplw r6, r0 + bge srr0_not_in_disableintr + stw r5, 0x198(context) + +srr0_not_in_disableintr: + lwz r0, 0(context) + lwz r1, 4(context) + lwz r2, 8(context) + lhz r4, 0x1a2(context) + rlwinm. r5, r4, 0, 0x1e, 0x1e + beq load_saved_gprs + rlwinm r4, r4, 0, 0x1f, 0x1d + sth r4, 0x1a2(context) + lmw r5, 0x14(context) + b load_special_regs + +load_saved_gprs: + lmw r13, 0x34(context) + +load_special_regs: + lwz r4, 0x1a8(context) + mtspr 0x391, r4 + lwz r4, 0x1ac(context) + mtspr 0x392, r4 + lwz r4, 0x1b0(context) + mtspr 0x393, r4 + lwz r4, 0x1b4(context) + mtspr 0x394, r4 + lwz r4, 0x1b8(context) + mtspr 0x395, r4 + lwz r4, 0x1bc(context) + mtspr 0x396, r4 + lwz r4, 0x1c0(context) + mtspr 0x397, r4 + lwz r4, 0x80(context) + mtcrf 0xff, r4 + lwz r4, 0x84(context) + mtlr r4 + lwz r4, 0x88(context) + mtctr r4 + lwz r4, 0x8c(context) + mtxer r4 + mfmsr r4 + rlwinm r4, r4, 0, 0x11, 0xf + rlwinm r4, r4, 0, 0x1f, 0x1d + mtmsr r4 + lwz r4, 0x198(context) + mtspr 0x1a, r4 + lwz r4, 0x19c(context) + mtspr 0x1b, r4 + lwz r4, 0x10(context) + lwz context, 0xc(context) + rfi + // clang-format on +} + +asm u8* OSGetStackPointer(void) { + // clang-format off + nofralloc + + mr r3, r1 + blr + // clang-format on +} + +void OSClearContext(OSContext* context) { + context->mode = 0; + context->state = 0; + + if (context == OS_CURRENT_FPU_CONTEXT) { + OS_CURRENT_FPU_CONTEXT = NULL; + } +} + +asm void OSInitContext(register OSContext* context, register u32 srr0, register u32 stack) { + // clang-format off + nofralloc + + stw srr0, 0x198(context) + stw stack, 4(context) + li r11, 0 + ori r11, r11, 0x9032 + stw r11, 0x19c(context) + li r0, 0 + stw r0, 0x80(context) + stw r0, 0x8c(context) + stw r2, 8(context) + stw r13, 0x34(context) + stw r0, 0xc(context) + stw r0, 0x10(context) + stw r0, 0x14(context) + stw r0, 0x18(context) + stw r0, 0x1c(context) + stw r0, 0x20(context) + stw r0, 0x24(context) + stw r0, 0x28(context) + stw r0, 0x2c(context) + stw r0, 0x30(context) + stw r0, 0x38(context) + stw r0, 0x3c(context) + stw r0, 0x40(context) + stw r0, 0x44(context) + stw r0, 0x48(context) + stw r0, 0x4c(context) + stw r0, 0x50(context) + stw r0, 0x54(context) + stw r0, 0x58(context) + stw r0, 0x5c(context) + stw r0, 0x60(context) + stw r0, 0x64(context) + stw r0, 0x68(context) + stw r0, 0x6c(context) + stw r0, 0x70(context) + stw r0, 0x74(context) + stw r0, 0x78(context) + stw r0, 0x7c(context) + stw r0, 0x1a4(context) + stw r0, 0x1a8(context) + stw r0, 0x1ac(context) + stw r0, 0x1b0(context) + stw r0, 0x1b4(context) + stw r0, 0x1b8(context) + stw r0, 0x1bc(context) + stw r0, 0x1c0(context) + + b OSClearContext + // clang-format on +} + +// inline duplicates for OSDumpContext to match +// maybe need to change inlining compiler flag for better match? +inline void i_OSClearContext(OSContext* context) { + context->mode = 0; + context->state = 0; + + if (context == OS_CURRENT_FPU_CONTEXT) { + OS_CURRENT_FPU_CONTEXT = NULL; + } +} + +inline OSContext* i_OSGetCurrentContext(void) { + return OS_CURRENT_CONTEXT; +} + +void OSDumpContext(OSContext* context) { + u32 i; + u32* p; + + OSReport("------------------------- Context 0x%08x -------------------------\n", context); + + for (i = 0; i < 16; ++i) { + OSReport("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", i, context->gpr[i], + context->gpr[i], i + 16, context->gpr[i + 16], context->gpr[i + 16]); + } + + OSReport("LR = 0x%08x CR = 0x%08x\n", context->lr, context->cr); + OSReport("SRR0 = 0x%08x SRR1 = 0x%08x\n", context->srr0, context->srr1); + + OSReport("\nGQRs----------\n"); + for (i = 0; i < 4; ++i) { + OSReport("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", i, context->gqr[i], i + 4, + context->gqr[i + 4]); + } + + if (context->state & OS_CONTEXT_STATE_FPSAVED) { + OSContext* currentContext; + OSContext fpuContext; + BOOL enabled; + + enabled = OSDisableInterrupts(); + currentContext = i_OSGetCurrentContext(); + i_OSClearContext(&fpuContext); + OSSetCurrentContext(&fpuContext); + + OSReport("\n\nFPRs----------\n"); + for (i = 0; i < 32; i += 2) { + OSReport("fr%d \t= %d \t fr%d \t= %d\n", i, (u32)context->fpr[i], i + 1, + (u32)context->fpr[i + 1]); + } + OSReport("\n\nPSFs----------\n"); + for (i = 0; i < 32; i += 2) { + OSReport("ps%d \t= 0x%x \t ps%d \t= 0x%x\n", i, (u32)context->ps[i], i + 1, + (u32)context->ps[i + 1]); + } + + i_OSClearContext(&fpuContext); + OSSetCurrentContext(currentContext); + OSRestoreInterrupts(enabled); + } + + OSReport("\nAddress: Back Chain LR Save\n"); + for (i = 0, p = (u32*)context->gpr[1]; p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) { + OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]); + } +} + +static asm void OSSwitchFPUContext(register u8 err, register OSContext* context) { + // clang-format off + nofralloc + + mfmsr r5 + ori r5, r5, 0x2000 + mtmsr r5 + isync + lwz r5, 0x19c(context) + ori r5, r5, 0x2000 + mtspr 0x1b, r5 + lis r3, OS_CURRENT_FPU_CONTEXT@ha + lwz r5, OS_CURRENT_FPU_CONTEXT@l(r3) + stw context, 0xd8(r3) + cmpw r5, context + beq context_is_curr_fpu_context + cmpwi r5, 0 + beq context_is_null + bl __OSSaveFPUContext + +context_is_null: + bl __OSLoadFPUContext + +context_is_curr_fpu_context: + lwz r3, 0x80(context) + mtcrf 0xff, r3 + lwz r3, 0x84(context) + mtlr r3 + lwz r3, 0x198(context) + mtspr 0x1a, r3 + lwz r3, 0x88(context) + mtctr r3 + lwz r3, 0x8c(context) + mtxer r3 + lhz r3, 0x1a2(context) + rlwinm r3, r3, 0, 0x1f, 0x1d + sth r3, 0x1a2(context) + lwz r5, 0x14(context) + lwz r3, 0xc(context) + lwz context, 0x10(context) + rfi + // clang-format on +} + +void __OSContextInit(void) { + __OSSetExceptionHandler(EXCEPTION_FLOATING_POINT, OSSwitchFPUContext); + __OSFPUContext = NULL; + DBPrintf("FPU-unavailable handler installed\n"); +} + +asm void OSFillFPUContext(register OSContext* context) { + // clang-format off + nofralloc + + mfmsr r5 + ori r5, r5, 0x2000 + mtmsr r5 + isync + + stfd f0, 0x90(context) + stfd f1, 0x98(context) + stfd f2, 0xa0(context) + stfd f3, 0xa8(context) + stfd f4, 0xb0(context) + stfd f5, 0xb8(context) + stfd f6, 0xc0(context) + stfd f7, 0xc8(context) + stfd f8, 0xd0(context) + stfd f9, 0xd8(context) + stfd f10, 0xe0(context) + stfd f11, 0xe8(context) + stfd f12, 0xf0(context) + stfd f13, 0xf8(context) + stfd f14, 0x100(context) + stfd f15, 0x108(context) + stfd f16, 0x110(context) + stfd f17, 0x118(context) + stfd f18, 0x120(context) + stfd f19, 0x128(context) + stfd f20, 0x130(context) + stfd f21, 0x138(context) + stfd f22, 0x140(context) + stfd f23, 0x148(context) + stfd f24, 0x150(context) + stfd f25, 0x158(context) + stfd f26, 0x160(context) + stfd f27, 0x168(context) + stfd f28, 0x170(context) + stfd f29, 0x178(context) + stfd f30, 0x180(context) + stfd f31, 0x188(context) + + mffs f0 + stfd f0, 0x190(context) + lfd f0, 0x90(context) + mfspr r5, 0x398 + rlwinm. r5, r5, 3, 0x1f, 0x1f + beq exit + + psq_st f0, 456(context), 0, 0 + psq_st f1, 464(context), 0, 0 + psq_st f2, 472(context), 0, 0 + psq_st f3, 480(context), 0, 0 + psq_st f4, 488(context), 0, 0 + psq_st f5, 496(context), 0, 0 + psq_st f6, 504(context), 0, 0 + psq_st f7, 512(context), 0, 0 + psq_st f8, 520(context), 0, 0 + psq_st f9, 528(context), 0, 0 + psq_st f10, 536(context), 0, 0 + psq_st f11, 544(context), 0, 0 + psq_st f12, 552(context), 0, 0 + psq_st f13, 560(context), 0, 0 + psq_st f14, 568(context), 0, 0 + psq_st f15, 576(context), 0, 0 + psq_st f16, 584(context), 0, 0 + psq_st f17, 592(context), 0, 0 + psq_st f18, 600(context), 0, 0 + psq_st f19, 608(context), 0, 0 + psq_st f20, 616(context), 0, 0 + psq_st f21, 624(context), 0, 0 + psq_st f22, 632(context), 0, 0 + psq_st f23, 640(context), 0, 0 + psq_st f24, 648(context), 0, 0 + psq_st f25, 656(context), 0, 0 + psq_st f26, 664(context), 0, 0 + psq_st f27, 672(context), 0, 0 + psq_st f28, 680(context), 0, 0 + psq_st f29, 688(context), 0, 0 + psq_st f30, 696(context), 0, 0 + psq_st f31, 704(context), 0, 0 + +exit: + blr + // clang-format on +} diff --git a/src/dolphin/os/OSError.c b/src/dolphin/os/OSError.c new file mode 100644 index 000000000..53bb300c6 --- /dev/null +++ b/src/dolphin/os/OSError.c @@ -0,0 +1,227 @@ +#include "dolphin/os/OSError.h" +#include "dolphin/base/PPCArch.h" +#include "dolphin/dsp.h" +#include "dolphin/dvd/dvdlow.h" +#include "dolphin/os/OS.h" + +OSThread* __OSCurrentThread : (OS_BASE_CACHED | 0x00E4); +OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC); +volatile OSContext* __OSFPUContext : (OS_BASE_CACHED | 0x00D8); + +extern volatile u32 __OSLastInterruptSrr0; +extern volatile s16 __OSLastInterrupt; +extern volatile OSTime __OSLastInterruptTime; + +extern OSErrorHandlerEx __OSErrorTable[16]; +OSErrorHandlerEx __OSErrorTable[16]; + +#define FPSCR_ENABLE (FPSCR_VE | FPSCR_OE | FPSCR_UE | FPSCR_ZE | FPSCR_XE) +extern u32 __OSFpscrEnableBits = FPSCR_ENABLE; + +__declspec(weak) void OSReport(const char* msg, ...) { + va_list marker; + + va_start(marker, msg); + vprintf(msg, marker); + va_end(marker); +} + +__declspec(weak) void OSVReport(const char* msg, va_list list) { + vprintf(msg, list); +} + +__declspec(weak) void OSPanic(const char* file, s32 line, const char* msg, ...) { + va_list marker; + u32 i; + u32* p; + + OSDisableInterrupts(); + va_start(marker, msg); + vprintf(msg, marker); + va_end(marker); + OSReport(" in \"%s\" on line %d.\n", file, line); + + // actually useful for debugging- stack crawl + OSReport("\nAddress: Back Chain LR Save\n"); + for (i = 0, p = (u32*)OSGetStackPointer(); // get current stack pointer + p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) // get caller stack pointer + { + OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]); + } + + PPCHalt(); +} + +OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler) { + OSErrorHandlerEx oldHandler; + BOOL enabled; + + enabled = OSDisableInterrupts(); + oldHandler = __OSErrorTable[error]; + __OSErrorTable[error] = (OSErrorHandlerEx)handler; + + if (error == EXCEPTION_FLOATING_POINT_EXCEPTION) { + u32 msr; + u32 fpscr; + OSThread* thread; + + msr = PPCMfmsr(); + PPCMtmsr(msr | MSR_FP); + fpscr = PPCMffpscr(); + if (handler) { + for (thread = __OSActiveThreadQueue.head; thread; + thread = thread->active_threads_link.next) + { + thread->context.srr1 |= MSR_FE0 | MSR_FE1; + if ((thread->context.state & OS_CONTEXT_STATE_FPSAVED) == 0) { + int i; + thread->context.state |= OS_CONTEXT_STATE_FPSAVED; + for (i = 0; i < 32; ++i) { + *(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL; + *(u64*)&thread->context.ps[i] = (u64)0xffffffffffffffffLL; + } + thread->context.fpscr = FPSCR_NI; + } + thread->context.fpscr |= __OSFpscrEnableBits & FPSCR_ENABLE; + thread->context.fpscr &= + ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + } + fpscr |= __OSFpscrEnableBits & FPSCR_ENABLE; + msr |= MSR_FE0 | MSR_FE1; + } else { + for (thread = __OSActiveThreadQueue.head; thread; + thread = thread->active_threads_link.next) + { + thread->context.srr1 &= ~(MSR_FE0 | MSR_FE1); + thread->context.fpscr &= ~FPSCR_ENABLE; + thread->context.fpscr &= + ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + } + fpscr &= ~FPSCR_ENABLE; + msr &= ~(MSR_FE0 | MSR_FE1); + } + + fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | FPSCR_ZX | + FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + + PPCMtfpscr(fpscr); + PPCMtmsr(msr); + } + + OSRestoreInterrupts(enabled); + return oldHandler; +} + +void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar) { + OSTime now; + + now = OSGetTime(); + + if (!(context->srr1 & 2)) { + OSReport("Non-recoverable Exception %d", exception); + + } else { + if (exception == EXCEPTION_PROGRAM && (context->srr1 & (0x80000000 >> 11)) && + __OSErrorTable[EXCEPTION_FLOATING_POINT_EXCEPTION] != 0) + { + u32 fpscr; + u32 msr; + + exception = EXCEPTION_FLOATING_POINT_EXCEPTION; + + msr = PPCMfmsr(); + PPCMtmsr(msr | 0x2000); + + if (__OSFPUContext) { + OSSaveFPUContext((OSContext*)__OSFPUContext); + } + + fpscr = PPCMffpscr(); + fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + PPCMtfpscr(fpscr); + + PPCMtmsr(msr); + + if (__OSFPUContext == context) { + OSDisableScheduler(); + __OSErrorTable[exception](exception, context, dsisr, dar); + context->srr1 &= ~0x2000; + __OSFPUContext = NULL; + + context->fpscr &= + ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + OSEnableScheduler(); + __OSReschedule(); + } else { + context->srr1 &= ~0x2000; + __OSFPUContext = NULL; + } + + OSLoadContext(context); + } + + if (__OSErrorTable[exception]) { + OSDisableScheduler(); + __OSErrorTable[exception](exception, context, dsisr, dar); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + + if (exception == OS_ERROR_DECREMENTER) { + OSLoadContext(context); + } + + OSReport("Unhandled Exception %d", exception); + } + + OSReport("\n"); + OSDumpContext(context); + OSReport("\nDSISR = 0x%08x DAR = 0x%08x\n", dsisr, dar); + OSReport("TB = 0x%016llx\n", now); + + switch (exception) { + case EXCEPTION_DSI: + OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access " + "invalid address 0x%x (read from DAR)\n", + context->srr0, dar); + break; + case EXCEPTION_ISI: + OSReport("\nAttempted to fetch instruction from invalid address 0x%x " + "(read from SRR0)\n", + context->srr0); + break; + case EXCEPTION_ALIGNMENT: + OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access " + "unaligned address 0x%x (read from DAR)\n", + context->srr0, dar); + break; + case EXCEPTION_PROGRAM: + OSReport("\nProgram exception : Possible illegal instruction/operation " + "at or around 0x%x (read from SRR0)\n", + context->srr0, dar); + break; + case EXCEPTION_MEMORY_PROTECTION: + OSReport("\n"); + OSReport("AI DMA Address = 0x%04x%04x\n", __DSPRegs[DSP_DMA_START_HI], + __DSPRegs[DSP_DMA_START_LO]); + OSReport("ARAM DMA Address = 0x%04x%04x\n", __DSPRegs[DSP_ARAM_DMA_MM_HI], + __DSPRegs[DSP_ARAM_DMA_MM_LO]); + OSReport("DI DMA Address = 0x%08x\n", __DIRegs[5]); + break; + } + + OSReport("\nLast interrupt (%d): SRR0 = 0x%08x TB = 0x%016llx\n", __OSLastInterrupt, + __OSLastInterruptSrr0, __OSLastInterruptTime); + + PPCHalt(); +} diff --git a/src/dolphin/os/OSExec.c b/src/dolphin/os/OSExec.c new file mode 100644 index 000000000..16fee7dc8 --- /dev/null +++ b/src/dolphin/os/OSExec.c @@ -0,0 +1,299 @@ +// +// Generated By: dol2asm +// Translation Unit: OSExec +// + +#include "dolphin/os/OSExec.h" +#include "dolphin/os/OS.h" +#include "dolphin/ai.h" +#include "dol2asm.h" +#include "string.h" +#include "printf.h" + +#pragma push +#pragma optimization_level 0 +#pragma optimizewithasm off +static asm s32 PackArgs(void* param_0, u32 param_1, void* param_2) { + nofralloc +#include "asm/dolphin/os/OSExec/PackArgs.s" +} +#pragma pop + +static asm void Run(int param_0) { + // clang-format off + nofralloc + + mflr r0 + stw r0, 4(r1) + stwu r1, -0x18(r1) + stw r31, 0x14(r1) + mr r31, r3 + bl ICFlashInvalidate + sync + isync + mtlr r31 + blr + + lwz r0, 0x1c(r1) + lwz r31, 0x14(r1) + addi r1, r1, 0x18 + mtlr r0 + blr + // clang-format on +} + +static void ReadDisc(void* param_0, s32 param_1, s32 param_2) { + DVDCommandBlock cmd; + DVDReadAbsAsyncPrio(&cmd, param_0, param_1, param_2, NULL, 0); + while (DVDGetCommandBlockStatus(&cmd)) { + if (!DVDCheckDisk()) { + __OSDoHotReset(0); + } + } +} + +static BOOL Prepared; + +static void Callback(void) { + Prepared = TRUE; +} + +OSExecParams* osExecParams : 0x800030f0; + +void __OSGetExecParams(OSExecParams* param_0) { + if (OSPhysicalToCached(0) <= osExecParams) { + memcpy(param_0, osExecParams, sizeof(OSExecParams)); + } else { + param_0->valid = FALSE; + } +} + +static __OSSetExecParams(const OSExecParams* src, OSExecParams* dst) { + memcpy(dst, src, sizeof(OSExecParams)); + osExecParams = dst; +} + +static s32 apploaderPosition; + +s32 appLoaderOffset : 0x800030f4; + +static int GetApploaderPosition(void) { + u8 padding[8]; + + if (apploaderPosition != 0) { + return apploaderPosition; + } + + if (appLoaderOffset) { + void* buffer = OSAllocFromArenaLo(0x40, 0x20); + ReadDisc(buffer, 0x40, appLoaderOffset); + apploaderPosition = appLoaderOffset + ((s32*)buffer)[0xe]; + } else { + apploaderPosition = 0x2440; + } + return apploaderPosition; +} + +SECTION_DATA static char lit_115[] = "2004/02/01"; + +// GetApploaderPosition inline issue + end of function +#ifdef NONMATCHING + +typedef int (*AppLoaderInnerCallback)(void*, s32*, s32*); +typedef void (*LogCallback)(void*); +typedef void (*AppLoaderCallback)(LogCallback*, AppLoaderInnerCallback*, int (**callback)(void)); + +typedef struct { + char version[10]; + s16 field_0xa; + s32 field_0xc; + AppLoaderCallback field_0x10; + s32 field_0x14; + s32 field_0x18; + s32 field_0x1c; +} AppLoaderStruct; + +static AppLoaderStruct* LoadApploader() { + AppLoaderStruct* iVar1; + s32 pos; + s32 nextPos; + + iVar1 = (AppLoaderStruct*)OSAllocFromArenaLo(sizeof(AppLoaderStruct), sizeof(AppLoaderStruct)); + pos = GetApploaderPosition(); + ReadDisc(iVar1, sizeof(AppLoaderStruct), pos); + nextPos = GetApploaderPosition(); + ReadDisc((void*)0x81200000, iVar1->field_0x14 + 0x1fU & 0xffffffe0, nextPos + 0x20); + ICInvalidateRange((void*)0x81200000, iVar1->field_0x14 + 0x1fU & 0xffffffe0); + return iVar1; +} + +static BOOL IsNewApploader(const char* version) { + BOOL rv; + if (strncmp(version, "2004/02/01", 10) > 0) { + rv = TRUE; + } else { + rv = FALSE; + } + return rv; +} + +static int LoadDol(OSExecParams* def, AppLoaderCallback cb) { + LogCallback local_c; + AppLoaderInnerCallback innercb; + int (*local_14)(void); + OSExecParams* execParams; + void* local_18; + s32 local_1c; + s32 local_20; + cb(&local_c, &innercb, &local_14); + execParams = OSAllocFromArenaLo(sizeof(OSExecParams), 1); + __OSSetExecParams(def, execParams); + local_c(OSReport); + OSSetArenaLo(execParams); + while (innercb(&local_18, &local_1c, &local_20)) { + ReadDisc(local_18, local_1c, local_20); + } + return (*local_14)(); +} + +static void StartDol(OSExecParams* execParams, int param_1) { + OSExecParams* uVar1 = (OSExecParams*)OSAllocFromArenaLo(sizeof(OSExecParams), 1); + __OSSetExecParams(execParams, uVar1); + __PIRegs[9] = 7; + OSDisableInterrupts(); + Run(param_1); +} + +u8 DAT_800030e2 : 0x800030E2; + +void __OSBootDolSimple(u32 param_0, u32 param_1, void* param_2, void* param_3, s32 param_4, u32 param_5, void* param_6) { + OSExecParams* puVar1; + AppLoaderStruct* iVar3; + DVDDiskID* id; + int uVar2; + s32 iVar4; + s32 is_streaming; + DVDCommandBlock cmd; + + OSDisableInterrupts(); + puVar1 = (OSExecParams*)OSAllocFromArenaLo(sizeof(OSExecParams), 1); + puVar1->valid = 1; + puVar1->restartCode = param_1; + puVar1->regionStart = param_2; + puVar1->regionEnd = param_3; + puVar1->argsUseDefault = param_4; + if (param_4 == 0) { + puVar1->argsAddr = OSAllocFromArenaLo(0x2000, 1); + PackArgs(puVar1->argsAddr, param_5, param_6); + } + DVDInit(); + DVDSetAutoInvalidation(TRUE); + DVDResume(); + Prepared = FALSE; + __DVDPrepareResetAsync((DVDCBCallback)Callback); + __OSMaskInterrupts(0xffffffe0); + __OSUnmaskInterrupts(0x400); + OSEnableInterrupts(); + while (Prepared != TRUE) { + if (!DVDCheckDisk()) { + __OSDoHotReset(0); + } + } + + if (!__OSIsGcam) { + id = DVDGetCurrentDiskID(); + if (id->is_streaming) { + is_streaming = TRUE; + } else { + is_streaming = FALSE; + } + if (is_streaming) { + AISetStreamVolLeft(0); + AISetStreamVolRight(0); + DVDCancelStreamAsync(&cmd, NULL); + while (DVDGetCommandBlockStatus(&cmd)) { + if (!DVDCheckDisk()) { + __OSDoHotReset(0); + } + } + AISetStreamPlayState(0); + } + } + + iVar3 = LoadApploader(); + if (IsNewApploader(iVar3->version)) { + if (param_0 == -1) { + param_0 = GetApploaderPosition(); + param_0 += iVar3->field_0x14; + param_0 += 0x20; + } + puVar1->bootDol = param_0; + uVar2 = LoadDol(puVar1, iVar3->field_0x10); + StartDol(puVar1, uVar2); + } else { + BOOT_REGION_START = (u32)param_2; + BOOT_REGION_END = (u32)param_3; + DAT_800030e2 = 1; + // GetApploaderPosition is inlined for some reason + iVar4 = GetApploaderPosition() + iVar3->field_0x14; + ReadDisc((void*)0x81300000, iVar3->field_0x18 + 0x1fU & 0xffffffe0, + iVar4 + 0x20); + ICInvalidateRange((void*)0x81300000, iVar3->field_0x18 + 0x1fU & 0xffffffe0); + OSDisableInterrupts(); + ICFlashInvalidate(); + Run(0x81300000); + } +} +#else +#pragma push +#pragma optimization_level 0 +#pragma optimizewithasm off +asm void __OSBootDolSimple(u32 param_0, u32 param_1, void* param_2, void* param_3, s32 param_4, u32 param_5, void* param_6) { + nofralloc +#include "asm/dolphin/os/OSExec/__OSBootDolSimple.s" +} +#pragma pop +#endif + +SECTION_SDATA static char lit_213[] = "%d"; + +#ifdef NONMATCHING +void __OSBootDol(s32 param_0, u32 param_1, char** param_2) { + char acStack_28[20]; + void* local_2c; + void* local_30; + s32 iVar3; + char** ppcVar1; + char** ppcVar2; + char** ppcVarDst; + char** ppcVarSrc; + int iVar2; + OSGetSaveRegion(&local_2c, &local_30); + sprintf(acStack_28, "%d", param_0); + iVar3 = 0; + if (param_2 != NULL) { + ppcVar2 = param_2; + while (*ppcVar2 != NULL) { + ppcVar2++; + iVar3++; + } + } + ppcVar1 = (char**)OSAllocFromArenaLo((iVar3 + 2) * 4, 1); + *ppcVar1 = acStack_28; + ppcVarSrc = param_2; + ppcVarDst = ppcVar1 + 1; + for (iVar2 = 1; iVar2 < iVar3 + 1; iVar2++) { + *ppcVarDst++ = *ppcVarSrc++; + } + __OSBootDolSimple(0xffffffff, param_1, local_2c, local_30, 0, iVar3 + 1, ppcVar1); +} +#else +#pragma push +#pragma optimization_level 0 +#pragma optimizewithasm off +asm void __OSBootDol(s32 param_0, u32 param_1, char** param_2) { + nofralloc +#include "asm/dolphin/os/OSExec/__OSBootDol.s" +} +#pragma pop +#endif diff --git a/src/dolphin/os/OSFont.c b/src/dolphin/os/OSFont.c new file mode 100644 index 000000000..218f50c2c --- /dev/null +++ b/src/dolphin/os/OSFont.c @@ -0,0 +1,303 @@ +#include "dolphin/os/OSFont.h" +#include "dolphin/os/OS.h" +#include "dolphin/vi/vi.h" + +static u16 HankakuToCode[192] = { + 0x020C, 0x020D, 0x020E, 0x020F, 0x0210, 0x0211, 0x0212, 0x0213, + 0x0214, 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021A, 0x021B, + 0x021C, 0x021D, 0x021E, 0x021F, 0x0220, 0x0221, 0x0222, 0x0223, + 0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022A, 0x022B, + 0x022C, 0x022D, 0x022E, 0x022F, 0x0230, 0x0231, 0x0232, 0x0233, + 0x0234, 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023A, 0x023B, + 0x023C, 0x023D, 0x023E, 0x023F, 0x0240, 0x0241, 0x0242, 0x0243, + 0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024A, 0x024B, + 0x024C, 0x024D, 0x024E, 0x024F, 0x0250, 0x0251, 0x0252, 0x0253, + 0x0254, 0x0255, 0x0256, 0x0257, 0x0258, 0x0259, 0x025A, 0x025B, + 0x025C, 0x025D, 0x025E, 0x025F, 0x0260, 0x0261, 0x0262, 0x0263, + 0x0264, 0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026A, 0x020C, + 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, + 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, + 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, + 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, + 0x020C, 0x026B, 0x026C, 0x026D, 0x026E, 0x026F, 0x0270, 0x0271, + 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, 0x0279, + 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F, 0x0280, 0x0281, + 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, + 0x028A, 0x028B, 0x028C, 0x028D, 0x028E, 0x028F, 0x0290, 0x0291, + 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, 0x0298, 0x0299, + 0x029A, 0x029B, 0x029C, 0x029D, 0x029E, 0x029F, 0x02A0, 0x02A1, + 0x02A2, 0x02A3, 0x02A4, 0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, +}; + +static u16 Zenkaku2Code[1221] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x006C, + 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0074, + 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080, 0x0081, + 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x008A, + 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, 0x0090, 0x0091, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0092, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x009D, 0x009E, 0x009F, 0x00A0, + 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, + 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, + 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x00B7, 0x00B8, 0x00B9, 0x00BA, + 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, + 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, + 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, + 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, + 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, + 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, + 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, + 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, + 0x00FF, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, + 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, + 0x010F, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, + 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, + 0x011F, 0x0120, 0x0121, 0x0122, 0x0123, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0124, 0x0125, 0x0126, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, + 0x012C, 0x012D, 0x012E, 0x012F, 0x0130, 0x0131, 0x0132, 0x0133, + 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, + 0x013C, 0x013D, 0x013E, 0x013F, 0x0140, 0x0141, 0x0142, 0x0143, + 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014A, 0x014B, + 0x014C, 0x014D, 0x014E, 0x014F, 0x0150, 0x0151, 0x0152, 0x0153, + 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, + 0x015C, 0x015D, 0x015E, 0x015F, 0x0160, 0x0161, 0x0162, 0x0163, + 0x0164, 0x0165, 0x0166, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, + 0x016C, 0x016D, 0x016E, 0x016F, 0x0170, 0x0171, 0x0172, 0x0173, + 0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017A, 0x017B, + 0x017C, 0x017D, 0x017E, 0x017F, 0x0180, 0x0181, 0x0182, 0x0183, + 0x0184, 0x0185, 0x0186, 0x0187, 0x0188, 0x0189, 0x018A, 0x018B, + 0x018C, 0x018D, 0x018E, 0x018F, 0x0190, 0x0191, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0193, + 0x0194, 0x0195, 0x0196, 0x0197, 0x0198, 0x0199, 0x019A, 0x019B, + 0x019C, 0x019D, 0x019E, 0x019F, 0x01A0, 0x01A1, 0x01A2, 0x01A3, + 0x01A4, 0x01A5, 0x01A6, 0x01A7, 0x01A8, 0x01A9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x01AA, 0x01AB, 0x01AC, 0x01AD, + 0x01AE, 0x01AF, 0x01B0, 0x01B1, 0x01B2, 0x01B3, 0x01B4, 0x01B5, + 0x01B6, 0x01B7, 0x01B8, 0x01B9, 0x01BA, 0x01BB, 0x01BC, 0x01BD, + 0x01BE, 0x01BF, 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C5, + 0x01C6, 0x01C7, 0x01C8, 0x01C9, 0x01CA, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x01CB, 0x01CC, 0x01CD, 0x01CE, + 0x01CF, 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, + 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, + 0x01DF, 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E4, 0x01E5, 0x01E6, + 0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x01EC, 0x01ED, 0x01EE, 0x01EF, 0x01F0, 0x01F1, + 0x01F2, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, + 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF, 0x0200, 0x0201, + 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209, + 0x020A, 0x020B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x020C, + 0x020D, 0x020E, 0x020F, 0x0210, 0x0211, 0x0212, 0x0213, 0x0214, + 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021A, 0x021B, 0x021C, + 0x021D, 0x021E, 0x021F, 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, + 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022A, 0x022B, 0x022C, + 0x022D, 0x022E, 0x022F, 0x0230, 0x0231, 0x0232, 0x0233, 0x0234, + 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023A, 0x023B, 0x023C, + 0x023D, 0x023E, 0x023F, 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, + 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024A, 0x024B, 0x024C, + 0x024D, 0x024E, 0x024F, 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, + 0x0255, 0x0256, 0x0257, 0x0258, 0x0259, 0x025A, 0x025B, 0x025C, + 0x025D, 0x025E, 0x025F, 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, + 0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026A, 0x026B, 0x026C, + 0x026D, 0x026E, 0x026F, 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, + 0x0275, 0x0276, 0x0277, 0x0278, 0x0279, 0x027A, 0x027B, 0x027C, + 0x027D, 0x027E, 0x027F, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, + 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, 0x028A, 0x028B, 0x028C, + 0x028D, 0x028E, 0x028F, 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, + 0x0295, 0x0296, 0x0297, 0x0298, 0x0299, 0x029A, 0x029B, 0x029C, + 0x029D, 0x029E, 0x029F, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x02A4, + 0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC, + 0x02AD, 0x02AE, 0x02AF, 0x02B0, 0x02B1, 0x02B2, 0x02B3, 0x02B4, + 0x02B5, 0x02B6, 0x02B7, 0x02B8, 0x02B9, 0x02BA, 0x02BB, 0x02BC, + 0x02BD, 0x02BE, 0x02BF, 0x02C0, 0x02C1, 0x02C2, 0x02C3, 0x02C4, + 0x02C5, 0x02C6, 0x02C7, 0x02C8, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x02C9, 0x02CA, 0x02CB, 0x02CC, 0x02CD, 0x02CE, 0x02CF, 0x02D0, + 0x02D1, 0x02D2, 0x02D3, 0x02D4, 0x02D5, 0x02D6, 0x02D7, 0x02D8, + 0x02D9, 0x02DA, 0x02DB, 0x02DC, 0x02DD, 0x02DE, 0x02DF, 0x02E0, + 0x02E1, 0x02E2, 0x02E3, 0x02E4, 0x02E5, 0x02E6, 0x0000, 0x02E7, + 0x02E8, 0x02E9, 0x02EA, 0x02EB, 0x02EC, 0x02ED, 0x02EE, 0x02EF, + 0x02F0, 0x02F1, 0x02F2, 0x02F3, 0x02F4, 0x02F5, 0x02F6, 0x02F7, + 0x02F8, 0x02F9, 0x02FA, 0x02FB, 0x02FC, 0x02FD, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x02FE, 0x02FF, + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031A, 0x031B, 0x0000, +}; + +static BOOL IsSjisLeadByte(u8 ch) { + return (0x81 <= ch && ch <= 0x9F) || (0xE0 <= ch && ch <= 0xFC); +} + +static BOOL IsSjisTrailByte(u8 ch) { + return (0x40 <= ch && ch <= 0xFC) && (ch != 0x7F); +} + +static u32 GetFontCode(u16 encode, u16 code) { + u32 tmp; + s32 trail; + + if (encode == OS_FONT_ENCODE_SJIS) { + if (0x20 <= code && code <= 0xDF) { + return HankakuToCode[code - 0x20]; + } else if (0x889E < code && code <= 0x9872) { + tmp = ((code >> 8) - 0x88) * 0xBC; + trail = code & 0xFF; + + if (!IsSjisTrailByte(trail)) { + return 0; + } + + trail -= 0x40; + if (trail >= 0x40) { + trail--; + } + + return tmp + trail + 0x2BE; + } else if (0x8140 <= code && code < 0x879E) { + tmp = ((code >> 8) - 0x81) * 0xBC; + trail = code & 0xFF; + + if (!IsSjisTrailByte(trail)) { + return 0; + } + + trail -= 0x40; + if (trail >= 0x40) { + trail--; + } + + return Zenkaku2Code[tmp + trail]; + } + } else if (code > 0x20 && code <= 0xFF) { + return code - 0x20; + } + + return 0; +} + +static u16 FontEncode = 0xFFFF; + +static OSFontHeader* FontDataAnsi; + +static OSFontHeader* FontDataSjis; + +static void* ParseString; + +u16 OSGetFontEncode(void) { + if (FontEncode != 0xFFFF) { + return FontEncode; + } + + switch (*(u32*)OSPhysicalToCached(0xCC)) { + case VI_NTSC: + FontEncode = ((__VIRegs[55] & 2) != 0) + ? OS_FONT_ENCODE_SJIS + : OS_FONT_ENCODE_ANSI; + break; + case VI_PAL: + case VI_MPAL: + case VI_DEBUG: + case VI_DEBUG_PAL: + case VI_EURGB60: + default: + FontEncode = OS_FONT_ENCODE_ANSI; + } + + ParseString = ParseStringS; + + return FontEncode; +} + +static const u8* ParseStringS(u16 encode, const u8* str, OSFontHeader** fontOut, + u32* codeOut) { + OSFontHeader* font; + u16 code = 0; + + switch (encode) { + case OS_FONT_ENCODE_ANSI: + font = FontDataAnsi; + code = *str; + if (code != 0) { + str++; + } + break; + case OS_FONT_ENCODE_SJIS: + font = FontDataSjis; + code = *str; + if (code == 0) { + break; + } + str++; + + if (IsSjisLeadByte(code) && IsSjisTrailByte(*str)) { + code = (code << 8 | *str++); + } + break; + } + + *fontOut = font; + *codeOut = GetFontCode(encode, code); + + return str; +} diff --git a/src/dolphin/os/OSInterrupt.c b/src/dolphin/os/OSInterrupt.c new file mode 100644 index 000000000..711bfcce5 --- /dev/null +++ b/src/dolphin/os/OSInterrupt.c @@ -0,0 +1,430 @@ +#include "dolphin/os/OSInterrupt.h" +#include "dolphin/dsp.h" +#include "dolphin/exi/EXIBios.h" +#include "dolphin/os/OS.h" + +vu32 __PIRegs[12] : 0xCC003000; +vu16 __MEMRegs[64] : 0xCC004000; + +asm BOOL OSDisableInterrupts(void) { + // clang-format off + nofralloc + + entry __RAS_OSDisableInterrupts_begin + + mfmsr r3 + // Clear external interrupts bit + rlwinm r4, r3, 0, 17, 15 + mtmsr r4 + + entry __RAS_OSDisableInterrupts_end + + // Return old interrupt status + rlwinm r3, r3, 17, 31, 31 + blr + // clang-format on +} + +asm BOOL OSEnableInterrupts(void) { + // clang-format off + nofralloc + + mfmsr r3 + // Set external interrupts bit + ori r4, r3, (1 << 15) + mtmsr r4 + + // Return old interrupt status + rlwinm r3, r3, 17, 31, 31 + blr + // clang-format on +} + +asm BOOL OSRestoreInterrupts(register BOOL status) { + // clang-format off + nofralloc + + cmpwi status, 0 + mfmsr r4 + beq disable + + // Set external interrupts bit + ori r5, r4, (1 << 15) + b set_msr + +disable: + // Clear external interrupts bit + rlwinm r5, r4, 0, 17, 15 + +set_msr: + mtmsr r5 + // Return old interrupt status + rlwinm r3, r4, 17, 31, 31 + blr + // clang-format on +} + +static __OSInterruptHandler* InterruptHandlerTable; + +__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt type, __OSInterruptHandler handler) { + __OSInterruptHandler old = InterruptHandlerTable[type]; + InterruptHandlerTable[type] = handler; + return old; +} + +__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt type) { + return InterruptHandlerTable[type]; +} + +void __OSInterruptInit(void) { + InterruptHandlerTable = OSPhysicalToCached(0x3040); + memset(InterruptHandlerTable, 0, 32 * sizeof(__OSInterruptHandler)); + + *(OSInterruptMask*)OSPhysicalToCached(0x00C4) = 0; + + *(OSInterruptMask*)OSPhysicalToCached(0x00C8) = 0; + + __PIRegs[1] = 0xf0; + + __OSMaskInterrupts(OS_INTERRUPTMASK_MEM | OS_INTERRUPTMASK_DSP | OS_INTERRUPTMASK_AI | + OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI); + + __OSSetExceptionHandler(4, (OSExceptionHandler)ExternalInterruptHandler); +} + +u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current) { + u32 reg; + + switch (__cntlzw(mask)) { + case OS_INTR_MEM_0: + case OS_INTR_MEM_1: + case OS_INTR_MEM_2: + case OS_INTR_MEM_3: + case OS_INTR_MEM_ADDRESS: + reg = 0; + if (!(current & OS_INTERRUPTMASK_MEM_0)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_MEM_1)) + reg |= 0x2; + if (!(current & OS_INTERRUPTMASK_MEM_2)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_MEM_3)) + reg |= 0x8; + if (!(current & OS_INTERRUPTMASK_MEM_ADDRESS)) + reg |= 0x10; + __MEMRegs[0x0000000e] = (u16)reg; + mask &= ~OS_INTERRUPTMASK_MEM; + break; + case OS_INTR_DSP_AI: + case OS_INTR_DSP_ARAM: + case OS_INTR_DSP_DSP: + reg = __DSPRegs[0x00000005]; + reg &= ~0x1F8; + if (!(current & OS_INTERRUPTMASK_DSP_AI)) + reg |= 0x10; + if (!(current & OS_INTERRUPTMASK_DSP_ARAM)) + reg |= 0x40; + if (!(current & OS_INTERRUPTMASK_DSP_DSP)) + reg |= 0x100; + __DSPRegs[0x00000005] = (u16)reg; + mask &= ~OS_INTERRUPTMASK_DSP; + break; + case OS_INTR_AI_AI: + reg = __AIRegs[0]; + reg &= ~0x2C; + if (!(current & OS_INTERRUPTMASK_AI_AI)) + reg |= 0x4; + __AIRegs[0] = reg; + mask &= ~OS_INTERRUPTMASK_AI; + break; + case OS_INTR_EXI_0_EXI: + case OS_INTR_EXI_0_TC: + case OS_INTR_EXI_0_EXT: + reg = __EXIRegs[0]; + reg &= ~0x2C0F; + if (!(current & OS_INTERRUPTMASK_EXI_0_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_0_TC)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_EXI_0_EXT)) + reg |= 0x400; + __EXIRegs[0] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_0; + break; + case OS_INTR_EXI_1_EXI: + case OS_INTR_EXI_1_TC: + case OS_INTR_EXI_1_EXT: + reg = __EXIRegs[5]; + reg &= ~0xC0F; + + if (!(current & OS_INTERRUPTMASK_EXI_1_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_1_TC)) + reg |= 0x4; + if (!(current & OS_INTERRUPTMASK_EXI_1_EXT)) + reg |= 0x400; + __EXIRegs[5] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_1; + break; + case OS_INTR_EXI_2_EXI: + case OS_INTR_EXI_2_TC: + reg = __EXIRegs[10]; + reg &= ~0xF; + if (!(current & OS_INTERRUPTMASK_EXI_2_EXI)) + reg |= 0x1; + if (!(current & OS_INTERRUPTMASK_EXI_2_TC)) + reg |= 0x4; + + __EXIRegs[10] = reg; + mask &= ~OS_INTERRUPTMASK_EXI_2; + break; + case OS_INTR_PI_CP: + case OS_INTR_PI_SI: + case OS_INTR_PI_DI: + case OS_INTR_PI_RSW: + case OS_INTR_PI_ERROR: + case OS_INTR_PI_VI: + case OS_INTR_PI_DEBUG: + case OS_INTR_PI_PE_TOKEN: + case OS_INTR_PI_PE_FINISH: + case OS_INTR_PI_HSP: + reg = 0xF0; + + if (!(current & OS_INTERRUPTMASK_PI_CP)) { + reg |= 0x800; + } + if (!(current & OS_INTERRUPTMASK_PI_SI)) { + reg |= 0x8; + } + if (!(current & OS_INTERRUPTMASK_PI_DI)) { + reg |= 0x4; + } + if (!(current & OS_INTERRUPTMASK_PI_RSW)) { + reg |= 0x2; + } + if (!(current & OS_INTERRUPTMASK_PI_ERROR)) { + reg |= 0x1; + } + if (!(current & OS_INTERRUPTMASK_PI_VI)) { + reg |= 0x100; + } + if (!(current & OS_INTERRUPTMASK_PI_DEBUG)) { + reg |= 0x1000; + } + if (!(current & OS_INTERRUPTMASK_PI_PE_TOKEN)) { + reg |= 0x200; + } + if (!(current & OS_INTERRUPTMASK_PI_PE_FINISH)) { + reg |= 0x400; + } + if (!(current & OS_INTERRUPTMASK_PI_HSP)) { + reg |= 0x2000; + } + __PIRegs[1] = reg; + mask &= ~OS_INTERRUPTMASK_PI; + break; + default: + break; + } + return mask; +} + +OSInterruptMask __OSMaskInterrupts(OSInterruptMask global) { + BOOL enabled; + OSInterruptMask prev; + OSInterruptMask local; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + prev = *(OSInterruptMask*)OSPhysicalToCached(0x00C4); + local = *(OSInterruptMask*)OSPhysicalToCached(0x00C8); + mask = ~(prev | local) & global; + global |= prev; + *(OSInterruptMask*)OSPhysicalToCached(0x00C4) = global; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask global) { + BOOL enabled; + OSInterruptMask prev; + OSInterruptMask local; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + prev = *(OSInterruptMask*)OSPhysicalToCached(0x00C4); + local = *(OSInterruptMask*)OSPhysicalToCached(0x00C8); + mask = (prev | local) & global; + global = prev & ~global; + *(OSInterruptMask*)OSPhysicalToCached(0x00C4) = global; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +static u32 InterruptPrioTable[] = { + 0x00000100, 0x00000040, 0xF8000000, 0x00000200, 0x00000080, 0x00003000, + 0x00000020, 0x03FF8C00, 0x04000000, 0x00004000, 0xFFFFFFFF, +}; + +extern OSTime __OSLastInterruptTime; +OSTime __OSLastInterruptTime; + +extern s16 __OSLastInterrupt; +s16 __OSLastInterrupt; + +extern u32 __OSLastInterruptSrr0; +u32 __OSLastInterruptSrr0; + +void __OSDispatchInterrupt(__OSException exception, OSContext* context) { + u32 intsr; + u32 reg; + OSInterruptMask cause; + OSInterruptMask unmasked; + OSInterruptMask* prio; + __OSInterrupt interrupt; + __OSInterruptHandler handler; + intsr = __PIRegs[0]; + intsr &= ~0x00010000; + + if (intsr == 0 || (intsr & __PIRegs[1]) == 0) { + OSLoadContext(context); + } + + cause = 0; + + if (intsr & 0x00000080) { + reg = __MEMRegs[15]; + if (reg & 0x1) + cause |= OS_INTERRUPTMASK_MEM_0; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_MEM_1; + if (reg & 0x4) + cause |= OS_INTERRUPTMASK_MEM_2; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_MEM_3; + if (reg & 0x10) + cause |= OS_INTERRUPTMASK_MEM_ADDRESS; + } + + if (intsr & 0x00000040) { + reg = __DSPRegs[5]; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_DSP_AI; + if (reg & 0x20) + cause |= OS_INTERRUPTMASK_DSP_ARAM; + if (reg & 0x80) + cause |= OS_INTERRUPTMASK_DSP_DSP; + } + + if (intsr & 0x00000020) { + reg = __AIRegs[0]; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_AI_AI; + } + + if (intsr & 0x00000010) { + reg = __EXIRegs[0]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_0_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_0_TC; + if (reg & 0x800) + cause |= OS_INTERRUPTMASK_EXI_0_EXT; + reg = __EXIRegs[5]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_1_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_1_TC; + if (reg & 0x800) + cause |= OS_INTERRUPTMASK_EXI_1_EXT; + reg = __EXIRegs[10]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_2_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_2_TC; + } + + if (intsr & 0x00002000) + cause |= OS_INTERRUPTMASK_PI_HSP; + if (intsr & 0x00001000) + cause |= OS_INTERRUPTMASK_PI_DEBUG; + if (intsr & 0x00000400) + cause |= OS_INTERRUPTMASK_PI_PE_FINISH; + if (intsr & 0x00000200) + cause |= OS_INTERRUPTMASK_PI_PE_TOKEN; + if (intsr & 0x00000100) + cause |= OS_INTERRUPTMASK_PI_VI; + if (intsr & 0x00000008) + cause |= OS_INTERRUPTMASK_PI_SI; + if (intsr & 0x00000004) + cause |= OS_INTERRUPTMASK_PI_DI; + if (intsr & 0x00000002) + cause |= OS_INTERRUPTMASK_PI_RSW; + if (intsr & 0x00000800) + cause |= OS_INTERRUPTMASK_PI_CP; + if (intsr & 0x00000001) + cause |= OS_INTERRUPTMASK_PI_ERROR; + + unmasked = cause & ~(*(OSInterruptMask*)OSPhysicalToCached(0x00C4) | + *(OSInterruptMask*)OSPhysicalToCached(0x00C8)); + if (unmasked) { + for (prio = InterruptPrioTable;; ++prio) { + if (unmasked & *prio) { + interrupt = (__OSInterrupt)__cntlzw(unmasked & *prio); + break; + } + } + + handler = __OSGetInterruptHandler(interrupt); + if (handler) { + if (OS_INTR_MEM_ADDRESS < interrupt) { + __OSLastInterrupt = interrupt; + __OSLastInterruptTime = OSGetTime(); + __OSLastInterruptSrr0 = context->srr0; + } + + OSDisableScheduler(); + handler(interrupt, context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + } + + OSLoadContext(context); +} + +static asm void ExternalInterruptHandler(register __OSInterrupt type, register OSContext* context) { + // clang-format off + nofralloc + + stw r0, context->gpr[0] + stw r1, context->gpr[1] + stw r2, context->gpr[2] + stmw r6, context->gpr[6] + + mfspr r0, GQR1 + stw r0, context->gqr[1] + mfspr r0, GQR2 + stw r0, context->gqr[2] + mfspr r0, GQR3 + stw r0, context->gqr[3] + mfspr r0, GQR4 + stw r0, context->gqr[4] + mfspr r0, GQR5 + stw r0, context->gqr[5] + mfspr r0, GQR6 + stw r0, context->gqr[6] + mfspr r0, GQR7 + stw r0, context->gqr[7] + + stwu r1, -8(r1) + b __OSDispatchInterrupt + // clang-format on +} diff --git a/src/dolphin/os/OSLink.c b/src/dolphin/os/OSLink.c new file mode 100644 index 000000000..e0e987d86 --- /dev/null +++ b/src/dolphin/os/OSLink.c @@ -0,0 +1,474 @@ +#include "dolphin/os/OS.h" + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) + +// Name Value Field Calculation +#define R_PPC_NONE 0 // none none +#define R_PPC_ADDR32 1 // word32 S + A +#define R_PPC_ADDR24 2 // low24* (S + A) >> 2 +#define R_PPC_ADDR16 3 // half16* S + A +#define R_PPC_ADDR16_LO 4 // half16 #lo(S + A) +#define R_PPC_ADDR16_HI 5 // half16 #hi(S + A) +#define R_PPC_ADDR16_HA 6 // half16 #ha(S + A) +#define R_PPC_ADDR14 7 // low14* (S + A) >> 2 +#define R_PPC_ADDR14_BRTAKEN 8 // low14* (S + A) >> 2 +#define R_PPC_ADDR14_BRNTAKEN 9 // low14* (S + A) >> 2 +#define R_PPC_REL24 10 // low24* (S + A - P) >> 2 +#define R_PPC_REL14 11 // low14* (S + A - P) >> 2 +#define R_PPC_REL14_BRTAKEN 12 // low14* (S + A - P) >> 2 +#define R_PPC_REL14_BRNTAKEN 13 // low14* (S + A - P) >> 2 + +#define R_PPC_GOT16 14 // half16* G + A +#define R_PPC_GOT16_LO 15 // half16 #lo(G + A) +#define R_PPC_GOT16_HI 16 // half16 #hi(G + A) +#define R_PPC_GOT16_HA 17 // half16 #ha(G + A) +#define R_PPC_PLTREL24 18 // low24* (L + A - P) >> 2 +#define R_PPC_COPY 19 // none none +#define R_PPC_GLOB_DAT 20 // word32 S + A +#define R_PPC_JMP_SLOT 21 // none +#define R_PPC_RELATIVE 22 // word32 B + A + +#define R_PPC_LOCAL24PC 23 // low24* + +#define R_PPC_UADDR32 24 // word32 S + A +#define R_PPC_UADDR16 25 // half16* S + A +#define R_PPC_REL32 26 // word32 S + A - P + +#define R_PPC_PLT32 27 // word32 L + A +#define R_PPC_PLTREL32 28 // word32 L + A - P +#define R_PPC_PLT16_LO 29 // half16 #lo(L + A) +#define R_PPL_PLT16_HI 30 // half16 #hi(L + A) +#define R_PPC_PLT16_HA 31 // half16 #ha(L + A) + +#define R_PPC_SDAREL16 32 // half16* S + A - _SDA_BASE_ +#define R_PPC_SECTOFF 33 // half16* R + A +#define R_PPC_SECTOFF_LO 34 // half16 #lo(R + A) +#define R_PPC_SECTOFF_HI 35 // half16 #hi(R + A) +#define R_PPC_SECTOFF_HA 36 // half16 #ha(R + A) +#define R_PPC_ADDR30 37 // word30 (S + A - P) >> 2 + +#define R_PPC_EMB_NADDR32 101 // uword32 N (A - S) +#define R_PPC_EMB_NADDR16 102 // uhalf16 Y (A - S) +#define R_PPC_EMB_NADDR16_LO 103 // uhalf16 N #lo(A - S) +#define R_PPC_EMB_NADDR16_HI 104 // uhalf16 N #hi(A - S) +#define R_PPC_EMB_NADDR16_HA 105 // uhalf16 N #ha(A - S) +#define R_PPC_EMB_SDAI16 106 // uhalf16 Y T +#define R_PPC_EMB_SDA2I16 107 // uhalf16 Y U +#define R_PPC_EMB_SDA2REL 108 // uhalf16 Y S + A - _SDA2_BASE_ +#define R_PPC_EMB_SDA21 109 // ulow21 N +#define R_PPC_EMB_MRKREF 110 // none N +#define R_PPC_EMB_RELSEC16 111 // uhalf16 Y V + A +#define R_PPC_EMB_RELST_LO 112 // uhalf16 N #lo(W + A) +#define R_PPC_EMB_RELST_HI 113 // uhalf16 N #hi(W + A) +#define R_PPC_EMB_RELST_HA 114 // uhalf16 N #ha(W + A) +#define R_PPC_EMB_BIT_FLD 115 // uword32 Y +#define R_PPC_EMB_RELSDA 116 // uhalf16 Y + +#define EnqueueTail(queue, moduleInfo, link) \ + do { \ + OSModuleInfo* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (moduleInfo); \ + else \ + __prev->link.next = (moduleInfo); \ + (moduleInfo)->link.prev = __prev; \ + (moduleInfo)->link.next = NULL; \ + (queue)->tail = (moduleInfo); \ + } while (0) + +#define DequeueItem(queue, moduleInfo, link) \ + do { \ + OSModuleInfo* __next; \ + OSModuleInfo* __prev; \ + \ + __next = (moduleInfo)->link.next; \ + __prev = (moduleInfo)->link.prev; \ + \ + if (__next == NULL) \ + (queue)->tail = __prev; \ + else \ + __next->link.prev = __prev; \ + \ + if (__prev == NULL) \ + (queue)->head = __next; \ + else \ + __prev->link.next = __next; \ + } while (0) + +OSModuleQueue __OSModuleInfoList : (OS_BASE_CACHED | 0x30C8); + +#pragma dont_inline on + +__declspec(weak) void OSNotifyLink(OSModuleInfo* module) {} +__declspec(weak) void OSNotifyUnlink(OSModuleInfo* module) {} + +#pragma dont_inline reset + +void OSSetStringTable(void* string_table) { + __OSStringTable = string_table; +} + +static BOOL Relocate(OSModuleHeader* newModule, OSModuleHeader* module) { + OSModuleID idNew; + OSImportInfo* imp; + OSRel* rel; + OSSectionInfo* si; + OSSectionInfo* siFlush; + u32* p; + u32 offset; + u32 x; + + idNew = newModule ? newModule->info.id : 0; + for (imp = (OSImportInfo*)module->impOffset; + imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++) + { + if (imp->id == idNew) { + goto Found; + } + } + return FALSE; + +Found: + siFlush = 0; + for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) { + (u8*)p += rel->offset; + if (idNew) { + si = &OSGetSectionInfo(newModule)[rel->section]; + offset = OS_SECTIONINFO_OFFSET(si->offset); + } else { + offset = 0; + } + switch (rel->type) { + case R_PPC_NONE: + break; + case R_PPC_ADDR32: + x = offset + rel->addend; + *p = x; + break; + case R_PPC_ADDR24: + x = offset + rel->addend; + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_ADDR16: + x = offset + rel->addend; + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_LO: + x = offset + rel->addend; + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_HI: + x = offset + rel->addend; + *(u16*)p = (u16)(((x >> 16) & 0xffff)); + break; + case R_PPC_ADDR16_HA: + x = offset + rel->addend; + *(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff); + break; + case R_PPC_ADDR14: + case R_PPC_ADDR14_BRTAKEN: + case R_PPC_ADDR14_BRNTAKEN: + x = offset + rel->addend; + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_PPC_REL24: + x = offset + rel->addend - (u32)p; + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + x = offset + rel->addend - (u32)p; + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_DOLPHIN_NOP: + break; + case R_DOLPHIN_SECTION: + si = &OSGetSectionInfo(module)[rel->section]; + p = (u32*)OS_SECTIONINFO_OFFSET(si->offset); + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0; + break; + default: + OSReport("OSLink: unknown relocation type %3d\n", rel->type); + break; + } + } + + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + + return TRUE; +} + +static BOOL Link(OSModuleInfo* newModule, void* bss, BOOL fixed) { + u32 i; + OSSectionInfo* si; + OSModuleHeader* moduleHeader; + OSModuleInfo* moduleInfo; + OSImportInfo* imp; + + moduleHeader = (OSModuleHeader*)newModule; + moduleHeader->bssSection = 0; + + if (OS_MODULE_VERSION < newModule->version || + 2 <= newModule->version && + (moduleHeader->align && (u32)newModule % moduleHeader->align != 0 || + moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)) + { + return FALSE; + } + + EnqueueTail(&__OSModuleInfoList, newModule, link); + newModule->sectionInfoOffset += (u32)moduleHeader; + moduleHeader->relOffset += (u32)moduleHeader; + moduleHeader->impOffset += (u32)moduleHeader; + if (3 <= newModule->version) { + moduleHeader->fixSize += (u32)moduleHeader; + } + + for (i = 1; i < newModule->numSections; i++) { + si = &OSGetSectionInfo(newModule)[i]; + if (si->offset != 0) { + si->offset += (u32)moduleHeader; + } else if (si->size != 0) { + moduleHeader->bssSection = (u8)i; + si->offset = (u32)bss; + } + } + + for (imp = (OSImportInfo*)moduleHeader->impOffset; + imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) + { + imp->offset += (u32)moduleHeader; + } + + if (moduleHeader->prologSection != SHN_UNDEF) { + moduleHeader->prolog += + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->prologSection].offset); + } + + if (moduleHeader->epilogSection != SHN_UNDEF) { + moduleHeader->epilog += + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(newModule)[moduleHeader->epilogSection].offset); + } + + if (moduleHeader->unresolvedSection != SHN_UNDEF) { + moduleHeader->unresolved += OS_SECTIONINFO_OFFSET( + OSGetSectionInfo(newModule)[moduleHeader->unresolvedSection].offset); + } + + if (__OSStringTable) { + newModule->nameOffset += (u32)__OSStringTable; + } + + Relocate(0, moduleHeader); + + for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) { + Relocate(moduleHeader, (OSModuleHeader*)moduleInfo); + if (moduleInfo != newModule) { + Relocate((OSModuleHeader*)moduleInfo, moduleHeader); + } + } + + if (fixed) { + for (imp = (OSImportInfo*)moduleHeader->impOffset; + imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) + { + if (imp->id == 0 || imp->id == newModule->id) { + moduleHeader->impSize = (u32)((u8*)imp - (u8*)moduleHeader->impOffset); + break; + } + } + } + + memset(bss, 0, moduleHeader->bssSize); + + OSNotifyLink(newModule); + return TRUE; +} + +BOOL OSLink(OSModuleInfo* newModule, void* bss) { + return Link(newModule, bss, FALSE); +} + +BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss) { + if (OS_MODULE_VERSION < newModule->version || newModule->version < 3) { + return FALSE; + } + return Link(newModule, bss, TRUE); +} + +static BOOL Undo(OSModuleHeader* newModule, OSModuleHeader* module) { + OSModuleID idNew; + OSImportInfo* imp; + OSRel* rel; + OSSectionInfo* si; + OSSectionInfo* siFlush; + u32* p; + u32 offset; + u32 x; + + idNew = newModule->info.id; + for (imp = (OSImportInfo*)module->impOffset; + imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++) + { + if (imp->id == idNew) { + goto Found; + } + } + return FALSE; + +Found: + siFlush = 0; + for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) { + (u8*)p += rel->offset; + si = &OSGetSectionInfo(newModule)[rel->section]; + offset = OS_SECTIONINFO_OFFSET(si->offset); + x = 0; + switch (rel->type) { + case R_PPC_NONE: + break; + case R_PPC_ADDR32: + *p = x; + break; + case R_PPC_ADDR24: + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_ADDR16: + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_LO: + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_HI: + *(u16*)p = (u16)(((x >> 16) & 0xffff)); + break; + case R_PPC_ADDR16_HA: + *(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff); + break; + case R_PPC_ADDR14: + case R_PPC_ADDR14_BRTAKEN: + case R_PPC_ADDR14_BRNTAKEN: + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_PPC_REL24: + if (module->unresolvedSection != SHN_UNDEF) { + x = (u32)module->unresolved - (u32)p; + } + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_DOLPHIN_NOP: + break; + case R_DOLPHIN_SECTION: + si = &OSGetSectionInfo(module)[rel->section]; + p = (u32*)OS_SECTIONINFO_OFFSET(si->offset); + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0; + break; + default: + OSReport("OSUnlink: unknown relocation type %3d\n", rel->type); + break; + } + } + + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + + return TRUE; +} + +BOOL OSUnlink(OSModuleInfo* oldModule) { + OSModuleHeader* moduleHeader; + OSModuleInfo* moduleInfo; + u32 i; + OSSectionInfo* si; + OSImportInfo* imp; + + moduleHeader = (OSModuleHeader*)oldModule; + + DequeueItem(&__OSModuleInfoList, oldModule, link); + + for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) { + Undo(moduleHeader, (OSModuleHeader*)moduleInfo); + } + + OSNotifyUnlink(oldModule); + + if (__OSStringTable) { + oldModule->nameOffset -= (u32)__OSStringTable; + } + + if (moduleHeader->prologSection != SHN_UNDEF) { + moduleHeader->prolog -= + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->prologSection].offset); + } + + if (moduleHeader->epilogSection != SHN_UNDEF) { + moduleHeader->epilog -= + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->epilogSection].offset); + } + + if (moduleHeader->unresolvedSection != SHN_UNDEF) { + moduleHeader->unresolved -= OS_SECTIONINFO_OFFSET( + OSGetSectionInfo(oldModule)[moduleHeader->unresolvedSection].offset); + } + + for (imp = (OSImportInfo*)moduleHeader->impOffset; + imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) + { + imp->offset -= (u32)moduleHeader; + } + + for (i = 1; i < oldModule->numSections; i++) { + si = &OSGetSectionInfo(oldModule)[i]; + if (i == moduleHeader->bssSection) { + moduleHeader->bssSection = 0; + si->offset = 0; + } else if (si->offset != 0) { + si->offset -= (u32)moduleHeader; + } + } + moduleHeader->relOffset -= (u32)moduleHeader; + moduleHeader->impOffset -= (u32)moduleHeader; + oldModule->sectionInfoOffset -= (u32)moduleHeader; + + return TRUE; +} + +void __OSModuleInit(void) { + __OSModuleList.tail = NULL; + __OSModuleList.head = NULL; + __OSStringTable = NULL; +} diff --git a/src/dolphin/os/OSMemory.c b/src/dolphin/os/OSMemory.c new file mode 100644 index 000000000..da66c1446 --- /dev/null +++ b/src/dolphin/os/OSMemory.c @@ -0,0 +1,210 @@ +#include "dolphin/os/OSMemory.h" +#include "dolphin/os/OS.h" + +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) + +vu16 __MEMRegs[64] : 0xCC004000; + +extern OSErrorHandlerEx __OSErrorTable[16]; + +static BOOL OnReset(BOOL final) { + if (final != FALSE) { + __MEMRegs[8] = 0xFF; + __OSMaskInterrupts(OS_INTERRUPTMASK_MEM_RESET); + } + return TRUE; +} + +static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + u32 addr; + u32 cause; + + cause = __MEMRegs[0xf]; + addr = (((u32)__MEMRegs[0x12] & 0x3ff) << 16) | __MEMRegs[0x11]; + __MEMRegs[0x10] = 0; + + if (__OSErrorTable[EXCEPTION_MEMORY_PROTECTION]) { + __OSErrorTable[EXCEPTION_MEMORY_PROTECTION](EXCEPTION_MEMORY_PROTECTION, context, cause, + addr); + return; + } + + __OSUnhandledException(EXCEPTION_MEMORY_PROTECTION, context, cause, addr); +} + +void OSProtectRange(u32 chan, void* addr, u32 nBytes, u32 control) { + BOOL enabled; + u32 start; + u32 end; + u16 reg; + if (4 <= chan) { + return; + } + + control &= OS_PROTECT_CONTROL_RDWR; + + end = (u32)addr + nBytes; + start = TRUNC(addr, 1u << 10); + end = ROUND(end, 1u << 10); + + DCFlushRange((void*)start, end - start); + + enabled = OSDisableInterrupts(); + + __OSMaskInterrupts(OS_INTERRUPTMASK(OS_INTR_MEM_0 + chan)); + + __MEMRegs[0 + 2 * chan] = (u16)(start >> 10); + __MEMRegs[1 + 2 * chan] = (u16)(end >> 10); + + reg = __MEMRegs[8]; + reg &= ~(OS_PROTECT_CONTROL_RDWR << 2 * chan); + reg |= control << 2 * chan; + __MEMRegs[8] = reg; + + if (control != OS_PROTECT_CONTROL_RDWR) { + __OSUnmaskInterrupts(OS_INTERRUPTMASK(OS_INTR_MEM_0 + chan)); + } + + OSRestoreInterrupts(enabled); +} + +static asm void Config24MB(void) { + // clang-format off + nofralloc + + li r7, 0 + lis r4, 0x0000 + addi r4, r4, 0x0002 + lis r3, 0x8000 + addi r3, r3, 0x01FF + lis r6, 0x0100 + addi r6, r6, 0x0002 + lis r5, 0x8100 + addi r5, r5, 0x00FF + isync + mtdbatu 0, r7 + mtdbatl 0, r4 + mtdbatu 0, r3 + isync + mtibatu 0, r7 + mtibatl 0, r4 + mtibatu 0, r3 + isync + mtdbatu 2, r7 + mtdbatl 2, r6 + mtdbatu 2, r5 + isync + mtibatu 2, r7 + mtibatl 2, r6 + mtibatu 2, r5 + isync + mfmsr r3 + ori r3, r3, 0x30 + mtspr 0x1b, r3 + mflr r3 + mtspr 0x1a, r3 + rfi + // clang-format on +} + +static asm void Config48MB(void) { + // clang-format off + nofralloc + + li r7, 0 + lis r4, 0x0000 + addi r4, r4, 0x0002 + lis r3, 0x8000 + addi r3, r3, 0x03FF + lis r6, 0x0200 + addi r6, r6, 0x0002 + lis r5, 0x8200 + addi r5, r5, 0x01FF + isync + mtdbatu 0, r7 + mtdbatl 0, r4 + mtdbatu 0, r3 + isync + mtibatu 0, r7 + mtibatl 0, r4 + mtibatu 0, r3 + isync + mtdbatu 2, r7 + mtdbatl 2, r6 + mtdbatu 2, r5 + isync + mtibatu 2, r7 + mtibatl 2, r6 + mtibatu 2, r5 + isync + mfmsr r3 + ori r3, r3, 0x30 + mtspr 0x1b, r3 + mflr r3 + mtspr 0x1a, r3 + rfi + // clang-format on +} + +static asm void RealMode(register u32 config) { + // clang-format off + nofralloc + + clrlwi config, config, 2 + mtspr 0x1a, config + mfmsr config + rlwinm config, config, 0, 0x1c, 0x19 + mtspr 0x1b, config + rfi + // clang-format on +} + +static OSResetFunctionInfo ResetFunctionInfo = { + OnReset, + 0x7F, +}; + +inline u32 OSGetPhysicalMemSize() { + return *(u32*)(OSPhysicalToCached(0x0028)); +} + +inline u32 OSGetConsoleSimulatedMemSize() { + return *(u32*)(OSPhysicalToCached(0x00F0)); +} + +void __OSInitMemoryProtection() { + u32 padding[8]; + u32 simulatedSize; + BOOL enabled; + simulatedSize = OSGetConsoleSimulatedMemSize(); + enabled = OSDisableInterrupts(); + + __MEMRegs[16] = 0; + __MEMRegs[8] = 0xFF; + + __OSMaskInterrupts(OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | + OS_INTERRUPTMASK_MEM_3); + __OSSetInterruptHandler(OS_INTR_MEM_0, MEMIntrruptHandler); + __OSSetInterruptHandler(OS_INTR_MEM_1, MEMIntrruptHandler); + __OSSetInterruptHandler(OS_INTR_MEM_2, MEMIntrruptHandler); + __OSSetInterruptHandler(OS_INTR_MEM_3, MEMIntrruptHandler); + __OSSetInterruptHandler(OS_INTR_MEM_ADDRESS, MEMIntrruptHandler); + OSRegisterResetFunction(&ResetFunctionInfo); + + if (OSGetConsoleSimulatedMemSize() < OSGetPhysicalMemSize() && + OSGetConsoleSimulatedMemSize() == 0x1800000) + { + DCInvalidateRange((void*)0x81800000, 0x1800000); + __MEMRegs[20] = 2; + } + + if (simulatedSize <= 0x1800000) { + RealMode((u32)&Config24MB); + } else if (simulatedSize <= 0x3000000) { + RealMode((u32)&Config48MB); + } + + __OSUnmaskInterrupts(OS_INTERRUPTMASK_MEM_ADDRESS); + OSRestoreInterrupts(enabled); +} diff --git a/src/dolphin/os/OSMessage.c b/src/dolphin/os/OSMessage.c new file mode 100644 index 000000000..2765b8070 --- /dev/null +++ b/src/dolphin/os/OSMessage.c @@ -0,0 +1,87 @@ +#include "dolphin/os/OSMessage.h" + +void OSInitMessageQueue(OSMessageQueue* mq, OSMessage* msgArray, s32 msgCount) { + OSInitThreadQueue(&mq->sending_queue); + OSInitThreadQueue(&mq->receiving_queue); + mq->message_array = msgArray; + mq->num_messages = msgCount; + mq->first_index = 0; + mq->num_used = 0; +} + +BOOL OSSendMessage(OSMessageQueue* mq, OSMessage msg, s32 flags) { + BOOL enabled; + s32 lastIndex; + + enabled = OSDisableInterrupts(); + + while (mq->num_messages <= mq->num_used) { + if (!(flags & OS_MESSAGE_BLOCK)) { + OSRestoreInterrupts(enabled); + return FALSE; + } else { + OSSleepThread(&mq->sending_queue); + } + } + + lastIndex = (mq->first_index + mq->num_used) % mq->num_messages; + mq->message_array[lastIndex] = msg; + mq->num_used++; + + OSWakeupThread(&mq->receiving_queue); + + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL OSReceiveMessage(OSMessageQueue* mq, OSMessage* msg, s32 flags) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + + while (mq->num_used == 0) { + if (!(flags & OS_MESSAGE_BLOCK)) { + OSRestoreInterrupts(enabled); + return FALSE; + } else { + OSSleepThread(&mq->receiving_queue); + } + } + + if (msg != NULL) { + *msg = mq->message_array[mq->first_index]; + } + mq->first_index = (mq->first_index + 1) % mq->num_messages; + mq->num_used--; + + OSWakeupThread(&mq->sending_queue); + + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL OSJamMessage(OSMessageQueue* queue, void* msg, s32 flags) { + s32 lastMesg; + u32 interrupt; + + interrupt = OSDisableInterrupts(); + + while (queue->num_messages <= queue->num_used) { + if (!(flags & OS_MSG_PERSISTENT)) { + OSRestoreInterrupts(interrupt); + return FALSE; + } + + OSSleepThread(&queue->sending_queue); + } + + // Find last position in queue + lastMesg = (queue->first_index + queue->num_messages - 1) % queue->num_messages; + queue->first_index = lastMesg; + queue->message_array[queue->first_index] = msg; + queue->num_used++; + + OSWakeupThread(&queue->receiving_queue); + OSRestoreInterrupts(interrupt); + return TRUE; +} diff --git a/src/dolphin/os/OSMutex.c b/src/dolphin/os/OSMutex.c new file mode 100644 index 000000000..8a6dd25e3 --- /dev/null +++ b/src/dolphin/os/OSMutex.c @@ -0,0 +1,231 @@ +#include "dolphin/os/OSMutex.h" +#include "dolphin/os/OS.h" + +#define PushTail(queue, mutex, link) \ + do { \ + OSMutex* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (mutex); \ + else \ + __prev->link.next = (mutex); \ + (mutex)->link.prev = __prev; \ + (mutex)->link.next = NULL; \ + (queue)->tail = (mutex); \ + } while (0) + +#define PopHead(queue, mutex, link) \ + do { \ + OSMutex* __next; \ + \ + (mutex) = (queue)->head; \ + __next = (mutex)->link.next; \ + if (__next == NULL) \ + (queue)->tail = NULL; \ + else \ + __next->link.prev = NULL; \ + (queue)->head = __next; \ + } while (0) + +#define PopItem(queue, mutex, link) \ + do { \ + OSMutex* __next; \ + OSMutex* __prev; \ + \ + __next = (mutex)->link.next; \ + __prev = (mutex)->link.prev; \ + \ + if (__next == NULL) \ + (queue)->tail = __prev; \ + else \ + __next->link.prev = __prev; \ + \ + if (__prev == NULL) \ + (queue)->head = __next; \ + else \ + __prev->link.next = __next; \ + } while (0) + +// +// Declarations: +// + +void OSInitMutex(OSMutex* mutex) { + OSInitThreadQueue(&mutex->queue); + mutex->thread = 0; + mutex->count = 0; +} + +void OSLockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + OSThread* ownerThread; + + while (TRUE) { + ownerThread = ((OSMutex*)mutex)->thread; + if (ownerThread == 0) { + mutex->thread = currentThread; + mutex->count++; + PushTail(¤tThread->owned_mutexes, mutex, link); + break; + } else if (ownerThread == currentThread) { + mutex->count++; + break; + } else { + currentThread->mutex = mutex; + __OSPromoteThread(mutex->thread, currentThread->effective_priority); + OSSleepThread(&mutex->queue); + currentThread->mutex = 0; + } + } + OSRestoreInterrupts(enabled); +} + +void OSUnlockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + if (mutex->thread == currentThread && --mutex->count == 0) { + PopItem(¤tThread->owned_mutexes, mutex, link); + mutex->thread = NULL; + if ((s32)currentThread->effective_priority < (s32)currentThread->base_priority) { + currentThread->effective_priority = __OSGetEffectivePriority(currentThread); + } + + OSWakeupThread(&mutex->queue); + } + OSRestoreInterrupts(enabled); +} + +void __OSUnlockAllMutex(OSThread* thread) { + OSMutex* mutex; + + while (thread->owned_mutexes.head) { + PopHead(&thread->owned_mutexes, mutex, link); + mutex->count = 0; + mutex->thread = NULL; + OSWakeupThread(&mutex->queue); + } +} + + +BOOL OSTryLockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + BOOL locked; + if (mutex->thread == 0) { + mutex->thread = currentThread; + mutex->count++; + PushTail(¤tThread->owned_mutexes, mutex, link); + locked = TRUE; + } else if (mutex->thread == currentThread) { + mutex->count++; + locked = TRUE; + } else { + locked = FALSE; + } + OSRestoreInterrupts(enabled); + return locked; +} + +void OSInitCond(OSCond* cond) { OSInitThreadQueue(&cond->queue); } + +void OSWaitCond(OSCond* cond, OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + s32 count; + + if (mutex->thread == currentThread) { + count = mutex->count; + mutex->count = 0; + PopItem(¤tThread->owned_mutexes, mutex, link); + mutex->thread = NULL; + + if (currentThread->effective_priority < (s32)currentThread->base_priority) { + currentThread->effective_priority = __OSGetEffectivePriority(currentThread); + } + + OSDisableScheduler(); + OSWakeupThread(&mutex->queue); + OSEnableScheduler(); + OSSleepThread(&cond->queue); + OSLockMutex(mutex); + mutex->count = count; + } + + OSRestoreInterrupts(enabled); +} + +void OSSignalCond(OSCond* cond) { + OSWakeupThread(&cond->queue); +} + +static BOOL IsMember(OSMutexQueue* queue, OSMutex* mutex) { + OSMutex* member; + + for (member = queue->head; member; member = member->link.next) { + if (mutex == member) + return TRUE; + } + return FALSE; +} + +BOOL __OSCheckMutex(OSMutex* mutex) { + OSThread* thread; + OSThreadQueue* queue; + OSPriority priority = 0; + + queue = &mutex->queue; + if (!(queue->head == NULL || queue->head->link.prev == NULL)) + return FALSE; + if (!(queue->tail == NULL || queue->tail->link.next == NULL)) + return FALSE; + for (thread = queue->head; thread; thread = thread->link.next) { + if (!(thread->link.next == NULL || thread == thread->link.next->link.prev)) + return FALSE; + if (!(thread->link.prev == NULL || thread == thread->link.prev->link.next)) + return FALSE; + + if (thread->state != OS_THREAD_STATE_WAITING) + return FALSE; + + if (thread->effective_priority < priority) + return FALSE; + priority = thread->effective_priority; + } + + if (mutex->thread) { + if (mutex->count <= 0) + return FALSE; + } else { + if (0 != mutex->count) + return FALSE; + } + + return TRUE; +} + +BOOL __OSCheckDeadLock(OSThread* thread) { + OSMutex* mutex; + + mutex = thread->mutex; + while (mutex && mutex->thread) { + if (mutex->thread == thread) + return TRUE; + mutex = mutex->thread->mutex; + } + return FALSE; +} + +BOOL __OSCheckMutexes(OSThread* thread) { + OSMutex* mutex; + + for (mutex = thread->owned_mutexes.head; mutex; mutex = mutex->link.next) { + if (mutex->thread != thread) + return FALSE; + if (!__OSCheckMutex(mutex)) + return FALSE; + } + return TRUE; +} diff --git a/src/dolphin/os/OSReboot.c b/src/dolphin/os/OSReboot.c new file mode 100644 index 000000000..66b269b56 --- /dev/null +++ b/src/dolphin/os/OSReboot.c @@ -0,0 +1,29 @@ +#include "dolphin/os/OSReboot.h" +#include "dolphin/os/OSContext.h" +#include "dolphin/os/OSExec.h" + +void __OSReboot(u32 resetCode, u32 bootDol) { + struct OSContext context; + char* iVar1; + OSDisableInterrupts(); + OSSetArenaLo((void*)0x81280000); + OSSetArenaHi((void*)0x812f0000); + OSClearContext(&context); + OSSetCurrentContext(&context); + iVar1 = NULL; + __OSBootDol(bootDol, resetCode | 0x80000000, &iVar1); +} + +static void* SaveStart; + +static void* SaveEnd; + +void OSSetSaveRegion(void* start, void* end) { + SaveStart = start; + SaveEnd = end; +} + +void OSGetSaveRegion(void** start, void** end) { + *start = SaveStart; + *end = SaveEnd; +} diff --git a/src/dolphin/os/OSReset.c b/src/dolphin/os/OSReset.c new file mode 100644 index 000000000..77934c6f4 --- /dev/null +++ b/src/dolphin/os/OSReset.c @@ -0,0 +1,210 @@ +#include "dolphin/os/OSReset.h" +#include "dolphin/os/OS.h" + +vu16 __VIRegs[59] : 0xCC002000; +OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC); + +extern OSExecParams __OSRebootParams; + +static OSResetQueue ResetFunctionQueue; + +void OSRegisterResetFunction(OSResetFunctionInfo* func) { + OSResetFunctionInfo* tmp; + OSResetFunctionInfo* iter; + + for (iter = ResetFunctionQueue.first; iter && iter->priority <= func->priority; + iter = iter->next) + ; + + if (iter == NULL) { + tmp = ResetFunctionQueue.last; + if (tmp == NULL) { + ResetFunctionQueue.first = func; + } else { + tmp->next = func; + } + func->prev = tmp; + func->next = NULL; + ResetFunctionQueue.last = func; + return; + } + + func->next = iter; + tmp = iter->prev; + iter->prev = func; + func->prev = tmp; + if (tmp == NULL) { + ResetFunctionQueue.first = func; + return; + } + tmp->next = func; +} + +BOOL __OSCallResetFunctions(u32 arg0) { + OSResetFunctionInfo* iter; + s32 retCode = 0; + u32 priority = 0; + s32 temp; + + for (iter = ResetFunctionQueue.first; iter != NULL;) { + if (retCode != 0 && priority != iter->priority) + break; + temp = !iter->func(arg0); + priority = iter->priority; + iter = iter->next; + retCode |= temp; + } + retCode |= !__OSSyncSram(); + if (retCode) { + return 0; + } + return 1; +} + +static asm void Reset(register s32 param_0) { + // clang-format off + nofralloc + + b lbl_8033F7AC + +lbl_8033F790: + mfspr r8, 0x3f0 + ori r8, r8, 8 + mtspr 0x3f0, r8 + isync + sync + nop + b lbl_8033F7B0 + +lbl_8033F7AC: + b lbl_8033F7CC + +lbl_8033F7B0: + mftb r5, 0x10c + +lbl_8033F7B4: + mftb r6, 0x10c + subf r7, r5, r6 + cmplwi r7, 0x1124 + blt lbl_8033F7B4 + nop + b lbl_8033F7D0 + +lbl_8033F7CC: + b lbl_8033F7EC + +lbl_8033F7D0: + lis r8, 0xCC00 + ori r8, r8, 0x3000 + li r4, 3 + stw r4, 0x24(r8) + stw param_0, 0x24(r8) + nop + b lbl_8033F7F0 + +lbl_8033F7EC: + b lbl_8033F7F8 + +lbl_8033F7F0: + nop + b lbl_8033F7F0 + +lbl_8033F7F8: + b lbl_8033F790 + // clang-format on +} + +#pragma dont_inline on +static void KillThreads(void) { + OSThread* thread; + OSThread* next; + + for (thread = __OSActiveThreadQueue.head; thread; thread = next) { + next = thread->active_threads_link.next; + switch (thread->state) { + case 1: + case 4: + OSCancelThread(thread); + continue; + default: + continue; + } + } +} +#pragma dont_inline reset + +void __OSDoHotReset(s32 arg0) { + OSDisableInterrupts(); + __VIRegs[1] = 0; + ICFlashInvalidate(); + Reset(arg0 * 8); +} + +static u32 bootThisDol; + +void OSResetSystem(int reset, u32 resetCode, BOOL forceMenu) { + BOOL rc; + BOOL disableRecalibration; + u32 unk; + OSDisableScheduler(); + + if (reset == OS_RESET_HOTRESET && forceMenu) { + OSSram* sram; + + sram = __OSLockSram(); + sram->flags |= 0x40; + __OSUnlockSram(TRUE); + + resetCode = 0; + } + + if (reset == OS_RESET_SHUTDOWN || + (reset == OS_RESET_RESTART && (bootThisDol || resetCode + 0x3fff0000 == 0))) + { + __OSStopAudioSystem(); + disableRecalibration = __PADDisableRecalibration(TRUE); + while (!__OSCallResetFunctions(FALSE)) + ; + while (!__OSSyncSram()) + ; + OSDisableInterrupts(); + __OSCallResetFunctions(TRUE); + LCDisable(); + __PADDisableRecalibration(disableRecalibration); + KillThreads(); + } else { + __OSStopAudioSystem(); + while (!__OSCallResetFunctions(FALSE)) + ; + while (!__OSSyncSram()) + ; + OSDisableInterrupts(); + __OSCallResetFunctions(TRUE); + LCDisable(); + KillThreads(); + } + + if (reset == OS_RESET_HOTRESET) { + __OSDoHotReset(resetCode); + } else if (reset == OS_RESET_RESTART) { + if (forceMenu == TRUE) { + OSReport( + "OSResetSystem(): You can't specify TRUE to forceMenu if you restart. Ignored\n"); + } + OSEnableScheduler(); + __OSReboot(resetCode, bootThisDol); + } + memset(OSPhysicalToCached(0x40), 0, 0xcc - 0x40); + memset(OSPhysicalToCached(0xd4), 0, 0xe8 - 0xd4); + memset(OSPhysicalToCached(0xf4), 0, 0xf8 - 0xf4); + memset(OSPhysicalToCached(0x3000), 0, 0xc0); + memset(OSPhysicalToCached(0x30c8), 0, 0xd4 - 0xc8); + memset(OSPhysicalToCached(0x30e2), 0, 1); +} + +u32 OSGetResetCode(void) { + if (__OSRebootParams.valid) + return 0x80000000 | __OSRebootParams.restartCode; + + return ((__PIRegs[9] & ~7) >> 3); +} diff --git a/src/dolphin/os/OSResetSW.c b/src/dolphin/os/OSResetSW.c new file mode 100644 index 000000000..9fe625be7 --- /dev/null +++ b/src/dolphin/os/OSResetSW.c @@ -0,0 +1,92 @@ +#include "dolphin/os/OSResetSW.h" +#include "dolphin/os/OS.h" +#include "dolphin/os/OSReset.h" + +u8 GameChoice : (OS_BASE_CACHED | 0x30E3); + +void __OSResetSWInterruptHandler(__OSInterrupt interrupt, OSContext* context); + +static OSResetCallback ResetCallback; + +static BOOL Down; + +static BOOL LastState; + +static OSTime HoldUp; + +static OSTime HoldDown; + +void __OSResetSWInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + OSResetCallback callback; + + HoldDown = __OSGetSystemTime(); + while (__OSGetSystemTime() - HoldDown < OSMicrosecondsToTicks(100) && + !(__PIRegs[0] & 0x00010000)) { + ; + } + if (!(__PIRegs[0] & 0x00010000)) { + LastState = Down = TRUE; + __OSMaskInterrupts(OS_INTERRUPTMASK_PI_RSW); + if (ResetCallback) { + callback = ResetCallback; + ResetCallback = NULL; + callback(); + } + } + __PIRegs[0] = 2; +} + +BOOL OSGetResetButtonState(void) { + BOOL enabled = OSDisableInterrupts(); + BOOL state; + OSTime now = __OSGetSystemTime(); + u32 reg = __PIRegs[0]; + + if (!(reg & 0x00010000)) { + if (!Down) { + Down = TRUE; + state = HoldUp ? TRUE : FALSE; + HoldDown = now; + } else { + state = HoldUp || (OSMicrosecondsToTicks(100) < now - HoldDown) + ? TRUE + : FALSE; + } + } else if (Down) { + Down = FALSE; + state = LastState; + if (state) { + HoldUp = now; + } else { + HoldUp = 0; + } + } else if (HoldUp && (now - HoldUp < OSMillisecondsToTicks(40))) { + state = TRUE; + } else { + state = FALSE; + HoldUp = 0; + } + + LastState = state; + + if (GameChoice & 0x1F) { + OSTime fire = (GameChoice & 0x1F) * 60; + fire = __OSStartTime + OSSecondsToTicks(fire); + if (fire < now) { + now -= fire; + now = OSTicksToSeconds(now) / 2; + if ((now & 1) == 0) { + state = TRUE; + } else { + state = FALSE; + } + } + } + + OSRestoreInterrupts(enabled); + return state; +} + +BOOL OSGetResetSwitchState(void) { + return OSGetResetButtonState(); +} diff --git a/src/dolphin/os/OSRtc.c b/src/dolphin/os/OSRtc.c new file mode 100644 index 000000000..13b69ddd4 --- /dev/null +++ b/src/dolphin/os/OSRtc.c @@ -0,0 +1,251 @@ +#include "global.h" +#include "dolphin/os/OSRtc.h" +#include "dolphin/os/OSInterrupt.h" + +static void WriteSramCallback(s32 chan, OSContext* context); +static BOOL WriteSram(void* buffer, u32 offset, u32 size); +static BOOL UnlockSram(BOOL commit, u32 offset); + +static SramControlBlock Scb ALIGN_DECL(32); + +static void WriteSramCallback(s32 chan, OSContext* context) { + Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset); + if (Scb.sync) { + Scb.offset = RTC_SRAM_SIZE; + } +} + +static inline BOOL ReadSram(void* buffer) { + BOOL err; + u32 cmd; + + DCInvalidateRange(buffer, RTC_SRAM_SIZE); + + if (!EXILock(RTC_CHAN, RTC_DEV, 0)) { + return FALSE; + } + if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + cmd = RTC_CMD_READ | RTC_SRAM_ADDR; + err = FALSE; + err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDma(RTC_CHAN, buffer, RTC_SRAM_SIZE, 0, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + + return !err; +} + +BOOL WriteSram(void* buffer, u32 offset, u32 size) { + BOOL err; + u32 cmd; + + if (!EXILock(RTC_CHAN, RTC_DEV, WriteSramCallback)) { + return FALSE; + } + if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + offset <<= 6; + cmd = RTC_CMD_WRITE | RTC_SRAM_ADDR + offset; + err = FALSE; + err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIImmEx(RTC_CHAN, buffer, (s32)size, 1); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + + return !err; +} + +void __OSInitSram(void) { + Scb.locked = Scb.enabled = FALSE; + Scb.sync = ReadSram(Scb.sram); + Scb.offset = RTC_SRAM_SIZE; + OSSetGbsMode(OSGetGbsMode()); +} + +static void* LockSram(u32 offset) { + BOOL enabled; + enabled = OSDisableInterrupts(); + + if (Scb.locked != FALSE) { + OSRestoreInterrupts(enabled); + return NULL; + } + + Scb.enabled = enabled; + Scb.locked = TRUE; + + return Scb.sram + offset; +} + +OSSram* __OSLockSram() { + return LockSram(0); +} + +OSSramEx* __OSLockSramEx() { + return LockSram(sizeof(OSSram)); +} + +static BOOL UnlockSram(BOOL commit, u32 offset) { + u16* p; + + if (commit) { + if (offset == 0) { + OSSram* sram = (OSSram*)Scb.sram; + + if (2u < (sram->flags & 3)) { + sram->flags &= ~3; + } + + sram->checkSum = sram->checkSumInv = 0; + for (p = (u16*)&sram->counterBias; p < (u16*)(Scb.sram + sizeof(OSSram)); p++) { + sram->checkSum += *p; + sram->checkSumInv += ~*p; + } + } + + if (offset < Scb.offset) { + Scb.offset = offset; + } + + if (Scb.offset <= 0x14) { + OSSramEx* sram = (OSSramEx*)(Scb.sram + sizeof(OSSram)); + if (((u32)sram->gbs & 0x7c00) == 0x5000 || ((u32)sram->gbs & 0xc0) == 0xc0) { + sram->gbs = 0; + } + } + + Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset); + if (Scb.sync) { + Scb.offset = RTC_SRAM_SIZE; + } + } + Scb.locked = FALSE; + OSRestoreInterrupts(Scb.enabled); + return Scb.sync; +} + +BOOL __OSUnlockSram(BOOL commit) { + return UnlockSram(commit, 0); +} + +BOOL __OSUnlockSramEx(BOOL commit) { + return UnlockSram(commit, sizeof(OSSram)); +} + +BOOL __OSSyncSram(void) { + return Scb.sync; +} + +u32 OSGetSoundMode() { + OSSram* sram; + u32 mode; + + sram = __OSLockSram(); + mode = (sram->flags & 0x4) ? OS_SOUND_MODE_STEREO : OS_SOUND_MODE_MONO; + __OSUnlockSram(FALSE); + return mode; +} + +void OSSetSoundMode(u32 mode) { + OSSram* sram; + mode <<= 2; + mode &= 4; + + sram = __OSLockSram(); + if (mode == (sram->flags & 4)) { + __OSUnlockSram(FALSE); + return; + } + + sram->flags &= ~4; + sram->flags |= mode; + __OSUnlockSram(TRUE); +} + +u32 OSGetProgressiveMode() { + OSSram* sram; + u32 mode; + + sram = __OSLockSram(); + mode = (sram->flags & 0x80) >> 7; + __OSUnlockSram(FALSE); + return mode; +} + + +void OSSetProgressiveMode(u32 mode) { + OSSram* sram; + mode <<= 7; + mode &= 0x80; + + sram = __OSLockSram(); + if (mode == (sram->flags & 0x80)) { + __OSUnlockSram(FALSE); + return; + } + + sram->flags &= ~0x80; + sram->flags |= mode; + __OSUnlockSram(TRUE); +} + +u16 OSGetWirelessID(s32 channel) { + OSSramEx* sram; + u16 id; + + sram = __OSLockSramEx(); + id = sram->wirelessPadID[channel]; + __OSUnlockSramEx(FALSE); + return id; +} + +void OSSetWirelessID(s32 channel, u16 id) { + OSSramEx* sram; + + sram = __OSLockSramEx(); + if (sram->wirelessPadID[channel] != id) { + sram->wirelessPadID[channel] = id; + __OSUnlockSramEx(TRUE); + return; + } + + __OSUnlockSramEx(FALSE); +} + +u16 OSGetGbsMode() { + OSSramEx* sram; + u16 gbs; + + sram = __OSLockSramEx(); + gbs = sram->gbs; + __OSUnlockSramEx(FALSE); + return gbs; +} + +void OSSetGbsMode(u16 mode) { + OSSramEx* sram; + + if (((u32)mode & 0x7c00) == 0x5000 || ((u32)mode & 0xc0) == 0xc0) { + mode = 0; + } + + sram = __OSLockSramEx(); + + if (mode == sram->gbs) { + __OSUnlockSramEx(FALSE); + return; + } + sram->gbs = mode; + + __OSUnlockSramEx(TRUE); +} diff --git a/src/dolphin/os/OSSync.c b/src/dolphin/os/OSSync.c new file mode 100644 index 000000000..fd7b70863 --- /dev/null +++ b/src/dolphin/os/OSSync.c @@ -0,0 +1,32 @@ +#include "dolphin/os/OSSync.h" +#include "dolphin/os/OS.h" + +void __OSSystemCallVectorStart(); +void __OSSystemCallVectorEnd(); + +static asm void SystemCallVector(void) { + // clang-format off + nofralloc + +entry __OSSystemCallVectorStart + mfspr r9, HID0 + ori r10, r9, 8 + mtspr HID0, r10 + isync + sync + mtspr HID0, r9 + rfi + +entry __OSSystemCallVectorEnd + nop + // clang-format on +} + +void __OSInitSystemCall(void) { + void* addr = OSPhysicalToCached(0x00C00); + memcpy(addr, __OSSystemCallVectorStart, + (size_t)__OSSystemCallVectorEnd - (size_t)__OSSystemCallVectorStart); + DCFlushRangeNoSync(addr, 0x100); + __sync(); + ICInvalidateRange(addr, 0x100); +} diff --git a/src/dolphin/os/OSThread.c b/src/dolphin/os/OSThread.c new file mode 100644 index 000000000..6537c1b38 --- /dev/null +++ b/src/dolphin/os/OSThread.c @@ -0,0 +1,901 @@ +// +// Generated By: dol2asm +// Translation Unit: OSThread +// + +#include "global.h" +#include "dolphin/os/OSThread.h" +#include "dolphin/os/OS.h" + +OSThread* __OSCurrentThread : OS_BASE_CACHED + 0x00E4; +OSThreadQueue __OSActiveThreadQueue : OS_BASE_CACHED + 0x00DC; +volatile OSContext __OSCurrentContext : OS_BASE_CACHED + 0x00D4; +volatile OSContext* __OSFPUContext : OS_BASE_CACHED + 0x00D8; + +#define AddTail(queue, thread, link) \ + do { \ + OSThread* prev; \ + \ + prev = (queue)->tail; \ + if (prev == NULL) \ + (queue)->head = (thread); \ + else \ + prev->link.next = (thread); \ + (thread)->link.prev = prev; \ + (thread)->link.next = NULL; \ + (queue)->tail = (thread); \ + } while (0) + +#define AddPrio(queue, thread, link) \ + do { \ + OSThread *prev, *next; \ + \ + for (next = (queue)->head; next && next->effective_priority <= thread->effective_priority; \ + next = next->link.next) \ + ; \ + if (next == NULL) \ + AddTail(queue, thread, link); \ + else { \ + (thread)->link.next = next; \ + prev = next->link.prev; \ + next->link.prev = (thread); \ + (thread)->link.prev = prev; \ + if (prev == NULL) \ + (queue)->head = (thread); \ + else \ + prev->link.next = (thread); \ + } \ + } while (0) + +#define RemoveItem(queue, thread, link) \ + do { \ + OSThread *next, *prev; \ + next = (thread)->link.next; \ + prev = (thread)->link.prev; \ + if (next == NULL) \ + (queue)->tail = prev; \ + else \ + next->link.prev = prev; \ + if (prev == NULL) \ + (queue)->head = next; \ + else \ + prev->link.next = next; \ + } while (0) + +#define RemoveHead(queue, thread, link) \ + do { \ + OSThread* __next; \ + (thread) = (queue)->head; \ + __next = (thread)->link.next; \ + if (__next == NULL) \ + (queue)->tail = NULL; \ + else \ + __next->link.prev = NULL; \ + (queue)->head = __next; \ + } while (0) + +// +// External References: +// + +extern OSErrorHandlerEx __OSErrorTable[17]; +extern u32 __OSFpscrEnableBits; +void _epilog(); + +// +// Declarations: +// + +static void DefaultSwitchThreadCallback(OSThread* from, OSThread* to) {} + +static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback; + +OSSwitchThreadCallback OSSetSwitchThreadCallback(OSSwitchThreadCallback func) { + BOOL enable = OSDisableInterrupts(); + OSSwitchThreadCallback prev = SwitchThreadCallback; + OSSwitchThreadCallback temp; + if (func) { + temp = func; + } else { + temp = DefaultSwitchThreadCallback; + } + SwitchThreadCallback = temp; + + OSRestoreInterrupts(enable); + if (prev == DefaultSwitchThreadCallback) { + return NULL; + } + + return prev; +} + +static OSThreadQueue RunQueue[32]; + +#pragma push +#pragma force_active on +static OSThread IdleThread; +#pragma pop + +#pragma push +#pragma force_active on +static OSThread DefaultThread; +#pragma pop + +#pragma push +#pragma force_active on +static OSContext IdleContext; +#pragma pop + +static vu32 RunQueueBits; + +static volatile BOOL RunQueueHint; + +static volatile s32 Reschedule; + +extern u8 _stack_end[]; +extern u8 _stack_addr[]; + +static inline void OSInitMutexQueue(OSMutexQueue* queue) { + queue->head = queue->tail = NULL; +} + +static inline void OSSetCurrentThread(OSThread* thread) { + SwitchThreadCallback(__OSCurrentThread, thread); + __OSCurrentThread = thread; +} + +void __OSThreadInit() { + OSThread* thread = &DefaultThread; + int prio; + + thread->state = OS_THREAD_STATE_RUNNING; + thread->attributes = OS_THREAD_ATTR_DETACH; + thread->effective_priority = thread->base_priority = 16; + thread->suspend_count = 0; + thread->exit_value = (void*)-1; + thread->mutex = NULL; + OSInitThreadQueue(&thread->join_queue); + OSInitMutexQueue(&thread->owned_mutexes); + + __OSFPUContext = &thread->context; + + OSClearContext(&thread->context); + OSSetCurrentContext(&thread->context); + thread->stack_base = (void*)_stack_addr; + thread->stack_end = (void*)_stack_end; + *(thread->stack_end) = OS_THREAD_STACK_MAGIC; + + OSSetCurrentThread(thread); + OSClearStack(0); + + RunQueueBits = 0; + RunQueueHint = FALSE; + for (prio = OS_PRIORITY_MIN; prio <= OS_PRIORITY_MAX; ++prio) { + OSInitThreadQueue(&RunQueue[prio]); + } + + OSInitThreadQueue(&__OSActiveThreadQueue); + AddTail(&__OSActiveThreadQueue, thread, active_threads_link); + OSClearContext(&IdleContext); + Reschedule = 0; +} + +void OSInitThreadQueue(OSThreadQueue* queue) { + queue->tail = NULL; + queue->head = NULL; +} + +OSThread* OSGetCurrentThread(void) { + return OS_CURRENT_THREAD; +} + +BOOL OSIsThreadTerminated(OSThread* thread) { + return thread->state == OS_THREAD_STATE_DEAD || thread->state == OS_THREAD_STATE_UNINITIALIZED ? + TRUE : + FALSE; +} + +s32 OSDisableScheduler(void) { + BOOL intr = OSDisableInterrupts(); + s32 ret = Reschedule++; + OSRestoreInterrupts(intr); + return ret; +} + +s32 OSEnableScheduler(void) { + BOOL intr = OSDisableInterrupts(); + s32 ret = Reschedule--; + OSRestoreInterrupts(intr); + return ret; +} + +static inline void SetRun(OSThread* thread) { + thread->queue = &RunQueue[thread->effective_priority]; + AddTail(thread->queue, thread, link); + RunQueueBits |= 1u << (OS_PRIORITY_MAX - thread->effective_priority); + RunQueueHint = TRUE; +} + +#pragma dont_inline on +static void UnsetRun(OSThread* thread) { + OSThreadQueue* queue; + OSThread* next; + OSThread* prev; + + prev = thread->link.next; + queue = thread->queue; + next = thread->link.prev; + + if (prev == NULL) { + queue->tail = next; + } else { + prev->link.prev = next; + } + + if (next == NULL) { + queue->head = prev; + } else { + next->link.next = prev; + } + + if (queue->head == NULL) { + RunQueueBits &= ~(1 << 31 - thread->effective_priority); + } + + thread->queue = NULL; +} +#pragma dont_inline reset + +s32 __OSGetEffectivePriority(OSThread* thread) { + s32 prio = thread->base_priority; + + OSMutex* mutex; + for (mutex = thread->owned_mutexes.head; mutex != NULL; mutex = mutex->link.next) { + OSThread* mutexThread = mutex->queue.head; + if (mutexThread != NULL && mutexThread->effective_priority < prio) { + prio = mutexThread->effective_priority; + } + } + + return prio; +} + +static OSThread* SetEffectivePriority(OSThread* thread, s32 priority) { + switch (thread->state) { + case OS_THREAD_STATE_READY: + UnsetRun(thread); + thread->effective_priority = priority; + SetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + RemoveItem(thread->queue, thread, link); + thread->effective_priority = priority; + AddPrio(thread->queue, thread, link); + if (thread->mutex) { + return thread->mutex->thread; + } + break; + case OS_THREAD_STATE_RUNNING: + RunQueueHint = TRUE; + thread->effective_priority = priority; + break; + } + return NULL; +} + +static void UpdatePriority(OSThread* thread) { + OSPriority priority; + + do { + if (0 < thread->suspend_count) { + break; + } + priority = __OSGetEffectivePriority(thread); + if (thread->effective_priority == priority) { + break; + } + thread = SetEffectivePriority(thread, priority); + } while (thread); +} + +void __OSPromoteThread(OSThread* thread, s32 priority) { + do { + if (thread->suspend_count > 0 || thread->effective_priority <= priority) { + break; + } + + thread = SetEffectivePriority(thread, priority); + } while (thread != NULL); +} + +static inline void __OSSwitchThread(OSThread* nextThread) { + OSSetCurrentThread(nextThread); + OSSetCurrentContext(&nextThread->context); + OSLoadContext(&nextThread->context); +} + +inline OSThread* i_OSGetCurrentThread(void) { + return OS_CURRENT_THREAD; +} + +static OSThread* SelectThread(BOOL yield) { + OSContext* currentContext; + OSThread* currentThread; + OSThread* nextThread; + OSPriority priority; + OSThreadQueue* queue; + + if (0 < Reschedule) { + return 0; + } + + currentContext = OSGetCurrentContext(); + currentThread = i_OSGetCurrentThread(); + if (currentContext != ¤tThread->context) { + return 0; + } + + if (currentThread) { + if (currentThread->state == OS_THREAD_STATE_RUNNING) { + if (!yield) { + priority = __cntlzw(RunQueueBits); + if (currentThread->effective_priority <= priority) { + return 0; + } + } + currentThread->state = OS_THREAD_STATE_READY; + SetRun(currentThread); + } + + if (!(currentThread->context.state & OS_CONTEXT_STATE_EXC) && + OSSaveContext(¤tThread->context)) + { + return 0; + } + } + + if (RunQueueBits == 0) { + OSSetCurrentThread(NULL); + OSSetCurrentContext(&IdleContext); + do { + OSEnableInterrupts(); + while (RunQueueBits == 0) + ; + OSDisableInterrupts(); + } while (RunQueueBits == 0); + + OSClearContext(&IdleContext); + } + + RunQueueHint = FALSE; + + priority = __cntlzw(RunQueueBits); + queue = &RunQueue[priority]; + RemoveHead(queue, nextThread, link); + if (queue->head == 0) { + RunQueueBits &= ~(1u << (OS_PRIORITY_MAX - priority)); + } + nextThread->queue = NULL; + nextThread->state = OS_THREAD_STATE_RUNNING; + __OSSwitchThread(nextThread); + return nextThread; +} + +void __OSReschedule(void) { + if (!RunQueueHint) { + return; + } + + SelectThread(FALSE); +} + +void OSYieldThread(void) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + SelectThread(TRUE); + OSRestoreInterrupts(enabled); +} + +BOOL OSCreateThread(OSThread* thread_, void* func, void* param, void* stackBase, u32 stackSize, + s32 priority, u16 attribute) { + BOOL enabled; + u32 i; + u32* stack; + OSThread* thread; + u32 stack1, stack2; + + if (priority < 0 || priority > 31) { + return FALSE; + } + + thread = thread_; + + thread->state = OS_THREAD_STATE_READY; + thread->attributes = attribute & 1; + thread->base_priority = priority; + thread->effective_priority = priority; + thread->suspend_count = 1; + thread->exit_value = (void*)-1; + thread->mutex = NULL; + thread->join_queue.tail = NULL; + thread->join_queue.head = NULL; + thread->owned_mutexes.tail = NULL; + thread->owned_mutexes.head = NULL; + stack = (u32*)((u32)stackBase & 0xfffffff8); + stack[-2] = 0; + stack[-1] = 0; + OSInitContext(&thread->context, (u32)func, (u32)stack - 8); + thread->context.lr = (u32)OSExitThread; + thread->context.gpr[3] = (u32)param; + thread->stack_base = (u8*)stackBase; + thread->stack_end = (void*)((u32)stackBase - stackSize); + *(u32*)thread->stack_end = OS_THREAD_STACK_MAGIC; + thread->error_code = NULL; + thread->data[0] = NULL; + thread->data[1] = NULL; + enabled = OSDisableInterrupts(); + if (__OSErrorTable[16]) { + thread->context.srr1 |= 0x900; + thread->context.state |= 1; + thread->context.fpscr = (__OSFpscrEnableBits & 0xf8) | 4; + for (i = 0; i < 32; ++i) { + *(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL; + *(u64*)&thread->context.ps[i] = (u64)0xffffffffffffffffLL; + } + } + + AddTail(&OS_THREAD_QUEUE, thread, active_threads_link); + OSRestoreInterrupts(enabled); + return TRUE; +} + +void OSExitThread(void* exitValue) { + OSThread* currentThread; + BOOL enabled; + enabled = OSDisableInterrupts(); + currentThread = OS_CURRENT_THREAD; + OSClearContext(¤tThread->context); + + if (currentThread->attributes & OS_THREAD_ATTR_DETACH) { + RemoveItem(&OS_THREAD_QUEUE, currentThread, active_threads_link); + currentThread->state = OS_THREAD_STATE_UNINITIALIZED; + } else { + currentThread->state = OS_THREAD_STATE_DEAD; + currentThread->exit_value = exitValue; + } + + __OSUnlockAllMutex(currentThread); + OSWakeupThread(¤tThread->join_queue); + RunQueueHint = TRUE; + + if (RunQueueHint) { + SelectThread(FALSE); + } + + OSRestoreInterrupts(enabled); +} + +void OSCancelThread(OSThread* thread) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + + switch (thread->state) { + case OS_THREAD_STATE_READY: + if (!(0 < thread->suspend_count)) { + UnsetRun(thread); + } + break; + case OS_THREAD_STATE_RUNNING: + RunQueueHint = TRUE; + break; + case OS_THREAD_STATE_WAITING: + RemoveItem(thread->queue, thread, link); + thread->queue = NULL; + if (!(0 < thread->suspend_count) && thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + break; + default: + OSRestoreInterrupts(enabled); + return; + } + + OSClearContext(&thread->context); + if (thread->attributes & OS_THREAD_ATTR_DETACH) { + RemoveItem(&__OSActiveThreadQueue, thread, active_threads_link); + thread->state = 0; + } else { + thread->state = OS_THREAD_STATE_DEAD; + } + + __OSUnlockAllMutex(thread); + + OSWakeupThread(&thread->join_queue); + + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +void OSDetachThread(OSThread* thread) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + thread->attributes |= OS_THREAD_ATTR_DETACH; + + if (thread->state == OS_THREAD_STATE_DEAD) { + RemoveItem(&__OSActiveThreadQueue, thread, active_threads_link); + thread->state = OS_THREAD_STATE_UNINITIALIZED; + } + + OSWakeupThread(&thread->join_queue); + OSRestoreInterrupts(enabled); +} + +s32 OSResumeThread(OSThread* thread) { + BOOL enabled; + s32 suspendCount; + + enabled = OSDisableInterrupts(); + suspendCount = thread->suspend_count--; + if (thread->suspend_count < 0) { + thread->suspend_count = 0; + } else if (thread->suspend_count == 0) { + switch (thread->state) { + case OS_THREAD_STATE_READY: + thread->effective_priority = __OSGetEffectivePriority(thread); + SetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + RemoveItem(thread->queue, thread, link); + thread->effective_priority = __OSGetEffectivePriority(thread); + AddPrio(thread->queue, thread, link); + if (thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + break; + } + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return suspendCount; +} + +s32 OSSuspendThread(OSThread* thread) { + BOOL enabled; + s32 suspendCount; + + enabled = OSDisableInterrupts(); + suspendCount = thread->suspend_count++; + if (suspendCount == 0) { + switch (thread->state) { + case OS_THREAD_STATE_RUNNING: + RunQueueHint = TRUE; + thread->state = OS_THREAD_STATE_READY; + break; + case OS_THREAD_STATE_READY: + UnsetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + RemoveItem(thread->queue, thread, link); + thread->effective_priority = 32; + AddTail(thread->queue, thread, link); + if (thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + break; + } + + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return suspendCount; +} + +void OSSleepThread(OSThreadQueue* queue) { + BOOL enabled; + OSThread* currentThread; + + enabled = OSDisableInterrupts(); + currentThread = OSGetCurrentThread(); + + currentThread->state = OS_THREAD_STATE_WAITING; + currentThread->queue = queue; + AddPrio(queue, currentThread, link); + RunQueueHint = TRUE; + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +void OSWakeupThread(OSThreadQueue* queue) { + BOOL enabled; + OSThread* thread; + + enabled = OSDisableInterrupts(); + while (queue->head) { + RemoveHead(queue, thread, link); + thread->state = OS_THREAD_STATE_READY; + if (!(0 < thread->suspend_count)) { + SetRun(thread); + } + } + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +s32 OSSetThreadPriority(OSThread* thread, s32 priority) { + BOOL enabled; + + if (priority < 0 || priority > 31) { + return FALSE; + } + + enabled = OSDisableInterrupts(); + if ((s32)thread->base_priority != priority) { + thread->base_priority = priority; + + UpdatePriority(thread); + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return TRUE; +} + +s32 OSGetThreadPriority(OSThread* thread) { + return thread->base_priority; +} + +s32 CheckThreadQueue(OSThreadQueue* thread) { + OSThread* current; + if (thread->head && thread->head->link.prev) { + return 0; + } + + if (thread->tail && thread->tail->link.next) { + return 0; + } + + current = thread->head; + + while (current) { + if (current->link.next && current != current->link.next->link.prev) { + return 0; + } + + if (current->link.prev && current != current->link.prev->link.next) { + return 0; + } + + current = current->link.next; + } + + return 1; +} + +static BOOL isMember(OSThreadQueue* queue, OSThread* thread) { + OSThread* current = queue->head; + while (current != NULL) { + if (thread == current) { + return TRUE; + } + + current = current->link.next; + } + return FALSE; +} + +s32 OSCheckActiveThreads(void) { + s32 i; + OSThread* thread; + s32 rv = 0; + BOOL enabled; + enabled = OSDisableInterrupts(); + + for (i = 0; i <= 31; i++) { + if (RunQueueBits & (1 << (31 - i))) { + if (RunQueue[i].head == NULL || RunQueue[i].tail == NULL) { + OSReport("OSCheckActiveThreads: Failed RunQueue[prio].head != NULL && " + "RunQueue[prio].tail != NULL in %d\n", + 0x5e0); + OSPanic(__FILE__, 0x5e0, ""); + } + } else { + if (RunQueue[i].head != NULL || RunQueue[i].tail != NULL) { + OSReport("OSCheckActiveThreads: Failed RunQueue[prio].head == NULL && " + "RunQueue[prio].tail == NULL in %d\n", + 0x5e5); + OSPanic(__FILE__, 0x5e5, ""); + } + } + + if (CheckThreadQueue(&RunQueue[i]) == 0) { + OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(&RunQueue[prio]) in %d\n", + 0x5e7); + OSPanic(__FILE__, 0x5e7, ""); + } + } + + if (OS_THREAD_QUEUE.head != NULL && OS_THREAD_QUEUE.head->active_threads_link.prev != NULL) { + OSReport("OSCheckActiveThreads: Failed __OSActiveThreadQueue.head == NULL || " + "__OSActiveThreadQueue.head->linkActive.prev == NULL in %d\n", + 0x5ec); + OSPanic(__FILE__, 0x5ec, ""); + } + + if (OS_THREAD_QUEUE.tail != NULL && OS_THREAD_QUEUE.tail->active_threads_link.next != NULL) { + OSReport("OSCheckActiveThreads: Failed __OSActiveThreadQueue.tail == NULL || " + "__OSActiveThreadQueue.tail->linkActive.next == NULL in %d\n", + 0x5ee); + OSPanic(__FILE__, 0x5ee, ""); + } + + thread = OS_THREAD_QUEUE.head; + + while (thread != NULL) { + rv++; + if (thread->active_threads_link.next != NULL && + thread != thread->active_threads_link.next->active_threads_link.prev) + { + OSReport("OSCheckActiveThreads: Failed thread->linkActive.next == NULL || thread == " + "thread->linkActive.next->linkActive.prev in %d\n", + 0x5f6); + OSPanic(__FILE__, 0x5f6, ""); + } + + if (thread->active_threads_link.prev != NULL && + thread != thread->active_threads_link.prev->active_threads_link.next) + { + OSReport("OSCheckActiveThreads: Failed thread->linkActive.prev == NULL || thread == " + "thread->linkActive.prev->linkActive.next in %d\n", + 0x5f8); + OSPanic(__FILE__, 0x5f8, ""); + } + + if (*(u32*)thread->stack_end != OS_THREAD_STACK_MAGIC) { + OSReport( + "OSCheckActiveThreads: Failed *(thread->stackEnd) == OS_THREAD_STACK_MAGIC in %d\n", + 0x5fb); + OSPanic(__FILE__, 0x5fb, ""); + } + + if (OS_PRIORITY_MIN > thread->effective_priority || + thread->effective_priority > OS_PRIORITY_MAX + 1) + { + OSReport("OSCheckActiveThreads: Failed OS_PRIORITY_MIN <= thread->priority && " + "thread->priority <= OS_PRIORITY_MAX+1 in %d\n", + 0x5fe); + OSPanic(__FILE__, 0x5fe, ""); + } + + if (thread->suspend_count < 0) { + OSReport("OSCheckActiveThreads: Failed 0 <= thread->suspend in %d\n", 0x5ff); + OSPanic(__FILE__, 0x5ff, ""); + } + + if (!CheckThreadQueue(&thread->join_queue)) { + OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(&thread->queueJoin) in %d\n", + 0x600); + OSPanic(__FILE__, 0x600, ""); + } + + switch (thread->state) { + case OS_THREAD_STATE_READY: + if (thread->suspend_count <= 0) { + if (thread->queue != &RunQueue[thread->effective_priority]) { + OSReport("OSCheckActiveThreads: Failed thread->queue == " + "&RunQueue[thread->priority] in %d\n", + 0x606); + OSPanic(__FILE__, 0x606, ""); + } + + if (!isMember(&RunQueue[thread->effective_priority], thread)) { + OSReport("OSCheckActiveThreads: Failed IsMember(&RunQueue[thread->priority], " + "thread) in %d\n", + 0x607); + OSPanic(__FILE__, 0x607, ""); + } + + if (thread->effective_priority != __OSGetEffectivePriority(thread)) { + OSReport("OSCheckActiveThreads: Failed thread->priority == " + "__OSGetEffectivePriority(thread) in %d\n", + 0x608); + OSPanic(__FILE__, 0x608, ""); + } + } + break; + case OS_THREAD_STATE_RUNNING: + if (thread->suspend_count > 0) { + OSReport("OSCheckActiveThreads: Failed !IsSuspended(thread->suspend) in %d\n", + 0x60c); + OSPanic(__FILE__, 0x60c, ""); + } + + if (thread->queue != NULL) { + OSReport("OSCheckActiveThreads: Failed thread->queue == NULL in %d\n", 0x60d); + OSPanic(__FILE__, 0x60d, ""); + } + + if (thread->effective_priority != __OSGetEffectivePriority(thread)) { + OSReport("OSCheckActiveThreads: Failed thread->priority == " + "__OSGetEffectivePriority(thread) in %d\n", + 0x60e); + OSPanic(__FILE__, 0x60e, ""); + } + break; + case OS_THREAD_STATE_WAITING: + if (thread->queue == NULL) { + OSReport("OSCheckActiveThreads: Failed thread->queue != NULL in %d\n", 0x611); + OSPanic(__FILE__, 0x611, ""); + } + + if (CheckThreadQueue(thread->queue) == 0) { + OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(thread->queue) in %d\n", + 0x612); + OSPanic(__FILE__, 0x612, ""); + } + + if (!isMember(thread->queue, thread)) { + OSReport("OSCheckActiveThreads: Failed IsMember(thread->queue, thread) in %d\n", + 0x613); + OSPanic(__FILE__, 0x613, ""); + } + + if (thread->suspend_count <= 0) { + if (thread->effective_priority != __OSGetEffectivePriority(thread)) { + OSReport("OSCheckActiveThreads: Failed thread->priority == " + "__OSGetEffectivePriority(thread) in %d\n", + 0x616); + OSPanic(__FILE__, 0x616, ""); + } + } else if (thread->effective_priority != 32) { + OSReport("OSCheckActiveThreads: Failed thread->priority == 32 in %d\n", 0x61a); + OSPanic(__FILE__, 0x61a, ""); + } + + if (__OSCheckDeadLock(thread)) { + OSReport("OSCheckActiveThreads: Failed !__OSCheckDeadLock(thread) in %d\n", 0x61c); + OSPanic(__FILE__, 0x61c, ""); + } + break; + case OS_THREAD_STATE_DEAD: + if (thread->owned_mutexes.head != NULL || thread->owned_mutexes.tail != NULL) { + OSReport("OSCheckActiveThreads: Failed thread->queueMutex.head == NULL && " + "thread->queueMutex.tail == NULL in %d\n", + 0x620); + OSPanic(__FILE__, 0x620, ""); + } + break; + default: + OSReport("OSCheckActiveThreads: Failed. unkown thread state (%d) of thread %p\n", + thread->state, thread); + OSPanic(__FILE__, 0x626, ""); + break; + } + + if (!__OSCheckMutexes(thread)) { + OSReport("OSCheckActiveThreads: Failed __OSCheckMutexes(thread) in %d\n", 0x62b); + OSPanic(__FILE__, 0x62b, ""); + } + + thread = thread->active_threads_link.next; + } + + OSRestoreInterrupts(enabled); + return rv; +} + +void OSClearStack(u8 val) { + u32* sp; + u32* p; + u32 pattern; + + pattern = ((u32)val << 24) | ((u32)val << 16) | ((u32)val << 8) | (u32)val; + sp = (u32*)OSGetStackPointer(); + for (p = ((u32*)__OSCurrentThread->stack_end) + 1; p < sp; ++p) { + *p = pattern; + } +} + +extern u8 data_804516D0[8]; +u8 data_804516D0[8] ALIGN_DECL(8); diff --git a/src/dolphin/os/OSTime.c b/src/dolphin/os/OSTime.c new file mode 100644 index 000000000..4ce6151c0 --- /dev/null +++ b/src/dolphin/os/OSTime.c @@ -0,0 +1,138 @@ +#include "dolphin/os/OSTime.h" +#include "dolphin/os/OS.h" + +#define OS_TIME_MONTH_MAX 12 +#define OS_TIME_WEEK_DAY_MAX 7 +#define OS_TIME_YEAR_DAY_MAX 365 + +asm OSTime OSGetTime(void) { + // clang-format off + nofralloc + + mftbu r3 + mftb r4, 0x10C + + mftbu r5 + cmpw r3, r5 + bne OSGetTime + + blr + // clang-format on +} + +asm OSTick OSGetTick(void) { + // clang-format off + nofralloc + + mftb r3, 0x10C + blr + // clang-format on +} + +#define OS_SYSTEMTIME_BASE 0x30D8 + +OSTime __OSGetSystemTime(void) { + BOOL enabled; + OSTime* timeAdjustAddr = (OSTime*)(OS_BASE_CACHED + OS_SYSTEMTIME_BASE); + OSTime result; + + enabled = OSDisableInterrupts(); + result = *timeAdjustAddr + OSGetTime(); + OSRestoreInterrupts(enabled); + + return result; +} + +OSTime __OSTimeToSystemTime(OSTime time) { + BOOL enabled; + OSTime* timeAdjustAddr = (OSTime*)(OS_BASE_CACHED + OS_SYSTEMTIME_BASE); + OSTime result; + + enabled = OSDisableInterrupts(); + result = *timeAdjustAddr + time; + OSRestoreInterrupts(enabled); + + return result; +} + +// End of each month in standard year +static s32 YearDays[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, +}; + +// End of each month in leap year +static s32 LeapYearDays[] = { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, +}; + +static inline BOOL IsLeapYear(s32 year) { + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +static inline s32 GetYearDays(s32 year, s32 mon) { + return (IsLeapYear(year) ? LeapYearDays : YearDays)[mon]; +} + +static inline s32 GetLeapDays(s32 year) { + if (year < 1) { + return 0; + } + return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400; +} + +static void GetDates(s32 days, OSCalendarTime* cal) { + s32 year; + s32 totalDays; + s32* p_days; + s32 month; + cal->week_day = (days + 6) % OS_TIME_WEEK_DAY_MAX; + + for (year = days / OS_TIME_YEAR_DAY_MAX; + days < (totalDays = year * OS_TIME_YEAR_DAY_MAX + GetLeapDays(year));) + { + year--; + } + + days -= totalDays; + cal->year = year; + cal->year_day = days; + + p_days = IsLeapYear(year) ? LeapYearDays : YearDays; + month = OS_TIME_MONTH_MAX; + while (days < p_days[--month]) { + ; + } + cal->month = month; + cal->day_of_month = days - p_days[month] + 1; +} + +#define BIAS (2000 * 365 + (2000 + 3) / 4 - (2000 - 1) / 100 + (2000 - 1) / 400) + +#pragma dont_inline on +void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td) { + int days; + int secs; + OSTime d; + + d = ticks % OSSecondsToTicks(1); + if (d < 0) { + d += OSSecondsToTicks(1); + } + td->microseconds = (int)(OSTicksToMicroseconds(d) % 1000); + td->milliseconds = (int)(OSTicksToMilliseconds(d) % 1000); + + ticks -= d; + days = (int)(OSTicksToSeconds(ticks) / 86400 + BIAS); + secs = (int)(OSTicksToSeconds(ticks) % 86400); + if (secs < 0) { + days -= 1; + secs += 24 * 60 * 60; + } + + GetDates(days, td); + + td->hours = secs / 60 / 60; + td->minutes = (secs / 60) % 60; + td->seconds = secs % 60; +} +#pragma dont_inline reset diff --git a/src/dolphin/os/__ppc_eabi_init.cpp b/src/dolphin/os/__ppc_eabi_init.cpp new file mode 100644 index 000000000..ffa59dd69 --- /dev/null +++ b/src/dolphin/os/__ppc_eabi_init.cpp @@ -0,0 +1,49 @@ +// +// __ppc_eabi_init +// + +#include "global.h" +#include "dolphin/base/PPCArch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Forward References: +// + +void __init_user(); +void __init_cpp(); +void _ExitProcess(); + +// +// External References: +// + +typedef void (*voidfunctionptr)(); // pointer to function returning void +extern voidfunctionptr __init_cpp_exceptions_reference[]; + +void __init_user(void) { + __init_cpp(); +} + +#pragma peephole off +void __init_cpp(void) { + /** + * call static initializers + */ + voidfunctionptr* constructor; + for (constructor = __init_cpp_exceptions_reference; *constructor; constructor++) { + (*constructor)(); + } +} +#pragma peephole reset + +void _ExitProcess(void) { + PPCHalt(); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/dolphin/os/__start.c b/src/dolphin/os/__start.c new file mode 100644 index 000000000..76b189c17 --- /dev/null +++ b/src/dolphin/os/__start.c @@ -0,0 +1,160 @@ +#include "stdlib.h" +#include "global.h" +// #include "init.h" + +// +// Forward References: +// + +SECTION_INIT void __check_pad3(void); +SECTION_INIT void __set_debug_bba(void); +SECTION_INIT u8 __get_debug_bba(void); +SECTION_INIT void __start(void); + +// +// External References: +// + +void main(); +void OSInit(); +void OSResetSystem(s32, s32, s32); +void __init_user(); +void DBInit(); +void InitMetroTRK(); +void InitMetroTRK_BBA(); +extern u8 data_804516D0; +void __init_data(); +void __init_hardware(); +void __init_registers(); + +// +// Declarations: +// + +SECTION_INIT void __check_pad3(void) { + if ((*(u16*)0x800030E4 & 0xEEF) == 0xEEF) { + OSResetSystem(0, 0, 0); + } +} + +void __set_debug_bba(void) { + data_804516D0 = 1; +} + +SECTION_INIT u8 __get_debug_bba(void) { + return data_804516D0; +} + +SECTION_INIT asm void __start(void) { + // clang-format off + nofralloc + + bl __init_registers + bl __init_hardware + li r0, -1 + stwu r1, -8(r1) + stw r0, 4(r1) + stw r0, 0(r1) + bl __init_data + li r0, 0 + lis r6, 0x8000 + addi r6, r6, 0x0044 + stw r0, 0(r6) + lis r6, 0x8000 + addi r6, r6, 0x00F4 + lwz r6, 0(r6) + cmplwi r6, 0 + beq lbl_8000319C + lwz r7, 0xc(r6) + b lbl_800031BC + +lbl_8000319C: + lis r5, 0x8000 + addi r5, r5, 0x0034 + lwz r5, 0(r5) + cmplwi r5, 0 + beq lbl_800031F8 + lis r7, 0x8000 + addi r7, r7, 0x30E8 + lwz r7, 0(r7) + +lbl_800031BC: + li r5, 0 + cmplwi r7, 2 + beq lbl_800031E8 + cmplwi r7, 3 + li r5, 1 + beq lbl_800031E8 + cmplwi r7, 4 + bne lbl_800031F8 + li r5, 2 + bl __set_debug_bba + b lbl_800031F8 + +lbl_800031E8: + lis r6, InitMetroTRK@ha + addi r6, r6, InitMetroTRK@l + mtlr r6 + blrl + +lbl_800031F8: + lis r6, 0x8000 + addi r6, r6, 0x00F4 + lwz r5, 0(r6) + cmplwi r5, 0 + beq+ lbl_80003258 + lwz r6, 8(r5) + cmplwi r6, 0 + beq+ lbl_80003258 + add r6, r5, r6 + lwz r14, 0(r6) + cmplwi r14, 0 + beq lbl_80003258 + addi r15, r6, 4 + mtctr r14 + +lbl_80003230: + addi r6, r6, 4 + lwz r7, 0(r6) + add r7, r7, r5 + stw r7, 0(r6) + bdnz lbl_80003230 + lis r5, 0x8000 + addi r5, r5, 0x0034 + rlwinm r7, r15, 0, 0, 0x1a + stw r7, 0(r5) + b lbl_80003260 + +lbl_80003258: + li r14, 0 + li r15, 0 + +lbl_80003260: + bl DBInit + bl OSInit + lis r4, 0x8000 + addi r4, r4, 0x30E6 + lhz r3, 0(r4) + andi. r5, r3, 0x8000 + beq lbl_80003288 + andi. r3, r3, 0x7fff + cmplwi r3, 1 + bne lbl_8000328C + +lbl_80003288: + bl __check_pad3 + +lbl_8000328C: + bl __get_debug_bba + cmplwi r3, 1 + bne lbl_8000329C + bl InitMetroTRK_BBA + +lbl_8000329C: + bl __init_user + mr r3, r14 + mr r4, r15 + bl main + b exit + // clang-format on +} diff --git a/src/m_Do/m_Do_printf.cpp b/src/m_Do/m_Do_printf.cpp index 960ab075c..411e17572 100644 --- a/src/m_Do/m_Do_printf.cpp +++ b/src/m_Do/m_Do_printf.cpp @@ -45,22 +45,22 @@ extern "C" int search_partial_address(void* address, int* module_id, int* sectio return 0xFFFFFFFF; OSModuleInfo* module = *(OSModuleInfo**)0x800030C8; - for (; module != NULL; module = (OSModuleInfo*)module->mNext) { + for (; module != NULL; module = (OSModuleInfo*)module->link.next) { u32 i, addr; - OSSectionInfo* section = (OSSectionInfo*)module->info.sectionInfoOffset; + OSSectionInfo* section = (OSSectionInfo*)module->sectionInfoOffset; - for (i = 0; i < module->mNumSections; section++, i++) { - if (section->mSize != 0) { - addr = section->mOffset & ~0x01; - if ((addr <= (u32)address) && (u32)address < (addr + section->mSize)) { + for (i = 0; i < module->numSections; section++, i++) { + if (section->size != 0) { + addr = section->offset & ~0x01; + if ((addr <= (u32)address) && (u32)address < (addr + section->size)) { if (module_id != NULL) - *module_id = module->mId; + *module_id = module->id; if (section_id != NULL) *section_id = i; if (section_offset) *section_offset = (u32)address - addr; if (name_offset) - *name_offset = module->mModuleNameOffset; + *name_offset = module->nameOffset; return 0; } }