diff --git a/config/GAFE01_00/config.yml b/config/GAFE01_00/config.yml index c0dc3298..4b6271ae 100644 --- a/config/GAFE01_00/config.yml +++ b/config/GAFE01_00/config.yml @@ -20,6 +20,40 @@ block_relocations: - source: 0x80052D58 add_relocations: +# OS.c +- source: .text:0x80078984 + type: ha + target: __ArenaLo +- source: .text:0x80078988 + type: l + target: __ArenaLo +- source: .text:0x800789BC + type: ha + target: _stack_addr +- source: .text:0x800789C0 + type: l + target: _stack_addr +- source: .text:0x800789E0 + type: ha + target: __ArenaHi +- source: .text:0x800789E4 + type: l + target: __ArenaHi + +# OSThread.c +- source: .text:0x8007DC18 + type: ha + target: _stack_addr +- source: .text:0x8007DC1C + type: l + target: _stack_addr +- source: .text:0x8007DC20 + type: ha + target: _stack_end +- source: .text:0x8007DC28 + type: l + target: _stack_end + # emu64 - source: .text:0x8004F4F4 # setup_texture_tile (inlined texture_cache_select) type: ha diff --git a/config/GAFE01_00/ldscript.tpl b/config/GAFE01_00/ldscript.tpl index 7817acd4..df8f9ae2 100644 --- a/config/GAFE01_00/ldscript.tpl +++ b/config/GAFE01_00/ldscript.tpl @@ -12,10 +12,10 @@ SECTIONS } > text _stack_end = ($LAST_SECTION_SYMBOL + SIZEOF($LAST_SECTION_NAME)+ 0x7) & ~0x7; - _stack_addr = (_stack_end + 0x2000 + 0x7) & ~0x7; - _db_stack_addr = (_stack_addr + 0x1000); + _stack_addr = (_stack_end + 0x1000 + 0x7) & ~0x7; + _db_stack_addr = (_stack_addr + 0x2000); _db_stack_end = _stack_addr; - __ArenaLo = _db_stack_addr; + __ArenaLo = (_db_stack_addr + 0x1F) & ~0x1F; __ArenaHi = 0x81700000; } diff --git a/configure.py b/configure.py index 2d8e0402..eb87b069 100644 --- a/configure.py +++ b/configure.py @@ -565,27 +565,27 @@ config.libs = [ [ Object(Matching, "dolphin/os/__ppc_eabi_init.cpp"), Object(Matching, "dolphin/os/__start.c"), - Object(NonMatching, "dolphin/os/OS.c"), + Object(Matching, "dolphin/os/OS.c"), Object(Matching, "dolphin/os/OSAlarm.c"), - Object(NonMatching, "dolphin/os/OSAlloc.c"), + Object(Matching, "dolphin/os/OSAlloc.c"), Object(Matching, "dolphin/os/OSArena.c"), Object(Matching, "dolphin/os/OSAudioSystem.c"), Object(Matching, "dolphin/os/OSCache.c"), Object(Matching, "dolphin/os/OSContext.c"), Object(Matching, "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/OSMemory.c"), - Object(NonMatching, "dolphin/os/OSMessage.c"), - Object(NonMatching, "dolphin/os/OSMutex.c"), - Object(NonMatching, "dolphin/os/OSReboot.c"), - Object(NonMatching, "dolphin/os/OSReset.c"), - Object(NonMatching, "dolphin/os/OSResetSW.c"), + Object(Matching, "dolphin/os/OSFont.c"), + Object(Matching, "dolphin/os/OSInterrupt.c"), + Object(Matching, "dolphin/os/OSLink.c"), + Object(Matching, "dolphin/os/OSMemory.c"), + Object(Matching, "dolphin/os/OSMessage.c"), + Object(Matching, "dolphin/os/OSMutex.c"), + Object(Matching, "dolphin/os/OSReboot.c"), + Object(Matching, "dolphin/os/OSReset.c"), + Object(Matching, "dolphin/os/OSResetSW.c"), Object(Matching, "dolphin/os/OSRtc.c"), - Object(NonMatching, "dolphin/os/OSSync.c"), - Object(NonMatching, "dolphin/os/OSThread.c"), - Object(NonMatching, "dolphin/os/OSTime.c"), + Object(Matching, "dolphin/os/OSSync.c"), + Object(Matching, "dolphin/os/OSThread.c"), + Object(Matching, "dolphin/os/OSTime.c"), ], ), DolphinLib( diff --git a/include/boot.h b/include/boot.h index 968c79a7..3cae2bea 100644 --- a/include/boot.h +++ b/include/boot.h @@ -3,6 +3,7 @@ #include "types.h" #include "dolphin/os/OSModule.h" +#include "dolphin/os/OSLink.h" #include "dolphin/os/OSTime.h" #ifdef __cplusplus diff --git a/include/dolphin/base/PPCArch.h b/include/dolphin/base/PPCArch.h index fb10dba8..99faf173 100644 --- a/include/dolphin/base/PPCArch.h +++ b/include/dolphin/base/PPCArch.h @@ -94,6 +94,23 @@ void PPCSetFpNonIEEEMode(void); #define MSR_RI 0x00000002 // Recoverable interrupt #define MSR_LE 0x00000001 // Little Endian +#define MSR_POW_BIT 13 // Power Management +#define MSR_ILE_BIT 15 // Interrupt Little Endian +#define MSR_EE_BIT 16 // external interrupt +#define MSR_PR_BIT 17 // privilege level (should be 0) +#define MSR_FP_BIT 18 // floating point available +#define MSR_ME_BIT 19 // machine check enable +#define MSR_FE0_BIT 20 // floating point exception enable +#define MSR_SE_BIT 21 // single step trace enable +#define MSR_BE_BIT 22 // branch trace enable +#define MSR_FE1_BIT 23 // floating point exception enable +#define MSR_IP_BIT 25 // Exception prefix +#define MSR_IR_BIT 26 // instruction relocate +#define MSR_DR_BIT 27 // data relocate +#define MSR_PM_BIT 29 // Performance monitor marked mode +#define MSR_RI_BIT 30 // Recoverable interrupt +#define MSR_LE_BIT 31 // Little Endian + #ifdef __cplusplus } #endif diff --git a/include/dolphin/db.h b/include/dolphin/db.h index 7fe822e0..f3403e27 100644 --- a/include/dolphin/db.h +++ b/include/dolphin/db.h @@ -2,6 +2,7 @@ #define DB_H #include "types.h" +#include #ifdef __cplusplus extern "C"{ @@ -9,20 +10,8 @@ extern "C"{ #define OS_DBINTERFACE_ADDR 0x00000040 -typedef struct DBInterface -{ - u32 bPresent; - u32 exceptionMask; - void (*ExceptionDestination) ( void ); - void *exceptionReturn; -} DBInterface; - -extern DBInterface* __DBInterface; - -void DBInit(void); -void DBInitComm(int* inputFlagPtr, int* mtrCallback); -static void __DBExceptionDestination(void); -void DBPrintf(char* format, ...); +BOOL DBIsDebuggerPresent(void); +void DBPrintf(char* str, ...); #ifdef __cplusplus } diff --git a/include/dolphin/db/DBInterface.h b/include/dolphin/db/DBInterface.h new file mode 100644 index 00000000..60f1c9f5 --- /dev/null +++ b/include/dolphin/db/DBInterface.h @@ -0,0 +1,31 @@ +#ifndef _DOLPHIN_DBINTERFACE_H_ +#define _DOLPHIN_DBINTERFACE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DBInterface { + u32 bPresent; + u32 exceptionMask; + void (*ExceptionDestination)(void); + void* exceptionReturn; +} DBInterface; + +extern DBInterface* __DBInterface; + +void DBInit(void); +void DBInitComm(int* inputFlagPtr, int* mtrCallback); +void __DBExceptionDestination(void); +void __DBExceptionDestinationAux(void); +BOOL __DBIsExceptionMarked(__OSException exception); +void __DBMarkException(u8 exception, int value); +void __DBSetPresent(u32 value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/os.h b/include/dolphin/os.h index 7a8d58c4..dec25bb1 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -9,6 +9,7 @@ #include "dolphin/os/OSError.h" #include "dolphin/os/OSInterrupt.h" #include "dolphin/os/OSModule.h" +#include "dolphin/os/OSLink.h" #include "dolphin/os/OSMemory.h" #include "dolphin/os/OSMessage.h" #include "libforest/osreport.h" /* OSReport funcs */ @@ -100,6 +101,18 @@ typedef struct OSBootInfo_s { #define OS_BASE_CACHED (OS_CACHED_REGION_PREFIX << 16) #define OS_BASE_UNCACHED (OS_UNCACHED_REGION_PREFIX << 16) +typedef struct BI2Debug { + /* 0x00 */ s32 debugMonSize; + /* 0x04 */ s32 simMemSize; + /* 0x08 */ u32 argOffset; + /* 0x0C */ u32 debugFlag; + /* 0x10 */ int trackLocation; + /* 0x14 */ int trackSize; + /* 0x18 */ u32 countryCode; + /* 0x1C */ u8 unk[8]; + /* 0x24 */ u32 padSpec; +} BI2Debug; + #ifdef __MWERKS__ u32 __OSPhysicalMemSize : (OS_BASE_CACHED | 0x0028); volatile int __OSTVMode : (OS_BASE_CACHED | 0x00CC); diff --git a/include/dolphin/os/OSError.h b/include/dolphin/os/OSError.h index 27831723..541cea3c 100644 --- a/include/dolphin/os/OSError.h +++ b/include/dolphin/os/OSError.h @@ -9,6 +9,7 @@ extern "C" { typedef u16 OSError; typedef void (*OSErrorHandler)(OSError error, OSContext *context, ...); +typedef void (*OSErrorHandlerEx)(OSError error, OSContext* context, ...); #define OS_ERROR_SYSTEM_RESET 0 #define OS_ERROR_MACHINE_CHECK 1 @@ -37,4 +38,4 @@ extern u32 __OSFpscrEnableBits; } #endif -#endif \ No newline at end of file +#endif diff --git a/include/dolphin/os/OSException.h b/include/dolphin/os/OSException.h index 1a3ca131..45064a50 100644 --- a/include/dolphin/os/OSException.h +++ b/include/dolphin/os/OSException.h @@ -30,6 +30,26 @@ typedef void (*__OSExceptionHandler)(__OSException exception, OSContext* context __OSExceptionHandler __OSSetExceptionHandler(__OSException exception, __OSExceptionHandler handler); __OSExceptionHandler __OSGetExceptionHandler(__OSException exception); +#define OS_EXCEPTION_SAVE_GPRS(context) \ + stw r0, OS_CONTEXT_R0(context); \ + stw r1, OS_CONTEXT_R1(context); \ + stw r2, OS_CONTEXT_R2(context); \ + stmw r6, OS_CONTEXT_R6(context); \ + mfspr r0, GQR1; \ + stw r0, OS_CONTEXT_GQR1(context); \ + mfspr r0, GQR2; \ + stw r0, OS_CONTEXT_GQR2(context); \ + mfspr r0, GQR3; \ + stw r0, OS_CONTEXT_GQR3(context); \ + mfspr r0, GQR4; \ + stw r0, OS_CONTEXT_GQR4(context); \ + mfspr r0, GQR5; \ + stw r0, OS_CONTEXT_GQR5(context); \ + mfspr r0, GQR6; \ + stw r0, OS_CONTEXT_GQR6(context); \ + mfspr r0, GQR7; \ + stw r0, OS_CONTEXT_GQR7(context); + #ifdef __cplusplus } #endif diff --git a/include/dolphin/os/OSFont.h b/include/dolphin/os/OSFont.h index dd16efb8..4a1ca36f 100644 --- a/include/dolphin/os/OSFont.h +++ b/include/dolphin/os/OSFont.h @@ -7,6 +7,9 @@ extern "C" { #endif +#define OS_FONT_ROM_SIZE_ANSI 0x03000 +#define OS_FONT_ROM_SIZE_SJIS 0x4D000 + typedef struct OSFontHeader { u16 fontType; // _00 u16 firstChar; // _02, first char code defined in font. diff --git a/include/dolphin/os/OSInterrupt.h b/include/dolphin/os/OSInterrupt.h index d77f5c24..25202695 100644 --- a/include/dolphin/os/OSInterrupt.h +++ b/include/dolphin/os/OSInterrupt.h @@ -49,60 +49,98 @@ typedef enum OSInterruptType { OS_INTR_MAX } OSInterruptType; -#define OS_INTRMASK_MEM_0 (0x80000000U >> OS_INTR_MEM_0) -#define OS_INTRMASK_MEM_1 (0x80000000U >> OS_INTR_MEM_1) -#define OS_INTRMASK_MEM_2 (0x80000000U >> OS_INTR_MEM_2) -#define OS_INTRMASK_MEM_3 (0x80000000U >> OS_INTR_MEM_3) -#define OS_INTRMASK_MEM_ADDRESS (0x80000000U >> OS_INTR_MEM_ADDRESS) -#define OS_INTRMASK_DSP_AI (0x80000000U >> OS_INTR_DSP_AI) -#define OS_INTRMASK_DSP_ARAM (0x80000000U >> OS_INTR_DSP_ARAM) -#define OS_INTRMASK_DSP_DSP (0x80000000U >> OS_INTR_DSP_DSP) -#define OS_INTRMASK_AI_AI (0x80000000U >> OS_INTR_AI_AI) -#define OS_INTRMASK_EXI_0_EXI (0x80000000U >> OS_INTR_EXI_0_EXI) -#define OS_INTRMASK_EXI_0_TC (0x80000000U >> OS_INTR_EXI_0_TC) -#define OS_INTRMASK_EXI_0_EXT (0x80000000U >> OS_INTR_EXI_0_EXT) -#define OS_INTRMASK_EXI_1_EXI (0x80000000U >> OS_INTR_EXI_1_EXI) -#define OS_INTRMASK_EXI_1_TC (0x80000000U >> OS_INTR_EXI_1_TC) -#define OS_INTRMASK_EXI_1_EXT (0x80000000U >> OS_INTR_EXI_1_EXT) -#define OS_INTRMASK_EXI_2_EXI (0x80000000U >> OS_INTR_EXI_2_EXI) -#define OS_INTRMASK_EXI_2_TC (0x80000000U >> OS_INTR_EXI_2_TC) -#define OS_INTRMASK_PI_CP (0x80000000U >> OS_INTR_PI_CP) -#define OS_INTRMASK_PI_PE_TOKEN (0x80000000U >> OS_INTR_PI_PE_TOKEN) -#define OS_INTRMASK_PI_PE_FINISH (0x80000000U >> OS_INTR_PI_PE_FINISH) -#define OS_INTRMASK_PI_SI (0x80000000U >> OS_INTR_PI_SI) -#define OS_INTRMASK_PI_DI (0x80000000U >> OS_INTR_PI_DI) -#define OS_INTRMASK_PI_RSW (0x80000000U >> OS_INTR_PI_RSW) -#define OS_INTRMASK_PI_ERROR (0x80000000U >> OS_INTR_PI_ERROR) -#define OS_INTRMASK_PI_VI (0x80000000U >> OS_INTR_PI_VI) -#define OS_INTRMASK_PI_DEBUG (0x80000000U >> OS_INTR_PI_DEBUG) -#define OS_INTRMASK_PI_HSP (0x80000000U >> OS_INTR_PI_HSP) +#define __OS_INTERRUPT_MEM_0 0 +#define __OS_INTERRUPT_MEM_1 1 +#define __OS_INTERRUPT_MEM_2 2 +#define __OS_INTERRUPT_MEM_3 3 +#define __OS_INTERRUPT_MEM_ADDRESS 4 +#define __OS_INTERRUPT_DSP_AI 5 +#define __OS_INTERRUPT_DSP_ARAM 6 +#define __OS_INTERRUPT_DSP_DSP 7 +#define __OS_INTERRUPT_AI_AI 8 +#define __OS_INTERRUPT_EXI_0_EXI 9 +#define __OS_INTERRUPT_EXI_0_TC 10 +#define __OS_INTERRUPT_EXI_0_EXT 11 +#define __OS_INTERRUPT_EXI_1_EXI 12 +#define __OS_INTERRUPT_EXI_1_TC 13 +#define __OS_INTERRUPT_EXI_1_EXT 14 +#define __OS_INTERRUPT_EXI_2_EXI 15 +#define __OS_INTERRUPT_EXI_2_TC 16 +#define __OS_INTERRUPT_PI_CP 17 +#define __OS_INTERRUPT_PI_PE_TOKEN 18 +#define __OS_INTERRUPT_PI_PE_FINISH 19 +#define __OS_INTERRUPT_PI_SI 20 +#define __OS_INTERRUPT_PI_DI 21 +#define __OS_INTERRUPT_PI_RSW 22 +#define __OS_INTERRUPT_PI_ERROR 23 +#define __OS_INTERRUPT_PI_VI 24 +#define __OS_INTERRUPT_PI_DEBUG 25 +#define __OS_INTERRUPT_PI_HSP 26 +#define __OS_INTERRUPT_MAX 32 -#define OS_INTRMASK_MEM \ - (OS_INTRMASK_MEM_0 | OS_INTRMASK_MEM_1 | OS_INTRMASK_MEM_2 | \ - OS_INTRMASK_MEM_3 | OS_INTRMASK_MEM_ADDRESS) +#define OS_INTERRUPTMASK(interrupt) (0x80000000u >> (interrupt)) -#define OS_INTRMASK_AI (OS_INTRMASK_AI_AI) - -#define OS_INTRMASK_DSP \ - (OS_INTRMASK_DSP_AI | OS_INTRMASK_DSP_ARAM | OS_INTRMASK_DSP_DSP) - -#define OS_INTRMASK_EXI_0 \ - (OS_INTRMASK_EXI_0_EXI | OS_INTRMASK_EXI_0_TC | OS_INTRMASK_EXI_0_EXT) -#define OS_INTRMASK_EXI_1 \ - (OS_INTRMASK_EXI_1_EXI | OS_INTRMASK_EXI_1_TC | OS_INTRMASK_EXI_1_EXT) -#define OS_INTRMASK_EXI_2 (OS_INTRMASK_EXI_2_EXI | OS_INTRMASK_EXI_2_TC) -#define OS_INTRMASK_EXI \ - (OS_INTRMASK_EXI_0_EXI | OS_INTRMASK_EXI_0_TC | OS_INTRMASK_EXI_0_EXT | \ - OS_INTRMASK_EXI_1_EXI | OS_INTRMASK_EXI_1_TC | OS_INTRMASK_EXI_1_EXT | \ - OS_INTRMASK_EXI_2_EXI | OS_INTRMASK_EXI_2_TC) - -#define OS_INTRMASK_PI \ - (OS_INTRMASK_PI_CP | OS_INTRMASK_PI_SI | OS_INTRMASK_PI_DI | \ - OS_INTRMASK_PI_RSW | OS_INTRMASK_PI_ERROR | OS_INTRMASK_PI_VI | \ - OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH | \ - OS_INTRMASK_PI_DEBUG | OS_INTRMASK_PI_HSP) - -#define OS_INTRMASK_PI_PE (OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH) +#define OS_INTERRUPTMASK_MEM_0 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0) +#define OS_INTERRUPTMASK_MEM_1 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_1) +#define OS_INTERRUPTMASK_MEM_2 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_2) +#define OS_INTERRUPTMASK_MEM_3 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_3) +#define OS_INTERRUPTMASK_MEM_ADDRESS \ + OS_INTERRUPTMASK(__OS_INTERRUPT_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) +#define OS_INTERRUPTMASK_DSP_AI OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_AI) +#define OS_INTERRUPTMASK_DSP_ARAM OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_ARAM) +#define OS_INTERRUPTMASK_DSP_DSP OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_DSP) +#define OS_INTERRUPTMASK_DSP \ + (OS_INTERRUPTMASK_DSP_AI | OS_INTERRUPTMASK_DSP_ARAM \ + | OS_INTERRUPTMASK_DSP_DSP) +#define OS_INTERRUPTMASK_AI_AI OS_INTERRUPTMASK(__OS_INTERRUPT_AI_AI) +#define OS_INTERRUPTMASK_AI (OS_INTERRUPTMASK_AI_AI) +#define OS_INTERRUPTMASK_EXI_0_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXI) +#define OS_INTERRUPTMASK_EXI_0_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_TC) +#define OS_INTERRUPTMASK_EXI_0_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXT) +#define OS_INTERRUPTMASK_EXI_0 \ + (OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC \ + | OS_INTERRUPTMASK_EXI_0_EXT) +#define OS_INTERRUPTMASK_EXI_1_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXI) +#define OS_INTERRUPTMASK_EXI_1_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_TC) +#define OS_INTERRUPTMASK_EXI_1_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXT) +#define OS_INTERRUPTMASK_EXI_1 \ + (OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC \ + | OS_INTERRUPTMASK_EXI_1_EXT) +#define OS_INTERRUPTMASK_EXI_2_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_EXI) +#define OS_INTERRUPTMASK_EXI_2_TC OS_INTERRUPTMASK(__OS_INTERRUPT_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) +#define OS_INTERRUPTMASK_PI_PE_TOKEN \ + OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_TOKEN) +#define OS_INTERRUPTMASK_PI_PE_FINISH \ + OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_FINISH) +#define OS_INTERRUPTMASK_PI_PE \ + (OS_INTERRUPTMASK_PI_PE_TOKEN | OS_INTERRUPTMASK_PI_PE_FINISH) +#define OS_INTERRUPTMASK_PI_CP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_CP) +#define OS_INTERRUPTMASK_PI_SI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_SI) +#define OS_INTERRUPTMASK_PI_DI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DI) +#define OS_INTERRUPTMASK_PI_RSW OS_INTERRUPTMASK(__OS_INTERRUPT_PI_RSW) +#define OS_INTERRUPTMASK_PI_ERROR OS_INTERRUPTMASK(__OS_INTERRUPT_PI_ERROR) +#define OS_INTERRUPTMASK_PI_VI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_VI) +#define OS_INTERRUPTMASK_PI_DEBUG OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DEBUG) +#define OS_INTERRUPTMASK_PI_HSP OS_INTERRUPTMASK(__OS_INTERRUPT_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) typedef void (*__OSInterruptHandler)(__OSInterrupt, OSContext*); diff --git a/include/dolphin/os/OSLink.h b/include/dolphin/os/OSLink.h new file mode 100644 index 00000000..1e6a031c --- /dev/null +++ b/include/dolphin/os/OSLink.h @@ -0,0 +1,111 @@ +#ifndef OSLINK_H +#define OSLINK_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define OS_MODULE_VERSION 2 + +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; + +struct OSModuleQueue { + OSModuleInfo* head; + OSModuleInfo* tail; +}; + +OSModuleQueue __OSModuleList AT_ADDRESS(0x800030C8); +void* __OSStringTable AT_ADDRESS(0x800030D0); + +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; +#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* newModule, void* bss); +BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss); +BOOL OSUnlink(OSModuleInfo* module); +void OSSetStringTable(const void* string_table); +void __OSModuleInit(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* OSLINK_H */ diff --git a/include/dolphin/os/OSModule.h b/include/dolphin/os/OSModule.h index ba06e28f..84a1c008 100644 --- a/include/dolphin/os/OSModule.h +++ b/include/dolphin/os/OSModule.h @@ -7,63 +7,63 @@ extern "C" { #endif -typedef struct OSModuleInfo_s OSModuleInfo; +// typedef struct OSModuleInfo_s OSModuleInfo; -typedef struct OSModuleQueue_s { - OSModuleInfo* head; - OSModuleInfo* tail; -} OSModuleQueue; +// typedef struct OSModuleQueue_s { +// OSModuleInfo* head; +// OSModuleInfo* tail; +// } OSModuleQueue; -typedef struct OSModuleLink_s { - OSModuleInfo* next; - OSModuleInfo* prev; -} OSModuleLink; +// typedef struct OSModuleLink_s { +// OSModuleInfo* next; +// OSModuleInfo* prev; +// } OSModuleLink; -typedef struct OSModuleInfo_s { - u32 id; - OSModuleLink link; - u32 numSections; - u32 sectionInfoOfs; - u32 nameOfs; - u32 nameSize; - u32 version; -} OSModuleInfo; +// typedef struct OSModuleInfo_s { +// u32 id; +// OSModuleLink link; +// u32 numSections; +// u32 sectionInfoOfs; +// u32 nameOfs; +// u32 nameSize; +// u32 version; +// } OSModuleInfo; -typedef struct OSModuleHeader_s { - OSModuleInfo info; - u32 bssSize; - u32 relOfs; - u32 impOfs; - u32 impSize; +// typedef struct OSModuleHeader_s { +// OSModuleInfo info; +// u32 bssSize; +// u32 relOfs; +// u32 impOfs; +// u32 impSize; - u8 prologSection; - u8 epilogSection; - u8 unresolvedSection; - u8 bssSection; +// u8 prologSection; +// u8 epilogSection; +// u8 unresolvedSection; +// u8 bssSection; - u32 prolog; - u32 epilog; - u32 unresolved; - /* OS_MODULE_VERSION >= 2 */ +// u32 prolog; +// u32 epilog; +// u32 unresolved; +// /* OS_MODULE_VERSION >= 2 */ - u32 align; - u32 bssAlign; -} OSModuleHeader; +// u32 align; +// u32 bssAlign; +// } OSModuleHeader; -typedef struct OSSectionInfo_s { - u32 offset; - u32 size; -} OSSectionInfo; +// typedef struct OSSectionInfo_s { +// u32 offset; +// u32 size; +// } OSSectionInfo; -#define OSGetSectionInfo(module) \ - ((OSSectionInfo*) (((OSModuleInfo*) (module))->sectionInfoOfs)) +// #define OSGetSectionInfo(module) \ +// ((OSSectionInfo*) (((OSModuleInfo*) (module))->sectionInfoOfs)) -#define OS_SECTIONINFO_EXEC 1 -#define OS_SECTIONINFO_OFFSET(offset) ((offset) & ~OS_SECTIONINFO_EXEC) +// #define OS_SECTIONINFO_EXEC 1 +// #define OS_SECTIONINFO_OFFSET(offset) ((offset) & ~OS_SECTIONINFO_EXEC) -void OSSetStringTable (const void* strTable); -BOOL OSLink(OSModuleInfo* module, void* bss); -BOOL OSUnlink(OSModuleInfo* module); +// void OSSetStringTable (const void* strTable); +// BOOL OSLink(OSModuleInfo* module, void* bss); +// BOOL OSUnlink(OSModuleInfo* module); #ifdef __cplusplus } diff --git a/include/dolphin/os/OSReset.h b/include/dolphin/os/OSReset.h index fa200677..ee9a567a 100644 --- a/include/dolphin/os/OSReset.h +++ b/include/dolphin/os/OSReset.h @@ -13,6 +13,11 @@ extern "C" { #define OS_RESET_HOTRESET 1 /* Soft reset */ #define OS_RESET_SHUTDOWN 2 +struct OSResetFunctionQueue { + struct OSResetFunctionInfo* head; + struct OSResetFunctionInfo* tail; +}; + typedef BOOL (*OSResetFunction)(BOOL final); typedef struct OSResetFunctionInfo OSResetFunctionInfo; diff --git a/include/dolphin/os/OSResetSW.h b/include/dolphin/os/OSResetSW.h index fe9b4045..fe52cd8c 100644 --- a/include/dolphin/os/OSResetSW.h +++ b/include/dolphin/os/OSResetSW.h @@ -7,7 +7,11 @@ extern "C" { #endif -BOOL OSGetResetSwitchState(); +typedef void (*OSResetCallback)(void); + +OSResetCallback OSSetResetCallback(OSResetCallback callback); +BOOL OSGetResetSwitchState(void); +BOOL OSGetResetButtonState(void); #ifdef __cplusplus } diff --git a/include/dolphin/os/OSTime.h b/include/dolphin/os/OSTime.h index ce7f4748..9d621752 100644 --- a/include/dolphin/os/OSTime.h +++ b/include/dolphin/os/OSTime.h @@ -46,6 +46,19 @@ typedef struct OSCalendarTime_s { OSTime OSCalendarTimeToTicks(OSCalendarTime* td); void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td); +#define USEC_MAX 1000 +#define MSEC_MAX 1000 +#define MONTH_MAX 12 +#define WEEK_DAY_MAX 7 +#define YEAR_DAY_MAX 365 + +#define SECS_IN_MIN 60 +#define SECS_IN_HOUR (SECS_IN_MIN * 60) +#define SECS_IN_DAY (SECS_IN_HOUR * 24) +#define SECS_IN_YEAR (SECS_IN_DAY * 365) + +#define BIAS 0xB2575 + #ifdef __cplusplus } #endif diff --git a/src/static/JSystem/JUtility/JUTException.cpp b/src/static/JSystem/JUtility/JUTException.cpp index 6086c10b..197182f5 100644 --- a/src/static/JSystem/JUtility/JUTException.cpp +++ b/src/static/JSystem/JUtility/JUTException.cpp @@ -187,7 +187,7 @@ bool JUTException::searchPartialModule(u32 address, u32* module_id, u32* section if (section_offset) *section_offset = address - addr; if (name_offset) - *name_offset = module->nameOfs; + *name_offset = module->nameOffset; return true; } } diff --git a/src/static/boot.c b/src/static/boot.c index 763e24bb..c80ba5b6 100644 --- a/src/static/boot.c +++ b/src/static/boot.c @@ -85,7 +85,7 @@ s32 search_partial_address(u32 addr, u32* module_id, u32* section_idx, u32* sect *section_addr = addr - section_ofs; } if (module_name_ofs != nullptr) { - *module_name_ofs = module_p->info.nameOfs; + *module_name_ofs = module_p->info.nameOffset; } return 0; /* success */ diff --git a/src/static/dolphin/os/OS.c b/src/static/dolphin/os/OS.c new file mode 100644 index 00000000..cc32a837 --- /dev/null +++ b/src/static/dolphin/os/OS.c @@ -0,0 +1,583 @@ +#include +#include +#include +#include +#include +#include +#include "../src/static/dolphin/os/__os.h" + +void EnableMetroTRKInterrupts(void); + +#define OS_CURRENTCONTEXT_PADDR 0x00C0 + +#define OS_EXCEPTIONTABLE_ADDR 0x3000 +#define OS_DBJUMPPOINT_ADDR 0x60 +// memory locations for important stuff +#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 + +extern unsigned long __DVDLongFileNameFlag; +extern unsigned long __PADSpec; +extern unsigned char __ArenaLo[]; +extern char _stack_addr[]; +extern unsigned char __ArenaHi[]; + +// dummy entry points to the OS Exception vector +void __OSEVStart(void); +void __OSEVEnd(void); +void __OSEVSetNumber(void); +void __OSExceptionVector(void); + +void __DBVECTOR(void); +void __OSDBINTSTART(void); +void __OSDBINTEND(void); +void __OSDBJUMPSTART(void); +void __OSDBJUMPEND(void); + +#define NOP 0x60000000 + +static OSBootInfo* BootInfo; +static volatile u32* BI2DebugFlag; +static u32* BI2DebugFlagHolder; +static f64 ZeroPS; +static f64 ZeroF; +static BOOL __OSIsGcam; +static BOOL AreWeInitialized; + +typedef void (*OSExceptionHandler)(u8, struct OSContext*); +static OSExceptionHandler* OSExceptionTable; + +static void* __OSSavedRegionEnd; +static void* __OSSavedRegionStart; +static BOOL __OSInIPL; +OSTime __OSStartTime; + +static DVDDriveInfo DriveInfo __attribute__((aligned(0x20))); +static DVDCommandBlock DriveBlock; + +// functions +static asm void __OSInitFPRs(void); +static void OSExceptionInit(void); +static void OSDefaultExceptionHandler(u8 exception /* r3 */, + OSContext* context /* r4 */); + +// NOTE: this is unused, but stuff won't align properly without it +static asm void __OSInitFPRs(void) +{ +#ifdef __MWERKS__ // 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 +#endif // clang-format on +} + +unsigned long OSGetConsoleType() +{ + if ((!BootInfo) || (BootInfo->consoleType == 0)) { + return OS_CONSOLE_ARTHUR; + } + return BootInfo->consoleType; +} + +volatile u16 __OSDeviceCode AT_ADDRESS(0x800030E6); + +static void ClearArena() +{ + if (OSGetResetCode() != -0x80000000) { + __OSSavedRegionStart = NULL; + __OSSavedRegionEnd = NULL; + memset(OSGetArenaLo(), 0, (u8*)OSGetArenaHi() - (u8*)OSGetArenaLo()); + return; + } + + __OSSavedRegionStart = BOOT_REGION_START; + __OSSavedRegionEnd = BOOT_REGION_END; + + if (BOOT_REGION_START == NULL) { + memset(OSGetArenaLo(), 0, (u8*)OSGetArenaHi() - (u8*)OSGetArenaLo()); + return; + } + + if ((u8*)OSGetArenaLo() < (u8*)__OSSavedRegionStart) { + if ((u8*)OSGetArenaHi() <= (u8*)__OSSavedRegionStart) { + memset(OSGetArenaLo(), 0, + (u8*)OSGetArenaHi() - (u8*)OSGetArenaLo()); + return; + } + + memset(OSGetArenaLo(), 0, + (u8*)__OSSavedRegionStart - (u8*)OSGetArenaLo()); + + if ((u8*)OSGetArenaHi() > (u8*)__OSSavedRegionEnd) { + memset(__OSSavedRegionEnd, 0, + (u8*)OSGetArenaHi() - (u8*)__OSSavedRegionEnd); + } + } +} + +static void InquiryCallback(s32 result, struct DVDCommandBlock* block) +{ + switch (block->state) { + case 0: + __OSDeviceCode = DriveInfo.deviceCode | 0x8000; + break; + default: + __OSDeviceCode = 1; + break; + } +} + +void OSInit() +{ + u32 consoleType; + BI2Debug* bi2DebugInfo; + + if (AreWeInitialized != 0) + return; + + AreWeInitialized = 1; + __OSStartTime = __OSGetSystemTime(); + OSDisableInterrupts(); + PPCDisableSpeculation(); + PPCSetFpNonIEEEMode(); + BootInfo = (struct OSBootInfo_s*)OSPhysicalToCached(0); + BI2DebugFlag = NULL; + __DVDLongFileNameFlag = 0; + bi2DebugInfo = (BI2Debug*)*(BI2Debug**)OS_BI2_DEBUG_ADDRESS; + if (bi2DebugInfo != NULL) { + BI2DebugFlag = &bi2DebugInfo->debugFlag; + __PADSpec = bi2DebugInfo->padSpec; + *((u8*)DEBUGFLAG_ADDR) = (u8)*BI2DebugFlag; + *((u8*)OS_DEBUG_ADDRESS_2) = (u8)__PADSpec; + } else if (BootInfo->arenaHi) { + BI2DebugFlagHolder = (u32*)*((u8*)DEBUGFLAG_ADDR); + BI2DebugFlag = (u32*)&BI2DebugFlagHolder; + __PADSpec = (u32) * ((u8*)OS_DEBUG_ADDRESS_2); + } + + __DVDLongFileNameFlag = 1; + + OSSetArenaLo((!BootInfo->arenaLo) ? &__ArenaLo : BootInfo->arenaLo); + if ((!BootInfo->arenaLo) && (BI2DebugFlag) && (*(u32*)BI2DebugFlag < 2)) { + OSSetArenaLo((void*)(((u32)(char*)&_stack_addr + 0x1F) & 0xFFFFFFE0)); + } + OSSetArenaHi((!BootInfo->arenaHi) ? &__ArenaHi : BootInfo->arenaHi); + OSExceptionInit(); + __OSInitSystemCall(); + OSInitAlarm(); + __OSModuleInit(); + __OSInterruptInit(); + __OSSetInterruptHandler(0x16, &__OSResetSWInterruptHandler); + __OSContextInit(); + __OSCacheInit(); + EXIInit(); + SIInit(); + __OSInitSram(); + __OSThreadInit(); + __OSInitAudioSystem(); + PPCMthid2(PPCMfhid2() & 0xbfffffff); + if ((BootInfo->consoleType & OS_CONSOLE_DEVELOPMENT) != 0) { + BootInfo->consoleType = OS_CONSOLE_DEVHW1; + } else { + BootInfo->consoleType = OS_CONSOLE_RETAIL1; + } + BootInfo->consoleType += (__PIRegs[11] & 0xF0000000) >> 28; + if (__OSInIPL == 0) { + __OSInitMemoryProtection(); + } + + OSReport("\nDolphin OS $Revision: 54 $.\n"); + OSReport("Kernel built : %s %s\n", "Jun 5 2002", "02:09:12"); + + OSReport("Console Type : "); + + consoleType = OSGetConsoleType(); + // work out what console type this corresponds to and report it + // consoleTypeSwitchHi = inputConsoleType & 0xF0000000; + if ((consoleType & 0x10000000) == OS_CONSOLE_RETAIL) { // check "first" byte + OSReport("Retail %d\n", consoleType); + } else { + switch (consoleType) { // if "first" byte is 2, check "the rest" + 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: + OSReport("Development HW%d\n", ((u32)consoleType - 0x10000000) - 3); + break; + } + } + + // report memory size + OSReport("Memory %d MB\n", (u32)BootInfo->memorySize >> 0x14U); + // report heap bounds + OSReport("Arena : 0x%x - 0x%x\n", OSGetArenaLo(), OSGetArenaHi()); + + // if location of debug flag exists, and flag is >= 2, enable + // MetroTRKInterrupts + if (BI2DebugFlag && ((*BI2DebugFlag) >= 2)) { + EnableMetroTRKInterrupts(); + } + ClearArena(); + OSEnableInterrupts(); + if (__OSInIPL == 0) { + DVDInit(); + + if (__OSIsGcam) { + __OSDeviceCode = 0x9000; + return; + } + + DCInvalidateRange(&DriveInfo, 0x20); + DVDInquiryAsync(&DriveBlock, &DriveInfo, InquiryCallback); + } +} + +static u32 __OSExceptionLocations[] = { + 0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500, + 0x00000600, 0x00000700, 0x00000800, 0x00000900, 0x00000C00, + 0x00000D00, 0x00000F00, 0x00001300, 0x00001400, 0x00001700, +}; + +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)__OSDBJUMPSTART - (u32)__OSDBINTSTART); + DCFlushRangeNoSync(destAddr, + (u32)__OSDBJUMPSTART - (u32)__OSDBINTSTART); + __sync(); + ICInvalidateRange(destAddr, (u32)__OSDBJUMPSTART - (u32)__OSDBINTSTART); + } + + // Copy the right vector into the table + for (exception = 0; exception < __OS_EXCEPTION_MAX; 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 = (void*)OSPhysicalToCached(OS_EXCEPTIONTABLE_ADDR); + + // install default exception handlers + for (exception = 0; exception < __OS_EXCEPTION_MAX; 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"); +} + +static asm void __OSDBIntegrator(void) +{ +#ifdef __MWERKS__ // clang-format off + nofralloc +entry __OSDBINTSTART + li r5, OS_DBINTERFACE_ADDR + mflr r3 + stw r3, DB_EXCEPTIONRET_OFFSET(r5) + lwz r3, DB_EXCEPTIONDEST_OFFSET(r5) + oris r3, r3, OS_CACHED_REGION_PREFIX + mtlr r3 + li r3, 0x30 // MSR_IR | MSR_DR // turn on memory addressing + mtmsr r3 + blr +entry __OSDBINTEND +#endif // clang-format on +} + +static asm void __OSDBJump(void) { +#ifdef __MWERKS__ // clang-format off + nofralloc +entry __OSDBJUMPSTART + bla OS_DBJUMPPOINT_ADDR +entry __OSDBJUMPEND +#endif // clang-format on +} + +__OSExceptionHandler __OSSetExceptionHandler(__OSException exception, + __OSExceptionHandler handler) +{ + __OSExceptionHandler oldHandler; + + oldHandler = OSExceptionTable[exception]; + OSExceptionTable[exception] = handler; + return oldHandler; +} + +__OSExceptionHandler __OSGetExceptionHandler(__OSException exception) +{ + return OSExceptionTable[exception]; +} + +static asm void OSExceptionVector(void) +{ +#ifdef __MWERKS__ // 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 + addi r3, 0, 0x0000 + + // Load current context virtual address into r4 + lwz r4, 0xD4 + + // Check non-recoverable interrupt + rlwinm. r5, r5, 0, MSR_RI_BIT, MSR_RI_BIT + bne recoverable + addis r5, 0, OSDefaultExceptionHandler@ha + addi r5, r5, OSDefaultExceptionHandler@l + mtsrr0 r5 + rfi + // NOT REACHED HERE + +recoverable: + // Locate exception handler. + rlwinm r5, r3, 2, 22, 29 // 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 enalbed, not yet recoverable + + rfi + // NOT REACHED HERE + // The handler will restore state + +entry __OSEVEnd + nop +#endif // clang-format on +} + +void __OSUnhandledException(__OSException exception, OSContext* context, + u32 dsisr, u32 dar); +asm void OSDefaultExceptionHandler(register __OSException exception, + register OSContext* context) +{ +#ifdef __MWERKS__ // clang-format off + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + mfdsisr r5 + mfdar r6 + stwu r1, -0x8(r1) + b __OSUnhandledException +#endif // clang-format on +} + +void __OSPSInit(void) +{ + PPCMthid2(PPCMfhid2() | 0x80000000 | 0x20000000); + ICFlashInvalidate(); + __sync(); +#ifdef __MWERKS__ // clang-format off + asm + { + li r3, 0 + mtspr GQR0, r3 + } +#endif // clang-format on +} + +#define DI_CONFIG_IDX 0x9 +#define DI_CONFIG_CONFIG_MASK 0xFF + +u32 __OSGetDIConfig(void) +{ + return (__DIRegs[DI_CONFIG_IDX] & DI_CONFIG_CONFIG_MASK); +} diff --git a/src/static/dolphin/os/OSAlloc.c b/src/static/dolphin/os/OSAlloc.c new file mode 100644 index 00000000..ce8720fb --- /dev/null +++ b/src/static/dolphin/os/OSAlloc.c @@ -0,0 +1,389 @@ +#include +#include +#include +#include + +#define ALIGNMENT 32 + +#define InRange(cell, arenaStart, arenaEnd) \ + ((u32)arenaStart <= (u32)cell) && ((u32)cell < (u32)arenaEnd) + +#define HEADERSIZE 32u +#define MINOBJSIZE 64u + +struct Cell { + struct Cell* prev; + struct Cell* next; + long size; +}; + +struct HeapDesc { + long size; + struct Cell* free; + struct Cell* allocated; +}; + +volatile int __OSCurrHeap = -1; + +static struct HeapDesc* HeapArray; +static int NumHeaps; +static void* ArenaStart; +static void* ArenaEnd; + +// functions +static struct Cell* DLAddFront(struct Cell* list, struct Cell* cell); +static struct Cell* DLLookup(struct Cell* list, struct Cell* cell); +static struct Cell* DLExtract(struct Cell* list, struct Cell* cell); +static struct Cell* DLInsert(struct Cell* list, struct Cell* cell); + +static struct Cell* DLAddFront(struct Cell* list, struct Cell* cell) +{ + cell->next = list; + cell->prev = 0; + if (list) { + list->prev = cell; + } + return cell; +} + +static struct Cell* DLLookup(struct Cell* list, struct Cell* cell) +{ + for (; list; list = list->next) { + if (list == cell) { + return list; + } + } + return NULL; +} + +static struct Cell* DLExtract(struct Cell* list, struct Cell* cell) +{ + if (cell->next) { + cell->next->prev = cell->prev; + } + if (cell->prev == NULL) { + return cell->next; + } + cell->prev->next = cell->next; + return list; +} + +static struct Cell* DLInsert(struct Cell* list, struct Cell* cell) +{ + struct Cell* prev; + struct Cell* next; + + for (next = list, prev = NULL; next != 0; prev = next, next = next->next) { + if (cell <= next) { + break; + } + } + + cell->next = next; + cell->prev = prev; + if (next) { + next->prev = cell; + if ((u8*)cell + cell->size == (u8*)next) { + cell->size += next->size; + next = next->next; + cell->next = next; + if (next) { + next->prev = cell; + } + } + } + if (prev) { + prev->next = cell; + if ((u8*)prev + prev->size == (u8*)cell) { + prev->size += cell->size; + prev->next = next; + if (next) { + next->prev = prev; + } + } + return list; + } + return cell; +} + +void* OSAllocFromHeap(int heap, unsigned long size) +{ + struct HeapDesc* hd; + struct Cell* cell; + struct Cell* newCell; + long leftoverSize; + long requested; + + requested = size; + ASSERTMSGLINE(0x14D, HeapArray, + "OSAllocFromHeap(): heap is not initialized."); + ASSERTMSGLINE(0x14E, (signed long)size > 0, + "OSAllocFromHeap(): invalid size."); + ASSERTMSGLINE(0x14F, heap >= 0 && heap < NumHeaps, + "OSAllocFromHeap(): invalid heap handle."); + ASSERTMSGLINE(0x150, HeapArray[heap].size >= 0, + "OSAllocFromHeap(): invalid heap handle."); + + hd = &HeapArray[heap]; + size += 0x20; + size = (size + 0x1F) & 0xFFFFFFE0; + + for (cell = hd->free; cell != NULL; cell = cell->next) { + if ((signed)size <= (signed)cell->size) { + break; + } + } + + if (cell == NULL) { + return NULL; + } + ASSERTMSGLINE(0x168, !((s32)cell & 0x1F), + "OSAllocFromHeap(): heap is broken."); + ASSERTMSGLINE(0x169, cell->hd == NULL, + "OSAllocFromHeap(): heap is broken."); + + leftoverSize = cell->size - size; + if (leftoverSize < 0x40U) { + hd->free = DLExtract(hd->free, cell); + } else { + cell->size = size; + newCell = (void*)((u8*)cell + size); + newCell->size = leftoverSize; + newCell->prev = cell->prev; + newCell->next = cell->next; + if (newCell->next != NULL) { + newCell->next->prev = newCell; + } + if (newCell->prev != NULL) { + newCell->prev->next = newCell; + } else { + ASSERTMSGLINE(0x186, hd->free == cell, + "OSAllocFromHeap(): heap is broken."); + hd->free = newCell; + } + } + + hd->allocated = DLAddFront(hd->allocated, cell); + return (u8*)cell + 0x20; +} + +void OSFreeToHeap(int heap, void* ptr) +{ + struct HeapDesc* hd; + struct Cell* cell; + + ASSERTMSGLINE(0x23D, HeapArray, "OSFreeToHeap(): heap is not initialized."); + ASSERTMSGLINE( + 0x23F, ((u32)ArenaStart + 0x20) <= (u32)ptr && (u32)ptr < (u32)ArenaEnd, + "OSFreeToHeap(): invalid pointer."); + ASSERTMSGLINE(0x240, OFFSET(ptr, ALIGNMENT) == 0, + "OSFreeToHeap(): invalid pointer."); + ASSERTMSGLINE(0x241, HeapArray[heap].size >= 0, + "OSFreeToHeap(): invalid heap handle."); + cell = (void*)((u32)ptr - 0x20); + hd = &HeapArray[heap]; + ASSERTMSGLINE(0x246, cell->hd == hd, "OSFreeToHeap(): invalid pointer."); + ASSERTMSGLINE(0x247, DLLookup(hd->allocated, cell), + "OSFreeToHeap(): invalid pointer."); + + hd->allocated = DLExtract(hd->allocated, cell); + hd->free = DLInsert(hd->free, cell); +} + +void* OSInitAlloc(void* arenaStart, void* arenaEnd, int maxHeaps) +{ + unsigned long arraySize; + int i; + struct HeapDesc* hd; + + ASSERTMSGLINE(0x283, maxHeaps > 0, + "OSInitAlloc(): invalid number of heaps."); + ASSERTMSGLINE(0x285, (u32)arenaStart < (u32)arenaEnd, + "OSInitAlloc(): invalid range."); + ASSERTMSGLINE(0x288, maxHeaps <= (((u32)arenaEnd - (u32)arenaStart) / 24U), + "OSInitAlloc(): too small range."); + arraySize = maxHeaps * sizeof(struct HeapDesc); + HeapArray = arenaStart; + NumHeaps = maxHeaps; + + for (i = 0; i < NumHeaps; i++) { + hd = &HeapArray[i]; + hd->size = -1; + hd->free = hd->allocated = 0; + } + __OSCurrHeap = -1; + arenaStart = (void*)((u32)((char*)HeapArray + arraySize)); + arenaStart = (void*)(((u32)arenaStart + 0x1F) & 0xFFFFFFE0); + ArenaStart = arenaStart; + ArenaEnd = (void*)((u32)arenaEnd & 0xFFFFFFE0); + ASSERTMSGLINE(0x2A4, ((u32)ArenaEnd - (u32)ArenaStart) >= 0x40U, + "OSInitAlloc(): too small range."); + return arenaStart; +} + +int OSCreateHeap(void* start, void* end) +{ + int heap; + struct HeapDesc* hd; + struct Cell* cell; + + ASSERTMSGLINE(0x2BD, HeapArray, "OSCreateHeap(): heap is not initialized."); + ASSERTMSGLINE(0x2BE, (u32)start < (u32)end, + "OSCreateHeap(): invalid range."); + + start = (void*)(((u32)start + 0x1FU) & ~((32) - 1)); + end = (void*)(((u32)end) & ~((32) - 1)); + + ASSERTMSGLINE(0x2C1, (u32)start < (u32)end, + "OSCreateHeap(): invalid range."); + ASSERTMSGLINE(0x2C3, + (u32)ArenaStart <= (u32)start && (u32)end <= (u32)ArenaEnd, + "OSCreateHeap(): invalid range."); + ASSERTMSGLINE(0x2C5, ((u32)end - (u32)start) >= 0x40U, + "OSCreateHeap(): too small range."); + + for (heap = 0; heap < NumHeaps; heap++) { + hd = &HeapArray[heap]; + if (hd->size < 0) { + hd->size = (u32)end - (u32)start; + cell = start; + cell->prev = 0; + cell->next = 0; + cell->size = hd->size; + hd->free = cell; + hd->allocated = 0; + return heap; + } + } + return -1; +} + +void OSDestroyHeap(int heap) +{ + struct HeapDesc* hd; + long size; + + ASSERTMSGLINE(0x30A, HeapArray, + "OSDestroyHeap(): heap is not initialized."); + ASSERTMSGLINE(0x30B, (heap >= 0) && (heap < NumHeaps), + "OSDestroyHeap(): invalid heap handle."); + ASSERTMSGLINE(0x30C, HeapArray[heap].size >= 0, + "OSDestroyHeap(): invalid heap handle."); + + hd = &HeapArray[heap]; + + hd->size = -1; +} + +// custom macro for OSCheckHeap +#define ASSERTREPORT(line, cond) \ + if (!(cond)) { \ + OSReport("OSCheckHeap: Failed " #cond " in %d", line); \ + return -1; \ + } + +long OSCheckHeap(int heap) +{ + struct HeapDesc* hd; + struct Cell* cell; + long total = 0; + long free = 0; + + ASSERTREPORT(0x37D, HeapArray); + ASSERTREPORT(0x37E, 0 <= heap && heap < NumHeaps); + hd = &HeapArray[heap]; + ASSERTREPORT(0x381, 0 <= hd->size); + + ASSERTREPORT(0x383, hd->allocated == NULL || hd->allocated->prev == NULL); + + for (cell = hd->allocated; cell; cell = cell->next) { + ASSERTREPORT(0x386, InRange(cell, ArenaStart, ArenaEnd)); + ASSERTREPORT(0x387, OFFSET(cell, ALIGNMENT) == 0); + ASSERTREPORT(0x388, cell->next == NULL || cell->next->prev == cell); + ASSERTREPORT(0x389, MINOBJSIZE <= cell->size); + ASSERTREPORT(0x38A, OFFSET(cell->size, ALIGNMENT) == 0); + total += cell->size; + ASSERTREPORT(0x38D, 0 < total && total <= hd->size); + } + + ASSERTREPORT(0x395, hd->free == NULL || hd->free->prev == NULL); + + for (cell = hd->free; cell; cell = cell->next) { + ASSERTREPORT(0x398, InRange(cell, ArenaStart, ArenaEnd)); + ASSERTREPORT(0x399, OFFSET(cell, ALIGNMENT) == 0); + ASSERTREPORT(0x39A, cell->next == NULL || cell->next->prev == cell); + ASSERTREPORT(0x39B, MINOBJSIZE <= cell->size); + ASSERTREPORT(0x39C, OFFSET(cell->size, ALIGNMENT) == 0); + // NOTE: macro arg is stringified so format mustn't touch it + // clang-format off + ASSERTREPORT(0x39D, cell->next == NULL + || (char*) cell + cell->size < (char*) cell->next); + // clang-format on + total += cell->size; + free = (cell->size + free); + free -= HEADERSIZE; + ASSERTREPORT(0x3A1, 0 < total && total <= hd->size); + } + ASSERTREPORT(0x3A8, total == hd->size); + return free; +} + +unsigned long OSReferentSize(void* ptr) +{ + struct Cell* cell; + + ASSERTMSGLINE(0x3BB, HeapArray, + "OSReferentSize(): heap is not initialized."); + ASSERTMSGLINE(0x3BD, InRange(ptr, ArenaStart + HEADERSIZE, ArenaEnd), + "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(0x3BE, !OFFSET(ptr, 32), + "OSReferentSize(): invalid pointer."); + cell = (void*)((u32)ptr - HEADERSIZE); + ASSERTMSGLINE(0x3C2, cell->hd, "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(0x3C4, !(((u32)cell->hd - (u32)HeapArray) % 24), + "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE( + 0x3C6, + ((u32)HeapArray <= (u32)cell->hd) + && ((u32)cell->hd < (u32)((u32)HeapArray + (NumHeaps * 0x18))), + "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(0x3C7, cell->hd->size >= 0, + "OSReferentSize(): invalid pointer."); + ASSERTMSGLINE(0x3C9, DLLookup(cell->hd->allocated, cell), + "OSReferentSize(): invalid pointer."); + return (long)((u32)cell->size - HEADERSIZE); +} + +void OSDumpHeap(int heap) +{ + struct HeapDesc* hd; + struct Cell* cell; + + OSReport("\nOSDumpHeap(%d):\n", heap); + ASSERTMSGLINE(0x3DE, HeapArray, "OSDumpHeap(): heap is not initialized."); + ASSERTMSGLINE(0x3DF, (heap >= 0) && (heap < NumHeaps), + "OSDumpHeap(): invalid heap handle."); + hd = &HeapArray[heap]; + if (hd->size < 0) { + OSReport("--------Inactive\n"); + return; + } + ASSERTMSGLINE(0x3E8, OSCheckHeap(heap) >= 0, + "OSDumpHeap(): heap is broken."); + + OSReport("addr size end prev next\n"); + OSReport("--------Allocated\n"); + + ASSERTMSGLINE(0x3F5, hd->allocated == NULL || hd->allocated->prev == NULL, + "OSDumpHeap(): heap is broken."); + + for (cell = hd->allocated; cell; cell = cell->next) { + OSReport("%x %d %x %x %x\n", cell, cell->size, + (char*)cell + cell->size, cell->prev, cell->next); + } + OSReport("--------Free\n"); + for (cell = hd->free; cell; cell = cell->next) { + OSReport("%x %d %x %x %x\n", cell, cell->size, + (char*)cell + cell->size, cell->prev, cell->next); + } +} diff --git a/src/static/dolphin/os/OSFont.c b/src/static/dolphin/os/OSFont.c new file mode 100644 index 00000000..4efe6ae2 --- /dev/null +++ b/src/static/dolphin/os/OSFont.c @@ -0,0 +1,505 @@ +#include +#include +#include + +#include "os/__os.h" + +static OSFontHeader* FontData; // type unsure +static u8* SheetImage; // type unsure +static u8* WidthTable; // type unsure +static int CharsInSheet; // type unsure + +static u16 HankakuToCode[] = { + 0x20C, 0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, + 0x217, 0x218, 0x219, 0x21A, 0x21B, 0x21C, 0x21D, 0x21E, 0x21F, 0x220, 0x221, + 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22A, 0x22B, 0x22C, + 0x22D, 0x22E, 0x22F, 0x230, 0x231, 0x232, 0x233, 0x234, 0x235, 0x236, 0x237, + 0x238, 0x239, 0x23A, 0x23B, 0x23C, 0x23D, 0x23E, 0x23F, 0x240, 0x241, 0x242, + 0x243, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24A, 0x24B, 0x24C, 0x24D, + 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257, 0x258, + 0x259, 0x25A, 0x25B, 0x25C, 0x25D, 0x25E, 0x25F, 0x260, 0x261, 0x262, 0x263, + 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x20C, 0x20C, 0x20C, 0x20C, + 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, + 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, + 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x20C, 0x26B, 0x26C, 0x26D, + 0x26E, 0x26F, 0x270, 0x271, 0x272, 0x273, 0x274, 0x275, 0x276, 0x277, 0x278, + 0x279, 0x27A, 0x27B, 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, 0x282, 0x283, + 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A, 0x28B, 0x28C, 0x28D, 0x28E, + 0x28F, 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, + 0x29A, 0x29B, 0x29C, 0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1, 0x2A2, 0x2A3, 0x2A4, + 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, +}; + +static u16 Zenkaku2Code[] = { + 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, 0x009, 0x00A, + 0x00B, 0x00C, 0x00D, 0x00E, 0x00F, 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, + 0x016, 0x017, 0x018, 0x019, 0x01A, 0x01B, 0x01C, 0x01D, 0x01E, 0x01F, 0x020, + 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x027, 0x028, 0x029, 0x02A, 0x02B, + 0x02C, 0x02D, 0x02E, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, + 0x037, 0x038, 0x039, 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x03F, 0x040, 0x041, + 0x042, 0x043, 0x044, 0x045, 0x046, 0x047, 0x048, 0x049, 0x04A, 0x04B, 0x04C, + 0x04D, 0x04E, 0x04F, 0x050, 0x051, 0x052, 0x053, 0x054, 0x055, 0x056, 0x057, + 0x058, 0x059, 0x05A, 0x05B, 0x05C, 0x05D, 0x05E, 0x05F, 0x060, 0x061, 0x062, + 0x063, 0x064, 0x065, 0x066, 0x067, 0x068, 0x069, 0x06A, 0x06B, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x06C, 0x06D, + 0x06E, 0x06F, 0x070, 0x071, 0x072, 0x073, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x074, 0x075, 0x076, 0x077, 0x078, 0x079, 0x07A, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x07B, + 0x07C, 0x07D, 0x07E, 0x07F, 0x080, 0x081, 0x082, 0x083, 0x084, 0x085, 0x086, + 0x087, 0x088, 0x089, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x08A, + 0x08B, 0x08C, 0x08D, 0x08E, 0x08F, 0x090, 0x091, 0x000, 0x000, 0x000, 0x000, + 0x092, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x093, 0x094, 0x095, 0x096, 0x097, 0x098, + 0x099, 0x09A, 0x09B, 0x09C, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x09D, 0x09E, 0x09F, 0x0A0, 0x0A1, 0x0A2, 0x0A3, 0x0A4, 0x0A5, 0x0A6, 0x0A7, + 0x0A8, 0x0A9, 0x0AA, 0x0AB, 0x0AC, 0x0AD, 0x0AE, 0x0AF, 0x0B0, 0x0B1, 0x0B2, + 0x0B3, 0x0B4, 0x0B5, 0x0B6, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x0B7, + 0x0B8, 0x0B9, 0x0BA, 0x0BB, 0x0BC, 0x0BD, 0x0BE, 0x0BF, 0x0C0, 0x0C1, 0x0C2, + 0x0C3, 0x0C4, 0x0C5, 0x0C6, 0x0C7, 0x0C8, 0x0C9, 0x0CA, 0x0CB, 0x0CC, 0x0CD, + 0x0CE, 0x0CF, 0x0D0, 0x000, 0x000, 0x000, 0x000, 0x0D1, 0x0D2, 0x0D3, 0x0D4, + 0x0D5, 0x0D6, 0x0D7, 0x0D8, 0x0D9, 0x0DA, 0x0DB, 0x0DC, 0x0DD, 0x0DE, 0x0DF, + 0x0E0, 0x0E1, 0x0E2, 0x0E3, 0x0E4, 0x0E5, 0x0E6, 0x0E7, 0x0E8, 0x0E9, 0x0EA, + 0x0EB, 0x0EC, 0x0ED, 0x0EE, 0x0EF, 0x0F0, 0x0F1, 0x0F2, 0x0F3, 0x0F4, 0x0F5, + 0x0F6, 0x0F7, 0x0F8, 0x0F9, 0x0FA, 0x0FB, 0x0FC, 0x0FD, 0x0FE, 0x0FF, 0x100, + 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A, 0x10B, + 0x10C, 0x10D, 0x10E, 0x10F, 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, + 0x117, 0x118, 0x119, 0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, + 0x122, 0x123, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12A, 0x12B, 0x12C, + 0x12D, 0x12E, 0x12F, 0x130, 0x131, 0x132, 0x133, 0x134, 0x135, 0x136, 0x137, + 0x138, 0x139, 0x13A, 0x13B, 0x13C, 0x13D, 0x13E, 0x13F, 0x140, 0x141, 0x142, + 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14A, 0x14B, 0x14C, 0x14D, + 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, + 0x159, 0x15A, 0x15B, 0x15C, 0x15D, 0x15E, 0x15F, 0x160, 0x161, 0x162, 0x163, + 0x164, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16A, 0x16B, 0x16C, 0x16D, 0x16E, + 0x16F, 0x170, 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0x177, 0x178, 0x179, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x17A, 0x17B, 0x17C, + 0x17D, 0x17E, 0x17F, 0x180, 0x181, 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, + 0x188, 0x189, 0x18A, 0x18B, 0x18C, 0x18D, 0x18E, 0x18F, 0x190, 0x191, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x192, 0x193, 0x194, 0x195, + 0x196, 0x197, 0x198, 0x199, 0x19A, 0x19B, 0x19C, 0x19D, 0x19E, 0x19F, 0x1A0, + 0x1A1, 0x1A2, 0x1A3, 0x1A4, 0x1A5, 0x1A6, 0x1A7, 0x1A8, 0x1A9, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x1AA, 0x1AB, 0x1AC, 0x1AD, 0x1AE, 0x1AF, 0x1B0, 0x1B1, + 0x1B2, 0x1B3, 0x1B4, 0x1B5, 0x1B6, 0x1B7, 0x1B8, 0x1B9, 0x1BA, 0x1BB, 0x1BC, + 0x1BD, 0x1BE, 0x1BF, 0x1C0, 0x1C1, 0x1C2, 0x1C3, 0x1C4, 0x1C5, 0x1C6, 0x1C7, + 0x1C8, 0x1C9, 0x1CA, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x1CB, 0x1CC, 0x1CD, 0x1CE, + 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1D5, 0x1D6, 0x1D7, 0x1D8, 0x1D9, + 0x1DA, 0x1DB, 0x1DC, 0x1DD, 0x1DE, 0x1DF, 0x1E0, 0x1E1, 0x1E2, 0x1E3, 0x1E4, + 0x1E5, 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1EA, 0x1EB, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x1EC, 0x1ED, + 0x1EE, 0x1EF, 0x1F0, 0x1F1, 0x1F2, 0x1F3, 0x1F4, 0x1F5, 0x1F6, 0x1F7, 0x1F8, + 0x1F9, 0x1FA, 0x1FB, 0x1FC, 0x1FD, 0x1FE, 0x1FF, 0x200, 0x201, 0x202, 0x203, + 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20A, 0x20B, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x20C, 0x20D, 0x20E, 0x20F, 0x210, 0x211, 0x212, 0x213, + 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21A, 0x21B, 0x21C, 0x21D, 0x21E, + 0x21F, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, + 0x22A, 0x22B, 0x22C, 0x22D, 0x22E, 0x22F, 0x230, 0x231, 0x232, 0x233, 0x234, + 0x235, 0x236, 0x237, 0x238, 0x239, 0x23A, 0x23B, 0x23C, 0x23D, 0x23E, 0x23F, + 0x240, 0x241, 0x242, 0x243, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24A, + 0x24B, 0x24C, 0x24D, 0x24E, 0x24F, 0x250, 0x251, 0x252, 0x253, 0x254, 0x255, + 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B, 0x25C, 0x25D, 0x25E, 0x25F, 0x260, + 0x261, 0x262, 0x263, 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26A, 0x26B, + 0x26C, 0x26D, 0x26E, 0x26F, 0x270, 0x271, 0x272, 0x273, 0x274, 0x275, 0x276, + 0x277, 0x278, 0x279, 0x27A, 0x27B, 0x27C, 0x27D, 0x27E, 0x27F, 0x280, 0x281, + 0x282, 0x283, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28A, 0x28B, 0x28C, + 0x28D, 0x28E, 0x28F, 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, + 0x298, 0x299, 0x29A, 0x29B, 0x29C, 0x29D, 0x29E, 0x29F, 0x2A0, 0x2A1, 0x2A2, + 0x2A3, 0x2A4, 0x2A5, 0x2A6, 0x2A7, 0x2A8, 0x2A9, 0x2AA, 0x2AB, 0x2AC, 0x2AD, + 0x2AE, 0x2AF, 0x2B0, 0x2B1, 0x2B2, 0x2B3, 0x2B4, 0x2B5, 0x2B6, 0x2B7, 0x2B8, + 0x2B9, 0x2BA, 0x2BB, 0x2BC, 0x2BD, 0x2BE, 0x2BF, 0x2C0, 0x2C1, 0x2C2, 0x2C3, + 0x2C4, 0x2C5, 0x2C6, 0x2C7, 0x2C8, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x2C9, 0x2CA, 0x2CB, 0x2CC, 0x2CD, + 0x2CE, 0x2CF, 0x2D0, 0x2D1, 0x2D2, 0x2D3, 0x2D4, 0x2D5, 0x2D6, 0x2D7, 0x2D8, + 0x2D9, 0x2DA, 0x2DB, 0x2DC, 0x2DD, 0x2DE, 0x2DF, 0x2E0, 0x2E1, 0x2E2, 0x2E3, + 0x2E4, 0x2E5, 0x2E6, 0x000, 0x2E7, 0x2E8, 0x2E9, 0x2EA, 0x2EB, 0x2EC, 0x2ED, + 0x2EE, 0x2EF, 0x2F0, 0x2F1, 0x2F2, 0x2F3, 0x2F4, 0x2F5, 0x2F6, 0x2F7, 0x2F8, + 0x2F9, 0x2FA, 0x2FB, 0x2FC, 0x2FD, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x2FE, 0x2FF, 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, + 0x307, 0x308, 0x309, 0x30A, 0x30B, 0x30C, 0x30D, 0x30E, 0x30F, 0x310, 0x311, + 0x312, 0x313, 0x314, 0x315, 0x316, 0x317, 0x318, 0x319, 0x31A, 0x31B, 0x000 +}; + +static int GetFontCode(unsigned short code) +{ + if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) { + if (code >= 0x20 && code <= 0xDF) { + return HankakuToCode[code - 0x20]; + } + + if (code > 0x889E) { + int i = ((code >> 8) - 0x88) * 188; + int j = (code & 0xFF) - 0x40; + + if (j >= 0x40) { + j--; + } + + return (i + j + 0x2BE); + } + + if (code < 0x879E) { + int i = ((code >> 8) - 0x81) * 188; + int j = (code & 0xFF) - 0x40; + + if (j >= 0x40) { + j--; + } + + return Zenkaku2Code[i + j]; + } + } else if (code > 0x20 && code <= 0xFF) { + return code - 0x20; + } else { + return 0; + } + return 0; +} + +static void Decode(unsigned char* s, unsigned char* d) +{ + int i; + int j; + int k; + int p; + int q; + int r7; // huh? DWARF info says these 2 variables might be register names + // and not actual names. + int r25; + int cnt; + int os; + unsigned int flag; + unsigned int code; + + os = *(int*)(s + 0x4); + r7 = *(int*)(s + 0x8); + r25 = *(int*)(s + 0xC); + + q = 0; + flag = 0; + p = 16; + + do { + // Get next mask + if (flag == 0) { + code = *(u32*)(s + p); + p += sizeof(u32); + flag = sizeof(u32) * 8; + } + + // Non-linked chunk + if (code & 0x80000000) { + d[q++] = s[r25++]; + } + // Linked chunk + else { + // Read offset from link table + j = s[r7] << 8 | s[r7 + 1]; + r7 += sizeof(u16); + + // Apply offset + k = q - (j & 0x0FFF); + cnt = j >> 12; + if (cnt == 0) { + cnt = s[r25++] + 0x12; + } else { + cnt += 2; + } + + // Copy chunk + for (i = 0; i < cnt; i++, q++, k++) { + d[q] = d[k - 1]; + } + } + + // Prepare next mask bit + code <<= 1; + flag--; + } while (q < os); +} + +static u32 GetFontSize(u8* buf) +{ + if (buf[0] == 'Y' && buf[1] == 'a' && buf[2] == 'y') { + return *(u32*)(buf + 0x4); + } + + return 0; +} + +unsigned short OSGetFontEncode(void) +{ + static u16 fontEncode = 0xFFFF; + if (fontEncode <= 1) { + return fontEncode; + } + switch (*(int*)OSPhysicalToCached(0xCC)) { + case VI_NTSC: + fontEncode = (__VIRegs[VI_DTV_STAT] & 2) ? 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; + } + + return fontEncode; +} + +static void ReadROM(void* buf, int length, int offset) +{ + int len; + while (length > 0) { + len = (length <= 0x100) ? length : 0x100; + length -= len; + + while (!__OSReadROM(buf, len, offset)) { + ; + } + + offset += len; + (u8*)buf += len; + } +} + +static u32 ReadFont(void* img) +{ + if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) { + ReadROM(img, OS_FONT_ROM_SIZE_SJIS, 0x1AFF00); + } else { + ReadROM(img, OS_FONT_ROM_SIZE_ANSI, 0x1FCF00); + } + + return GetFontSize(img); +} + +u32 OSLoadFont(OSFontHeader* fontData, void* temp) +{ + u32 size; + + SheetImage = NULL; + size = ReadFont(temp); + if (size) { + Decode(temp, (void*)fontData); + FontData = fontData; + WidthTable = (u8*)FontData + FontData->widthTable; + CharsInSheet = FontData->sheetColumn * FontData->sheetRow; + } + + return size; +} + +char* OSGetFontTexel(char* string, void* image, long pos, long stride, + long* width) +{ + unsigned short code; + unsigned char* src; + unsigned char* dst; + int fontCode; + int sheet; + int numChars; + int row; + int column; + int x; + int y; + int offsetSrc; + int offsetDst; + unsigned char* colorIndex; + unsigned char* imageSrc; + + ASSERTLINE(0x1F6, FontData && !SheetImage); + + code = *string; + if (code == '\0') { + return string; + } + + string++; + if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) { + if ((((code >= 0x80) && (code <= 0x9F)) + || ((code >= 0xE0) && (code <= 0xFF))) + && ((s8)*string != 0U)) { + code = (code << 8) | (*string++); // Shift-JIS encoded byte + } + } + colorIndex = &FontData->c0; + + ASSERTLINE(0x209, FontData->sheetFormat == GX_TF_I4); + + fontCode = GetFontCode(code); + + sheet = fontCode / CharsInSheet; + numChars = fontCode - (sheet * CharsInSheet); + row = numChars / FontData->sheetColumn; + column = (numChars - (row * FontData->sheetColumn)); + row *= FontData->cellHeight; + column *= FontData->cellWidth; + imageSrc = (u8*)FontData + FontData->sheetImage; + imageSrc += (sheet * FontData->sheetSize) / 2; + + for (y = 0; y < FontData->cellHeight; y++) { + for (x = 0; x < FontData->cellWidth; x++) { + src = imageSrc + + (((FontData->sheetWidth / 8) * 32) / 2) * ((row + y) / 8); + src += ((column + x) / 8) * 16; + src += ((row + y) % 8) * 2; + src += ((column + x) % 8) / 4; + + offsetSrc = (column + x) % 4; + + dst = (u8*)image + ((y / 8) * (((stride * 4) / 8) * 32)); + dst += (((pos + x) / 8) * 32); + dst += ((y % 8) * 4); + dst += ((pos + x) % 8) / 2; + + offsetDst = (pos + x) % 2; + + *dst |= colorIndex[*src >> (6 - (offsetSrc * 2)) & 3] + & ((offsetDst != 0) ? 0x0F : 0xF0); + } + } + *width = WidthTable[fontCode]; + + return string; +} + +static void ExpandFontSheet(u8* src, u8* dst) +{ + int i; + u8* colorIndex = &FontData->c0; + + if (FontData->sheetFormat == GX_TF_I4) { + for (i = (s32)(FontData->sheetFullSize) / 2 - 1; i >= 0; i--) { + dst[i * 2 + 0] = colorIndex[src[i] >> 6 & 3] & 0xF0 + | colorIndex[src[i] >> 4 & 3] & 0x0F; + dst[i * 2 + 1] = colorIndex[src[i] >> 2 & 3] & 0xF0 + | colorIndex[src[i] >> 0 & 3] & 0x0F; + } + } else if (FontData->sheetFormat == GX_TF_IA4) { + for (i = (s32)(FontData->sheetFullSize) / 4 - 1; i >= 0; i--) { + dst[i * 4 + 0] = colorIndex[src[i] >> 6 & 3]; + dst[i * 4 + 1] = colorIndex[src[i] >> 4 & 3]; + dst[i * 4 + 2] = colorIndex[src[i] >> 2 & 3]; + dst[i * 4 + 3] = colorIndex[src[i] >> 0 & 3]; + } + } + + DCStoreRange(dst, FontData->sheetFullSize); +} + +int OSInitFont(OSFontHeader* fontData) +{ + unsigned long size; + void* temp; + + if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) { + temp = (void*)((u8*)fontData + 0xD3F00); + } else { + temp = (void*)((u8*)fontData + 0x1D120); + } + temp = ((void*)(((u32)(temp)) & ~((32) - 1))); + size = OSLoadFont(fontData, temp); + if (size == 0) { + return 0; + } + SheetImage = (u8*)FontData + FontData->sheetImage; + SheetImage = (void*)((s32)(SheetImage + 0x1F) & 0xFFFFFFE0); + ExpandFontSheet((u8*)FontData + FontData->sheetImage, SheetImage); + return 1; +} + +char* OSGetFontTexture(char* string, void** image, long* x, long* y, + long* width) +{ + unsigned short code; + int fontCode; + int sheet; + int numChars; + int row; + int column; + + ASSERTLINE(0x291, SheetImage); + ASSERTLINE(0x292, WidthTable); + + code = *string; + if (code == 0) { + *image = NULL; + return string; + } + + string++; + if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) { + if ((((code >= 0x80) && (code <= 0x9F)) + || ((code >= 0xE0) && (code <= 0xFF))) + && ((s8)*string != 0U)) { + code = (code << 8) | (*string++); // Shift-JIS encoded byte + } + } + + fontCode = GetFontCode(code); + + sheet = fontCode / CharsInSheet; + ((u32*)image)[0] = (u32)SheetImage + (FontData->sheetSize * sheet); + numChars = fontCode - (sheet * CharsInSheet); + row = numChars / FontData->sheetColumn; + column = (numChars - (row * FontData->sheetColumn)); + *x = column * FontData->cellWidth; + *y = row * FontData->cellHeight; + + if (width) { + *width = WidthTable[fontCode]; + } + return string; +} + +char* OSGetFontWidth(char* string, s32* width) +{ + unsigned short code; + + ASSERTLINE(0x2C2, WidthTable); + + code = *string; + if (code == 0) { + return string; + } + + string++; + if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) { + if ((((code >= 0x80) && (code <= 0x9F)) + || ((code >= 0xE0) && (code <= 0xFF))) + && ((s8)*string != 0U)) { + code = (code << 8) | (*string++); // Shift-JIS encoded byte + } + } + *width = WidthTable[GetFontCode(code)]; + return string; +} diff --git a/src/static/dolphin/os/OSInterrupt.c b/src/static/dolphin/os/OSInterrupt.c index 2836e8d3..f8394f13 100644 --- a/src/static/dolphin/os/OSInterrupt.c +++ b/src/static/dolphin/os/OSInterrupt.c @@ -1,43 +1,424 @@ -#include "dolphin/os/OSInterrupt.h" +#include +#include +#include +#include -asm BOOL OSDisableInterrupts(void) { - // clang-format off - nofralloc +#include "../src/static/dolphin/os/__os.h" - entry __RAS_OSDisableInterrupts_begin - mfmsr r3 - rlwinm r4, r3, 0, 17, 15 - mtmsr r4 - entry __RAS_OSDisableInterrupts_end - rlwinm r3, r3, 17, 31, 31 - blr - // clang-format on +static asm void ExternalInterruptHandler(register __OSException exception, + register OSContext* context); + +extern void __RAS_OSDisableInterrupts_begin(void); +extern void __RAS_OSDisableInterrupts_end(void); + +static __OSInterruptHandler* InterruptHandlerTable; + +volatile OSTime __OSLastInterruptTime; +volatile __OSInterrupt __OSLastInterrupt; +volatile u32 __OSLastInterruptSrr0; + +static OSInterruptMask InterruptPrioTable[] = { + OS_INTERRUPTMASK_PI_ERROR, + OS_INTERRUPTMASK_PI_DEBUG, + OS_INTERRUPTMASK_MEM, + OS_INTERRUPTMASK_PI_RSW, + OS_INTERRUPTMASK_PI_VI, + OS_INTERRUPTMASK_PI_PE, + OS_INTERRUPTMASK_PI_HSP, + OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP | OS_INTERRUPTMASK_AI + | OS_INTERRUPTMASK_EXI | OS_INTERRUPTMASK_PI_SI + | OS_INTERRUPTMASK_PI_DI, + OS_INTERRUPTMASK_DSP_AI, + OS_INTERRUPTMASK_PI_CP, + 0xFFFFFFFF, +}; + +asm BOOL OSDisableInterrupts(void) +{ +#ifdef __MWERKS__ // clang-format off + nofralloc +entry __RAS_OSDisableInterrupts_begin + mfmsr r3 + rlwinm r4, r3, 0, 17, 15 + mtmsr r4 + rlwinm r3, r3, 17, 31, 31 +entry __RAS_OSDisableInterrupts_end + blr +#endif // clang-format on } -asm BOOL OSEnableInterrupts(void) { - // clang-format off - nofralloc - /* 8007AC38 7C6000A6 */ mfmsr r3 - /* 8007AC3C 60648000 */ ori r4, r3, 0x8000 - /* 8007AC40 7C800124 */ mtmsr r4 - /* 8007AC44 54638FFE */ rlwinm r3, r3, 0x11, 0x1f, 0x1f - /* 8007AC48 4E800020 */ blr - // clang-format on +asm BOOL OSEnableInterrupts(void) +{ +#ifdef __MWERKS__ // clang-format off + nofralloc + + mfmsr r3 + ori r4, r3, 0x8000 + mtmsr r4 + rlwinm r3, r3, 17, 31, 31 + blr +#endif // clang-format on } asm BOOL OSRestoreInterrupts(register BOOL level) { - // clang-format off - nofralloc - /* 8007AC4C 2C030000 */ cmpwi level, 0x0 - /* 8007AC50 7C8000A6 */ mfmsr r4 - /* 8007AC54 4182000C */ beq- lbl_8007ac60 - /* 8007AC58 60858000 */ ori r5, r4, 0x8000 - /* 8007AC5C 48000008 */ b lbl_8007ac64 - lbl_8007ac60: - /* 8007AC60 5485045E */ rlwinm r5, r4, 0, 0x11, 0xf - lbl_8007ac64: - /* 8007AC64 7CA00124 */ mtmsr r5 - /* 8007AC68 54838FFE */ rlwinm r3, r4, 0x11, 0x1f, 0x1f - /* 8007AC6C 4E800020 */ blr - // clang-format on -} \ No newline at end of file +#ifdef __MWERKS__ // clang-format off + nofralloc + + cmpwi level, 0 + mfmsr r4 + beq _disable + ori r5, r4, 0x8000 + b _restore +_disable: + rlwinm r5, r4, 0, 17, 15 +_restore: + mtmsr r5 + rlwinm r3, r4, 17, 31, 31 + blr +#endif // clang-format on +} + +__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, + __OSInterruptHandler handler) +{ + __OSInterruptHandler oldHandler; + + oldHandler = InterruptHandlerTable[interrupt]; + InterruptHandlerTable[interrupt] = handler; + return oldHandler; +} + +__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt) +{ + return InterruptHandlerTable[interrupt]; +} + +void __OSInterruptInit(void) +{ + InterruptHandlerTable = (void*)OSPhysicalToCached(0x3040); + + memset(InterruptHandlerTable, 0, + __OS_INTERRUPT_MAX * 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, ExternalInterruptHandler); +} + +static u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current) +{ + u32 reg; + + switch (__cntlzw(mask)) { + case __OS_INTERRUPT_MEM_0: + case __OS_INTERRUPT_MEM_1: + case __OS_INTERRUPT_MEM_2: + case __OS_INTERRUPT_MEM_3: + case __OS_INTERRUPT_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_INTERRUPT_DSP_AI: + case __OS_INTERRUPT_DSP_ARAM: + case __OS_INTERRUPT_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_INTERRUPT_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_INTERRUPT_EXI_0_EXI: + case __OS_INTERRUPT_EXI_0_TC: + case __OS_INTERRUPT_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_INTERRUPT_EXI_1_EXI: + case __OS_INTERRUPT_EXI_1_TC: + case __OS_INTERRUPT_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_INTERRUPT_EXI_2_EXI: + case __OS_INTERRUPT_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_INTERRUPT_PI_CP: + case __OS_INTERRUPT_PI_SI: + case __OS_INTERRUPT_PI_DI: + case __OS_INTERRUPT_PI_RSW: + case __OS_INTERRUPT_PI_ERROR: + case __OS_INTERRUPT_PI_VI: + case __OS_INTERRUPT_PI_DEBUG: + case __OS_INTERRUPT_PI_PE_TOKEN: + case __OS_INTERRUPT_PI_PE_FINISH: + case __OS_INTERRUPT_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; +} + +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 (interrupt > __OS_INTERRUPT_MEM_ADDRESS) { + __OSLastInterrupt = interrupt; + __OSLastInterruptTime = OSGetTime(); + __OSLastInterruptSrr0 = context->srr0; + } + OSDisableScheduler(); + handler(interrupt, context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + } + + OSLoadContext(context); +} + +static asm void ExternalInterruptHandler(register __OSException exception, + register OSContext* context) +{ +#pragma unused(exception) +#ifdef __MWERKS__ // clang-format off + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + stwu r1, -0x8(r1) + b __OSDispatchInterrupt +#endif // clang-format on +} diff --git a/src/static/dolphin/os/OSLink.c b/src/static/dolphin/os/OSLink.c new file mode 100644 index 00000000..3e87e419 --- /dev/null +++ b/src/static/dolphin/os/OSLink.c @@ -0,0 +1,386 @@ +#include +#include +#include + +#include "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 ENQUEUE_INFO(queue, info, link) \ + do { \ + OSModuleInfo* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (info); \ + else \ + __prev->link.next = (info); \ + (info)->link.prev = __prev; \ + (info)->link.next = NULL; \ + (queue)->tail = (info); \ + } while (0) + +#define DEQUEUE_INFO(info, queue, link) \ + do { \ + OSModuleInfo* __next; \ + OSModuleInfo* __prev; \ + \ + __next = (info)->link.next; \ + __prev = (info)->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 AT_ADDRESS(OS_BASE_CACHED | 0x30C8); + +#pragma dont_inline on + +__declspec(weak) void OSNotifyLink(void) {} +__declspec(weak) void OSNotifyUnlink() {} + +#pragma dont_inline reset + +void OSSetStringTable(const void* string_table) { + __OSStringTable = string_table; +} + +static BOOL Relocate(OSModuleHeader* newModule, OSModuleHeader* module) { + u32 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_REL24: + x = offset + rel->addend - (u32)p; + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + 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; +} +BOOL OSLink(OSModuleInfo* newModule, void* bss) { + u32 i; + OSSectionInfo* si; + OSModuleHeader* moduleHeader; + OSModuleInfo* moduleInfo; + OSImportInfo* imp; + + moduleHeader = (OSModuleHeader*)newModule; + + if (newModule->version > 2 || (newModule->version >= 2 && + ((moduleHeader->align && (u32)newModule % moduleHeader->align != 0) || + (moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)))) + { + return FALSE; + } + + ENQUEUE_INFO(&__OSModuleInfoList, newModule, link); + memset(bss, 0, moduleHeader->bssSize); + newModule->sectionInfoOffset += (u32)moduleHeader; + moduleHeader->relOffset += (u32)moduleHeader; + moduleHeader->impOffset += (u32)moduleHeader; + + for (i = 0; i < newModule->numSections; i++) { + si = &OSGetSectionInfo(newModule)[i]; + if (si->offset != 0) { + si->offset += (u32)moduleHeader; + } else if (si->size != 0) { + si->offset = (u32)bss; + bss = (void*)((u32)bss + si->size); + } + } + + 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); + } + } + + OSNotifyLink(); + return TRUE; +} + +static BOOL Undo(OSModuleHeader* newModule, OSModuleHeader* module) { + u32 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_REL24: + if (module->unresolvedSection != SHN_UNDEF) { + x = (u32)module->unresolved - (u32)p; + } + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + 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; + + moduleHeader = (OSModuleHeader*)oldModule; + + DEQUEUE_INFO(oldModule, &__OSModuleInfoList, link); + + for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) { + Undo(moduleHeader, (OSModuleHeader*)moduleInfo); + } + + OSNotifyUnlink(); + return TRUE; +} + +void __OSModuleInit(void) { + __OSModuleList.tail = NULL; + __OSModuleList.head = NULL; + __OSStringTable = NULL; +} diff --git a/src/static/dolphin/os/OSMemory.c b/src/static/dolphin/os/OSMemory.c index fe0af603..7b7e6828 100644 --- a/src/static/dolphin/os/OSMemory.c +++ b/src/static/dolphin/os/OSMemory.c @@ -1,11 +1,17 @@ +#include #include "dolphin/os/OSMemory.h" #include "dolphin/os/OSError.h" #include "dolphin/os/OSInterrupt.h" #include "dolphin/hw_regs.h" +#include "dolphin/os/OSReset.h" + +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) u32 OSGetConsoleSimulatedMemSize(void){ return(SIM_MEM); } + static BOOL OnReset(BOOL final){ if (final) { __MEMRegs[8] = 0xff; @@ -13,6 +19,7 @@ static BOOL OnReset(BOOL final){ } return TRUE; } + static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext* ctx){ u32 cause = __MEMRegs[0xf]; u32 addr = (((u32) __MEMRegs[0x12] & 0x3ff) << 16) | __MEMRegs[0x11]; @@ -22,5 +29,185 @@ static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext* ctx){ __OSErrorTable[OS_ERROR_PROTECTION](OS_ERROR_PROTECTION, ctx, cause, addr); return; } - __OSUnhandledException(OS_ERROR_PROTECTION, ctx, cause, addr); -} \ No newline at end of file + + __OSUnhandledException(OS_ERROR_PROTECTION, ctx, cause, addr); +} + +#define OS_PROTECT_CONTROL_NONE 0x00 +#define OS_PROTECT_CONTROL_READ 0x01 +#define OS_PROTECT_CONTROL_WRITE 0x02 +#define OS_PROTECT_CONTROL_RDWR \ + (OS_PROTECT_CONTROL_READ | OS_PROTECT_CONTROL_WRITE) + +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_INTERRUPT_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_INTERRUPT_MEM_0 + chan)); + } + + OSRestoreInterrupts(enabled); +} + +static asm void Config24MB(void) +{ +#ifdef __MWERKS__ // 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 +#endif // clang-format on +} + +static asm void Config48MB(void) +{ +#ifdef __MWERKS__ // 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 +#endif // clang-format on +} + +static asm void RealMode(register u32 config) +{ +#ifdef __MWERKS__ // clang-format off + nofralloc + + clrlwi config, config, 2 + mtspr 0x1a, config + mfmsr config + rlwinm config, config, 0, 0x1c, 0x19 + mtspr 0x1b, config + rfi +#endif // clang-format on +} + +static OSResetFunctionInfo ResetFunctionInfo = { + OnReset, + 0x7F, +}; + +u32 OSGetPhysicalMemSize() { return __OSPhysicalMemSize; } + +void __OSInitMemoryProtection() +{ + char padding[0x28]; // TODO: wtf is this? + u32 simulatedSize; + BOOL enabled; + simulatedSize = OSGetConsoleSimulatedMemSize(); + enabled = OSDisableInterrupts(); + + if (simulatedSize <= 0x1800000) { + RealMode((u32)&Config24MB); + } else if (simulatedSize <= 0x3000000) { + RealMode((u32)&Config48MB); + } + + __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_INTERRUPT_MEM_0, MEMIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_1, MEMIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_2, MEMIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_3, MEMIntrruptHandler); + __OSSetInterruptHandler(__OS_INTERRUPT_MEM_ADDRESS, MEMIntrruptHandler); + OSRegisterResetFunction(&ResetFunctionInfo); + + simulatedSize = OSGetConsoleSimulatedMemSize(); + if (simulatedSize < OSGetPhysicalMemSize() && simulatedSize == 0x1800000) { + __MEMRegs[20] = 2; + } + + __OSUnmaskInterrupts(OS_INTERRUPTMASK_MEM_ADDRESS); + OSRestoreInterrupts(enabled); +} diff --git a/src/static/dolphin/os/OSMessage.c b/src/static/dolphin/os/OSMessage.c new file mode 100644 index 00000000..71bec9f6 --- /dev/null +++ b/src/static/dolphin/os/OSMessage.c @@ -0,0 +1,74 @@ +#include +#include + +void OSInitMessageQueue(struct OSMessageQueue* mq, OSMessage* msgArray, + int msgCount) +{ + OSInitThreadQueue(&mq->queueSend); + OSInitThreadQueue(&mq->queueReceive); + mq->msgArray = msgArray; + mq->msgCount = msgCount; + mq->firstIndex = 0; + mq->usedCount = 0; +} + +int OSSendMessage(struct OSMessageQueue* mq, OSMessage msg, int flags) +{ + int enabled; + long lastIndex; + + enabled = OSDisableInterrupts(); + while (mq->msgCount <= mq->usedCount) { + if (!(flags & 1)) { + OSRestoreInterrupts(enabled); + return 0; + } + OSSleepThread(&mq->queueSend); + } + lastIndex = (mq->firstIndex + mq->usedCount) % mq->msgCount; + ((u32*)mq->msgArray)[lastIndex] = (u32)msg; + mq->usedCount++; + OSWakeupThread(&mq->queueReceive); + OSRestoreInterrupts(enabled); + return 1; +} + +int OSReceiveMessage(struct OSMessageQueue* mq, OSMessage* msg, int flags) +{ + int enabled = OSDisableInterrupts(); + + while (mq->usedCount == 0) { + if (!(flags & 1)) { + OSRestoreInterrupts(enabled); + return 0; + } + OSSleepThread(&mq->queueReceive); + } + if (msg != NULL) { + *(u32*)msg = ((u32*)mq->msgArray)[mq->firstIndex]; + } + + mq->firstIndex = (mq->firstIndex + 1) % mq->msgCount; + mq->usedCount--; + OSWakeupThread(&mq->queueSend); + OSRestoreInterrupts(enabled); + return 1; +} + +int OSJamMessage(struct OSMessageQueue * mq, OSMessage msg, int flags) { + int enabled = OSDisableInterrupts(); + + while(mq->msgCount <= mq->usedCount) { + if(!(flags & 1)) { + OSRestoreInterrupts(enabled); + return 0; + } + OSSleepThread(&mq->queueSend); + } + mq->firstIndex = (mq->firstIndex + mq->msgCount - 1) % mq->msgCount; + ((u32*)mq->msgArray)[mq->firstIndex] = (u32)msg; + mq->usedCount++; + OSWakeupThread(&mq->queueReceive); + OSRestoreInterrupts(enabled); + return 1; +} diff --git a/src/static/dolphin/os/OSMutex.c b/src/static/dolphin/os/OSMutex.c new file mode 100644 index 00000000..c3c8e787 --- /dev/null +++ b/src/static/dolphin/os/OSMutex.c @@ -0,0 +1,255 @@ +#include +#include +#include + +#include "os/__os.h" + +#define ENQUEUE_MUTEX(mutex, queue, link) \ + do { \ + struct OSMutex* __prev = (queue)->tail; \ + if (__prev == NULL) { \ + (queue)->head = (mutex); \ + } else { \ + __prev->link.next = (mutex); \ + } \ + (mutex)->link.prev = __prev; \ + (mutex)->link.next = 0; \ + (queue)->tail = (mutex); \ + } while (0); + +#define DEQUEUE_MUTEX(mutex, queue, link) \ + do { \ + struct OSMutex* __next = (mutex)->link.next; \ + struct OSMutex* __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); + +#define DEQUEUE_HEAD(mutex, queue, link) \ + do { \ + struct OSMutex* __next = mutex->link.next; \ + if (__next == NULL) { \ + (queue)->tail = 0; \ + } else { \ + __next->link.prev = 0; \ + } \ + (queue)->head = __next; \ + } while (0); + +void OSInitMutex(struct OSMutex* mutex) +{ + OSInitThreadQueue(&mutex->queue); + mutex->thread = 0; + mutex->count = 0; +} + +void OSLockMutex(struct OSMutex* mutex) +{ + int enabled = OSDisableInterrupts(); + struct OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(0x8C, currentThread, + "OSLockMutex(): current thread does not exist."); + ASSERTMSGLINE(0x8E, currentThread->state == 2, + "OSLockMutex(): current thread is not running."); + + while (1) { + struct OSThread* ownerThread = mutex->thread; + if (ownerThread == 0) { + mutex->thread = currentThread; + mutex->count++; + ENQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link); + break; + } else if (ownerThread == currentThread) { + mutex->count++; + break; + } else { + currentThread->mutex = mutex; + __OSPromoteThread(mutex->thread, currentThread->priority); + OSSleepThread(&mutex->queue); + currentThread->mutex = NULL; + } + } + OSRestoreInterrupts(enabled); +} + +void OSUnlockMutex(struct OSMutex* mutex) +{ + int enabled = OSDisableInterrupts(); + struct OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(0xBD, currentThread, + "OSUnlockMutex(): current thread does not exist."); + ASSERTMSGLINE(0xBF, currentThread->state == 2, + "OSUnlockMutex(): current thread is not running."); + ASSERTMSG2LINE( + 0xC2, mutex->thread == currentThread, + "OSUnlockMutex(): current thread %p is not the owner of mutex %p.", + currentThread, mutex); + + if (mutex->thread == currentThread) { + if (!--mutex->count) { + DEQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link); + mutex->thread = 0; + + if (currentThread->priority < currentThread->base) { + currentThread->priority + = __OSGetEffectivePriority(currentThread); + } + OSWakeupThread(&mutex->queue); + } + } + OSRestoreInterrupts(enabled); +} + +void __OSUnlockAllMutex(struct OSThread* thread) +{ + struct OSMutex* mutex; + + while (thread->queueMutex.head) { + mutex = thread->queueMutex.head; + DEQUEUE_HEAD(mutex, &thread->queueMutex, link); + ASSERTLINE(0xE5, mutex->thread == thread); + mutex->count = 0; + mutex->thread = 0; + OSWakeupThread(&mutex->queue); + } +} + +int OSTryLockMutex(struct OSMutex* mutex) +{ + int enabled = OSDisableInterrupts(); + struct OSThread* currentThread = OSGetCurrentThread(); + int locked; + + ASSERTMSGLINE(0xFF, currentThread, + "OSTryLockMutex(): current thread does not exist."); + ASSERTMSGLINE(0x101, currentThread->state == 2, + "OSTryLockMutex(): current thread is not running."); + + if (!mutex->thread) { + mutex->thread = currentThread; + mutex->count++; + ENQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link); + locked = 1; + } else if (mutex->thread == currentThread) { + mutex->count++; + locked = 1; + } else { + locked = 0; + } + OSRestoreInterrupts(enabled); + return locked; +} + +void OSInitCond(struct OSCond* cond) { OSInitThreadQueue(&cond->queue); } + +void OSWaitCond(struct OSCond* cond, struct OSMutex* mutex) +{ + int enabled = OSDisableInterrupts(); + struct OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(0x139, currentThread, + "OSWaitCond(): current thread does not exist."); + ASSERTMSGLINE(0x13B, currentThread->state == 2, + "OSWaitCond(): current thread is not running."); + ASSERTMSG2LINE( + 0x13E, mutex->thread == currentThread, + "OSWaitCond(): current thread %p is not the owner of mutex %p.", + currentThread, mutex); + + if (mutex->thread == currentThread) { + long count = mutex->count; + mutex->count = 0; + DEQUEUE_MUTEX(mutex, ¤tThread->queueMutex, link); + mutex->thread = 0; + if (currentThread->priority < currentThread->base) { + currentThread->priority = __OSGetEffectivePriority(currentThread); + } + OSDisableScheduler(); + OSWakeupThread(&mutex->queue); + OSEnableScheduler(); + OSSleepThread(&cond->queue); + OSLockMutex(mutex); + mutex->count = count; + } + OSRestoreInterrupts(enabled); +} + +void OSSignalCond(struct OSCond* cond) { OSWakeupThread(&cond->queue); } + +int __OSCheckMutex(struct OSMutex * mutex) { + struct OSThread * thread; + struct OSThreadQueue * queue; + long priority; + + priority = 0; + queue = &mutex->queue; + + if (queue->head != NULL && queue->head->link.prev != NULL) { + return 0; + } + if (queue->tail != NULL && queue->tail->link.next != NULL) { + return 0; + } + thread = queue->head; + while(thread) { + if (thread->link.next != NULL && (thread != thread->link.next->link.prev)) { + return 0; + } + if (thread->link.prev != NULL && (thread != thread->link.prev->link.next)) { + return 0; + } + if (thread->state != 4) { + return 0; + } + if (thread->priority < priority) { + return 0; + } + priority = thread->priority; + thread = thread->link.next; + } + if (mutex->thread) { + if (mutex->count <= 0) { + return 0; + } + } else if (mutex->count != 0) { + return 0; + } + return 1; +} + +int __OSCheckDeadLock(struct OSThread * thread) { + struct OSMutex * mutex = thread->mutex; + + while(mutex && mutex->thread) { + if (mutex->thread == thread) { + return 1; + } + mutex = mutex->thread->mutex; + } + return 0; +} + +int __OSCheckMutexes(struct OSThread * thread) { + struct OSMutex * mutex = thread->queueMutex.head; + + while(mutex) { + if (mutex->thread != thread) { + return 0; + } + if (__OSCheckMutex(mutex) == 0) { + return 0; + } + mutex = mutex->link.next; + } + return 1; +} diff --git a/src/static/dolphin/os/OSReboot.c b/src/static/dolphin/os/OSReboot.c new file mode 100644 index 00000000..cd5b3e0b --- /dev/null +++ b/src/static/dolphin/os/OSReboot.c @@ -0,0 +1,127 @@ +#include +#include +#include "dvd/__dvd.h" +#include "os/__os.h" + +static void* SaveStart = NULL; +static void* SaveEnd = NULL; +static volatile BOOL Prepared; + +extern u32 OS_RESET_CODE AT_ADDRESS(0x800030F0); +// unknown function, set to true by __OSReboot +extern u8 OS_REBOOT_BOOL AT_ADDRESS(0x800030E2); +extern u32 UNK_817FFFF8 AT_ADDRESS(0x817FFFF8); +extern u32 UNK_817FFFFC AT_ADDRESS(0x817FFFFC); + +#define OS_BOOTROM_ADDR ((void*)0x81300000) + +typedef struct _ApploaderHeader { + /* 0x00 */ char date[16]; + /* 0x10 */ u32 entry; + /* 0x14 */ u32 size; + /* 0x18 */ u32 rebootSize; + /* 0x1C */ u32 reserved2; +} ApploaderHeader; // Size: 0x20 + +static ApploaderHeader Header __attribute__((aligned(32))); + +static asm void Run(register void (*addr)()) +{ +#ifdef __MWERKS__ // clang-format off + fralloc + bl OSDisableInterrupts + bl ICFlashInvalidate + sync + isync + mtlr addr + blr + frfree + blr +#endif // clang-format on +} + +inline void ReadApploader(DVDCommandBlock* dvdCmd, void* addr, u32 offset, + u32 numBytes) +{ + /* Not sure if this inline is correct - might need to call other inlines */ + while (Prepared == FALSE) { } + DVDReadAbsAsyncForBS(dvdCmd, addr, numBytes, offset + 0x2440, NULL); + + while (TRUE) { + switch (dvdCmd->state) { + case 0: + break; + case 1: + default: + continue; + case -1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + __OSDoHotReset(UNK_817FFFFC); + continue; + } + break; + } +} + +static void Callback(s32 result, struct DVDCommandBlock* block) +{ + Prepared = TRUE; +} + +void __OSReboot(u32 resetCode, u32 bootDol) +{ + OSContext exceptionContext; + DVDCommandBlock dvdCmd; + DVDCommandBlock dvdCmd2; + u32 numBytes; + u32 offset; + + OSDisableInterrupts(); + + UNK_817FFFFC = 0; + UNK_817FFFF8 = 0; + OS_REBOOT_BOOL = TRUE; + BOOT_REGION_START = SaveStart; + BOOT_REGION_END = SaveEnd; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + DVDInit(); + DVDSetAutoInvalidation(TRUE); + + __DVDPrepareResetAsync(Callback); + + if (!DVDCheckDisk()) { + __OSDoHotReset(UNK_817FFFFC); + } + + __OSMaskInterrupts(0xffffffe0); + __OSUnmaskInterrupts(0x400); + + OSEnableInterrupts(); + + offset = 0; + numBytes = 32; + ReadApploader(&dvdCmd, (void*)&Header, offset, numBytes); + + offset = Header.size + 0x20; + numBytes = OSRoundUp32B(Header.rebootSize); + ReadApploader(&dvdCmd2, OS_BOOTROM_ADDR, offset, numBytes); + + ICInvalidateRange(OS_BOOTROM_ADDR, numBytes); + Run(OS_BOOTROM_ADDR); +} + +void OSGetSaveRegion(void** start, void** end) +{ + *start = SaveStart; + *end = SaveEnd; +} diff --git a/src/static/dolphin/os/OSReset.c b/src/static/dolphin/os/OSReset.c new file mode 100644 index 00000000..3d980939 --- /dev/null +++ b/src/static/dolphin/os/OSReset.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include + +#include "os/__os.h" + +// These macros are copied from OSThread.c. Or ARE they the same +// macros? They dont seem to be in the SDK headers. +#define ENQUEUE_INFO(info, queue) \ + do { \ + struct OSResetFunctionInfo* __prev = (queue)->tail; \ + if (__prev == 0) { \ + (queue)->head = (info); \ + } else { \ + __prev->next = (info); \ + } \ + (info)->prev = __prev; \ + (info)->next = 0; \ + (queue)->tail = (info); \ + } while (0); + +#define DEQUEUE_INFO(info, queue) \ + do { \ + struct OSResetFunctionInfo* __next = (info)->next; \ + struct OSResetFunctionInfo* __prev = (info)->prev; \ + if (__next == 0) { \ + (queue)->tail = __prev; \ + } else { \ + __next->prev = __prev; \ + } \ + if (__prev == 0) { \ + (queue)->head = __next; \ + } else { \ + __prev->next = __next; \ + } \ + } while (0); + +#define ENQUEUE_INFO_PRIO(info, queue) \ + do { \ + struct OSResetFunctionInfo* __prev; \ + struct OSResetFunctionInfo* __next; \ + for (__next = (queue)->head; \ + __next && (__next->priority <= (info)->priority); \ + __next = __next->next) \ + ; \ + \ + if (__next == 0) { \ + ENQUEUE_INFO(info, queue); \ + } else { \ + (info)->next = __next; \ + __prev = __next->prev; \ + __next->prev = (info); \ + (info)->prev = __prev; \ + if (__prev == 0) { \ + (queue)->head = (info); \ + } else { \ + __prev->next = (info); \ + } \ + } \ + } while (0); + +static struct OSResetFunctionQueue ResetFunctionQueue; + +static int CallResetFunctions(int final); +static asm void Reset(unsigned long resetCode); + +void OSRegisterResetFunction(struct OSResetFunctionInfo* info) +{ + ENQUEUE_INFO_PRIO(info, &ResetFunctionQueue); +} + +void OSUnregisterResetFunction(struct OSResetFunctionInfo* info) +{ + DEQUEUE_INFO(info, &ResetFunctionQueue); +} + +static int CallResetFunctions(int final) +{ + struct OSResetFunctionInfo* info; + int err = 0; + + for (info = ResetFunctionQueue.head; info; info = info->next) { + err |= !info->func(final); + } + err |= !__OSSyncSram(); + if (err) { + return 0; + } + return 1; +} + +static asm void Reset(unsigned long resetCode) +{ +#ifdef __MWERKS__ // clang-format off + nofralloc + b L_000001BC +L_000001A0: + mfspr r8, HID0 + ori r8, r8, 0x8 + mtspr HID0, r8 + isync + sync + nop + b L_000001C0 +L_000001BC: + b L_000001DC +L_000001C0: + mftb r5, 268 +L_000001C4: + mftb r6, 268 + subf r7, r5, r6 + cmplwi r7, 0x1124 + blt L_000001C4 + nop + b L_000001E0 +L_000001DC: + b L_000001FC +L_000001E0: + lis r8, 0xcc00 + ori r8, r8, 0x3000 + li r4, 0x3 + stw r4, 0x24(r8) + stw r3, 0x24(r8) + nop + b L_00000200 +L_000001FC: + b L_00000208 +L_00000200: + nop + b L_00000200 +L_00000208: + b L_000001A0 +#endif // clang-format on +} + +void __OSDoHotReset(s32 arg0) +{ + OSDisableInterrupts(); + __VIRegs[1] = 0; + ICFlashInvalidate(); + Reset(arg0 * 8); +} + +inline BOOL __OSCallResetFunctions(BOOL arg0) +{ + OSResetFunctionInfo* iter; + s32 retCode = 0; + s32 temp; + + for (iter = ResetFunctionQueue.head; iter != NULL;) { + temp = !iter->func(arg0); + iter = iter->next; + retCode |= temp; + } + retCode |= !__OSSyncSram(); + if (retCode) { + return 0; + } + return 1; +} + +inline static void KillThreads(void) +{ + OSThread* thread; + OSThread* next; + + for (thread = __OSActiveThreadQueue.head; thread; thread = next) { + next = thread->linkActive.next; + switch (thread->state) { + case 1: + case 4: + OSCancelThread(thread); + continue; + default: + continue; + } + } +} + +extern u8 OS_REBOOT_BOOL AT_ADDRESS(0x800030E2); + +void OSResetSystem(int reset, unsigned long resetCode, int forceMenu) +{ + char trash[0x10]; // Either more inlines or more local vars, idk + s32 padThing; + + OSDisableScheduler(); + __OSStopAudioSystem(); + + if (reset == OS_RESET_SHUTDOWN) + padThing = __PADDisableRecalibration(1); + + do { + } while (CallResetFunctions(0) == 0); + + if ((reset == OS_RESET_HOTRESET && (forceMenu != 0))) { + __OSLockSram()->flags |= 0x40; + __OSUnlockSram(1); + do { + } while (__OSSyncSram() == 0); + } + + OSDisableInterrupts(); + __OSCallResetFunctions(TRUE); + + LCDisable(); + + if (reset == OS_RESET_HOTRESET) { + OSDisableInterrupts(); + __VIRegs[1] = 0; + ICFlashInvalidate(); + Reset(resetCode * 8); + } else if (reset == OS_RESET_RESTART) { + KillThreads(); + OSEnableScheduler(); + __OSReboot(resetCode, forceMenu); + } + + KillThreads(); + + // TODO: maybe use AT_ADDRESS vars or macros from other files here? + 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(&OS_REBOOT_BOOL, 0, 1); + __PADDisableRecalibration(padThing); +} + +u32 OSGetResetCode(void) +{ + if (OS_REBOOT_BOOL != 0) + return 0x80000000; + + return ((__PIRegs[9] & ~7) >> 3); +} diff --git a/src/static/dolphin/os/OSResetSW.c b/src/static/dolphin/os/OSResetSW.c new file mode 100644 index 00000000..48b5a54d --- /dev/null +++ b/src/static/dolphin/os/OSResetSW.c @@ -0,0 +1,92 @@ +#include +#include +#include + +#include "os/__os.h" + +u8 GameChoice AT_ADDRESS(OS_BASE_CACHED | 0x30E3); + +static OSResetCallback ResetCallback; + +static BOOL Down; + +static BOOL LastState; + +static OSTime HoldUp; +static OSTime HoldDown; + +void __OSResetSWInterruptHandler(__OSInterrupt exception, + struct 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 & 0x3F) { + OSTime fire = (GameChoice & 0x3F) * 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/static/dolphin/os/OSStopwatch.c b/src/static/dolphin/os/OSStopwatch.c new file mode 100644 index 00000000..39973077 --- /dev/null +++ b/src/static/dolphin/os/OSStopwatch.c @@ -0,0 +1,48 @@ +#include +#include + +void OSInitStopwatch(struct OSStopwatch* sw, char* name) +{ + sw->name = name; + sw->total = 0; + sw->hits = 0; + sw->min = 0x00000000FFFFFFFF; + sw->max = 0; +} + +void OSStartStopwatch(struct OSStopwatch* sw) +{ + sw->running = 1; + sw->last = OSGetTime(); +} + +void OSStopStopwatch(struct OSStopwatch* sw) +{ + long long interval; + + if (sw->running != 0) { + interval = OSGetTime() - sw->last; + sw->total += interval; + sw->running = 0; + sw->hits++; + if (sw->max < interval) { + sw->max = interval; + } + if (interval < sw->min) { + sw->min = interval; + } + } +} + +long long OSCheckStopwatch(struct OSStopwatch* sw) +{ + long long currTotal; + + currTotal = sw->total; + if (sw->running != 0) { + currTotal += OSGetTime() - sw->last; + } + return currTotal; +} + +void OSResetStopwatch(struct OSStopwatch* sw) { OSInitStopwatch(sw, sw->name); } diff --git a/src/static/dolphin/os/OSSync.c b/src/static/dolphin/os/OSSync.c new file mode 100644 index 00000000..4f2ad354 --- /dev/null +++ b/src/static/dolphin/os/OSSync.c @@ -0,0 +1,35 @@ +#include +#include + +#include "../src/static/dolphin/os/__os.h" + +void __OSSystemCallVectorStart(); +void __OSSystemCallVectorEnd(); + +static asm void SystemCallVector(void) +{ +#ifdef __MWERKS__ // clang-format off +entry __OSSystemCallVectorStart + nofralloc + mfspr r9, HID0 + ori r10, r9, 0x8 + mtspr HID0, r10 + isync + sync + mtspr HID0, r9 + rfi +entry __OSSystemCallVectorEnd + nop +#endif // clang-format on +} + +void __OSInitSystemCall(void) +{ + void* addr = (void*)OSPhysicalToCached(0xC00); + + memcpy(addr, __OSSystemCallVectorStart, + (u32)&__OSSystemCallVectorEnd - (u32)&__OSSystemCallVectorStart); + DCFlushRangeNoSync(addr, 0x100); + __sync(); + ICInvalidateRange(addr, 0x100); +} diff --git a/src/static/dolphin/os/OSThread.c b/src/static/dolphin/os/OSThread.c new file mode 100644 index 00000000..b6c9e01d --- /dev/null +++ b/src/static/dolphin/os/OSThread.c @@ -0,0 +1,806 @@ +#include +#include +#include +#include + +#include "os/__os.h" + +#define IsSuspended(suspend) (suspend > 0) + +#define ENQUEUE_THREAD(thread, queue, link) \ + do { \ + OSThread* __prev = (queue)->tail; \ + if (__prev == NULL) { \ + (queue)->head = (thread); \ + } else { \ + __prev->link.next = (thread); \ + } \ + (thread)->link.prev = __prev; \ + (thread)->link.next = 0; \ + (queue)->tail = (thread); \ + } while (0); + +#define DEQUEUE_THREAD(thread, queue, link) \ + do { \ + OSThread* __next = (thread)->link.next; \ + OSThread* __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 ENQUEUE_THREAD_PRIO(thread, queue, link) \ + do { \ + OSThread* __prev; \ + OSThread* __next; \ + for (__next = (queue)->head; \ + __next && (__next->priority <= (thread)->priority); \ + __next = __next->link.next) \ + ; \ + \ + if (__next == NULL) { \ + ENQUEUE_THREAD(thread, queue, 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 DEQUEUE_HEAD(thread, queue, link) \ + do { \ + OSThread* __next = thread->link.next; \ + if (__next == NULL) { \ + (queue)->tail = 0; \ + } else { \ + __next->link.prev = 0; \ + } \ + (queue)->head = __next; \ + } while (0); + +// which header should these go in? +extern unsigned char _stack_end[]; +extern char _stack_addr[]; + +// .bss +static OSThreadQueue RunQueue[32]; +static OSThread IdleThread; +static OSThread DefaultThread; +static struct OSContext IdleContext; +static volatile unsigned long RunQueueBits; +static volatile int RunQueueHint; +static long Reschedule; + +#define ALIGN4(val) (((val) + 0x3) & ~0x3) +#define ALIGN8(val) (((val) + 0x7) & ~0x7) + +// functions +static void OSInitMutexQueue(struct OSMutexQueue* queue); +static void __OSSwitchThread(OSThread* nextThread); +static int __OSIsThreadActive(OSThread* thread); +static void SetRun(OSThread* thread); +static void UnsetRun(OSThread* thread); +static OSThread* SetEffectivePriority(OSThread* thread, long priority); +static void UpdatePriority(OSThread* thread); +static OSThread* SelectThread(int yield); + +void __OSThreadInit() +{ + OSThread* thread = &DefaultThread; + int prio; + + thread->state = 2; + thread->attr = 1; + thread->priority = thread->base = 0x10; + thread->suspend = 0; + thread->val = (void*)-1; // wut + thread->mutex = 0; + + OSInitThreadQueue(&thread->queueJoin); + + thread->queueMutex.head = thread->queueMutex.tail + = 0; // it got inlined? cant reproduce the inline... + + ASSERTLINE(282, PPCMfmsr() & MSR_FP); + + __gUnkThread1 = thread; + OSClearContext(&thread->context); + OSSetCurrentContext(&thread->context); + thread->stackBase = (unsigned char*)&_stack_addr; + thread->stackEnd = (unsigned long*)&_stack_end; + *(u32*)thread->stackEnd = 0xDEADBABE; + __gCurrentThread = thread; + RunQueueBits = 0; + RunQueueHint = 0; + + for (prio = 0; prio <= 31; prio++) { + OSInitThreadQueue(&RunQueue[prio]); + } + OSInitThreadQueue(&__OSActiveThreadQueue); + + ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + + OSClearContext(&IdleContext); + Reschedule = 0; +} + +void OSInitThreadQueue(OSThreadQueue* queue) { queue->head = queue->tail = 0; } + +OSThread* OSGetCurrentThread() { return __gCurrentThread; } + +static void __OSSwitchThread(OSThread* nextThread) +{ + __gCurrentThread = nextThread; + OSSetCurrentContext(&nextThread->context); + OSLoadContext(&nextThread->context); +} + +int OSIsThreadTerminated(OSThread* thread) +{ + return (thread->state == 8 || thread->state == 0) ? 1 : 0; +} + +static int __OSIsThreadActive(OSThread* thread) +{ + OSThread* active; + + if (thread->state == 0) { + return 0; + } + + for (active = __OSActiveThreadQueue.head; active; + active = active->linkActive.next) { + if (thread == active) { + return 1; + } + } + return 0; +} + +s32 OSDisableScheduler(void) +{ + register int enabled; + long count; + + enabled = OSDisableInterrupts(); + count = Reschedule; + Reschedule = count + 1; + OSRestoreInterrupts(enabled); + return count; +} + +s32 OSEnableScheduler(void) +{ + register int enabled; + long count; + + enabled = OSDisableInterrupts(); + count = Reschedule; + Reschedule = count - 1; + OSRestoreInterrupts(enabled); + return count; +} + +static void SetRun(OSThread* thread) +{ + ASSERTLINE(469, !IsSuspended(thread->suspend)); + ASSERTLINE(470, thread->state == OS_THREAD_STATE_READY); + + ASSERTLINE(472, OS_PRIORITY_MIN <= thread->priority + && thread->priority <= OS_PRIORITY_MAX); + + thread->queue = &RunQueue[thread->priority]; + + ENQUEUE_THREAD(thread, thread->queue, link); + + RunQueueBits |= 1 << (0x1F - thread->priority); + RunQueueHint = 1; +} + +static void UnsetRun(OSThread* thread) +{ + OSThreadQueue* queue; + + ASSERTLINE(0x1ED, thread->state == OS_THREAD_STATE_READY); + + ASSERTLINE(0x1EF, OS_PRIORITY_MIN <= thread->priority + && thread->priority <= OS_PRIORITY_MAX); + ASSERTLINE(0x1F0, thread->queue == &RunQueue[thread->priority]); + + queue = thread->queue; + + DEQUEUE_THREAD(thread, queue, link); + + if (!queue->head) { + RunQueueBits &= ~(1 << (0x1F - thread->priority)); + } + thread->queue = NULL; +} + +long __OSGetEffectivePriority(OSThread* thread) +{ + long priority = thread->base; + struct OSMutex* mutex; + + for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) { + OSThread* blocked = mutex->queue.head; + if (blocked && blocked->priority < priority) { + priority = blocked->priority; + } + } + return priority; +} + +static OSThread* SetEffectivePriority(OSThread* thread, long priority) +{ + ASSERTLINE(547, !IsSuspended(thread->suspend)); + + switch (thread->state) { + case 1: + UnsetRun(thread); + thread->priority = priority; + SetRun(thread); + break; + case 4: + DEQUEUE_THREAD(thread, thread->queue, link); + thread->priority = priority; + + ENQUEUE_THREAD_PRIO(thread, thread->queue, link); + + if (thread->mutex) { + ASSERTLINE(0x232, thread->mutex->thread); + return thread->mutex->thread; + } + break; + case 2: + RunQueueHint = 1; + thread->priority = priority; + break; + } + return 0; +} + +static void UpdatePriority(OSThread* thread) +{ + long priority; + + while (1) { + if (thread->suspend > 0) { + break; + } + priority = __OSGetEffectivePriority(thread); + if (thread->priority == priority) { + break; + } + thread = SetEffectivePriority(thread, priority); + if (thread == 0) { + break; + } + } +} + +void __OSPromoteThread(OSThread* thread, long priority) +{ + while (1) { + if (thread->suspend > 0 || thread->priority <= priority) { + break; + } + thread = SetEffectivePriority(thread, priority); + if (thread == 0) { + break; + } + } +} + +static OSThread* SelectThread(int yield) +{ + struct OSContext* currentContext; + OSThread* currentThread; + OSThread* nextThread; + long priority; + OSThreadQueue* queue; + + if (Reschedule > 0) { + return NULL; + } + + currentContext = OSGetCurrentContext(); + currentThread = OSGetCurrentThread(); + + if (currentContext != ¤tThread->context) { + return NULL; + } + + if (currentThread) { + if (currentThread->state == 2) { + if (yield == 0) { + priority = __cntlzw(RunQueueBits); + if (currentThread->priority <= priority) + return NULL; + } + currentThread->state = 1; + SetRun(currentThread); + } + if (!(currentThread->context.state & 2) + && (OSSaveContext(¤tThread->context) != 0)) { + return NULL; + } + } + + __gCurrentThread = 0; + + if (RunQueueBits == 0) { + OSSetCurrentContext(&IdleContext); + do { + OSEnableInterrupts(); + while (RunQueueBits == 0) + ; + OSDisableInterrupts(); + } while (RunQueueBits == 0); + OSClearContext(&IdleContext); + } + + RunQueueHint = 0; + priority = __cntlzw(RunQueueBits); + + ASSERTLINE(0x2C6, + OS_PRIORITY_MIN <= priority && priority <= OS_PRIORITY_MAX); + + queue = &RunQueue[priority]; + nextThread = queue->head; + + DEQUEUE_HEAD(nextThread, queue, link); + + ASSERTLINE(0x2C9, nextThread->priority == priority); + + if (!queue->head) { + RunQueueBits &= ~(1 << (0x1F - priority)); + } + nextThread->queue = 0; + nextThread->state = 2; + __OSSwitchThread(nextThread); + return nextThread; +} + +void __OSReschedule(void) +{ + if (RunQueueHint != 0) { + SelectThread(0); + } +} + +void OSYieldThread(void) +{ + int enabled = OSDisableInterrupts(); + + SelectThread(1); + OSRestoreInterrupts(enabled); +} + +int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param, + void* stack, unsigned long stackSize, long priority, + unsigned short attr) +{ + int enabled; + unsigned long sp; + + ASSERTMSGLINE( + 0x31C, ((priority >= 0) && (priority <= 0x1F)), + "OSCreateThread(): priority out of range (0 <= priority <= 31)."); + + // why check this for an assert just to check it again right after? + if ((priority < 0) || (priority > 0x1F)) { + return 0; + } + + thread->state = 1; + thread->attr = attr & 1U; + thread->base = priority; + thread->priority = priority; + thread->suspend = 1; + thread->val = (void*)-1; + thread->mutex = 0; + OSInitThreadQueue(&thread->queueJoin); + + OSInitThreadQueue((void*)&thread->queueMutex); // why + + sp = (u32)stack; + sp &= ~7; + sp -= 8; + ((u32*)sp)[0] = 0; + ((u32*)sp)[1] = 0; + OSInitContext(&thread->context, (u32)func, sp); + thread->context.lr = (unsigned long)&OSExitThread; + thread->context.gpr[3] = (unsigned long)param; + thread->stackBase = stack; + thread->stackEnd = (void*)((unsigned int)stack - stackSize); + *thread->stackEnd = 0xDEADBABE; + enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(0x33B, __OSIsThreadActive(thread) == 0L, + "OSCreateThread(): thread %p is still active.", thread); + + ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + + OSRestoreInterrupts(enabled); + return 1; +} + +void OSExitThread(void* val) +{ + int enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(0x354, currentThread, + "OSExitThread(): current thread does not exist."); + ASSERTMSGLINE(0x356, currentThread->state == 2, + "OSExitThread(): current thread is not running."); + ASSERTMSGLINE(0x358, __OSIsThreadActive(currentThread) != 0, + "OSExitThread(): current thread is not active."); + + OSClearContext(¤tThread->context); + if (currentThread->attr & 1) { + DEQUEUE_THREAD(currentThread, &__OSActiveThreadQueue, linkActive); + currentThread->state = 0; + } else { + currentThread->state = 8; + currentThread->val = val; + } + __OSUnlockAllMutex(currentThread); + OSWakeupThread(¤tThread->queueJoin); + RunQueueHint = 1; + + if (RunQueueHint != 0) { + SelectThread(0); + } + + OSRestoreInterrupts(enabled); +} + +void OSCancelThread(OSThread* thread) +{ + int enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(0x37E, __OSIsThreadActive(thread) != 0, + "OSExitThread(): thread %p is not active.", thread); + + switch (thread->state) { + case 1: + if (thread->suspend <= 0) { + UnsetRun(thread); + } + break; + case 2: + RunQueueHint = 1; + break; + case 4: + DEQUEUE_THREAD(thread, thread->queue, link); + thread->queue = 0; + if ((thread->suspend <= 0) && (thread->mutex)) { + ASSERTLINE(0x391, thread->mutex->thread); + UpdatePriority(thread->mutex->thread); + } + break; + default: + OSRestoreInterrupts(enabled); + return; + } + OSClearContext(&thread->context); + if (thread->attr & 1) { + DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + thread->state = 0; + } else { + thread->state = 8; + } + __OSUnlockAllMutex(thread); + OSWakeupThread(&thread->queueJoin); + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +int OSJoinThread(OSThread* thread, void** val) +{ + int enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(0x3CA, __OSIsThreadActive(thread) != 0, + "OSJoinThread(): thread %p is not active.", thread); + + if (!(thread->attr & 1) && (thread->state != 8) + && (thread->queueJoin.head == NULL)) { + OSSleepThread(&thread->queueJoin); + if (__OSIsThreadActive(thread) == 0) { + OSRestoreInterrupts(enabled); + return 0; + } + } + if (thread->state == 8) { + if (val) { + *val = thread->val; + } + DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + thread->state = 0; + OSRestoreInterrupts(enabled); + return 1; + } + OSRestoreInterrupts(enabled); + return 0; +} + +void OSDetachThread(OSThread* thread) +{ + int enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(0x3FC, __OSIsThreadActive(thread) != 0, + "OSDetachThread(): thread %p is not active.", thread); + + thread->attr |= 1; + if (thread->state == 8) { + DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive); + thread->state = 0; + } + OSWakeupThread(&thread->queueJoin); + OSRestoreInterrupts(enabled); +} + +long OSResumeThread(OSThread* thread) +{ + int enabled = OSDisableInterrupts(); + long suspendCount; + + ASSERTMSG1LINE(0x419, __OSIsThreadActive(thread) != 0, + "OSResumeThread(): thread %p is not active.", thread); + ASSERTMSG1LINE(0x41B, thread->state != 8, + "OSResumeThread(): thread %p is terminated.", thread); + + suspendCount = thread->suspend--; + if (thread->suspend < 0) { + thread->suspend = 0; + } else if (thread->suspend == 0) { + switch (thread->state) { + case 1: + thread->priority = __OSGetEffectivePriority(thread); + SetRun(thread); + break; + case 4: + ASSERTLINE(0x42A, thread->queue); + DEQUEUE_THREAD(thread, thread->queue, link); + thread->priority = __OSGetEffectivePriority(thread); + ENQUEUE_THREAD_PRIO(thread, thread->queue, link); + if (thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + } + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return suspendCount; +} + +long OSSuspendThread(OSThread* thread) +{ + int enabled = OSDisableInterrupts(); + long suspendCount; + + ASSERTMSG1LINE(0x44C, __OSIsThreadActive(thread) != 0, + "OSSuspendThread(): thread %p is not active.", thread); + ASSERTMSG1LINE(0x44E, thread->state != 8, + "OSSuspendThread(): thread %p is terminated.", thread); + + suspendCount = thread->suspend++; + if (suspendCount == 0) { + switch (thread->state) { + case 2: + RunQueueHint = 1; + thread->state = 1; + break; + case 1: + UnsetRun(thread); + break; + case 4: + DEQUEUE_THREAD(thread, thread->queue, link); + thread->priority = 0x20; + ENQUEUE_THREAD(thread, thread->queue, link); + if (thread->mutex) { + ASSERTLINE(0x463, thread->mutex->thread); + UpdatePriority(thread->mutex->thread); + } + break; + } + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return suspendCount; +} + +void OSSleepThread(OSThreadQueue* queue) +{ + int enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + ASSERTMSGLINE(0x484, currentThread, + "OSSleepThread(): current thread does not exist."); + ASSERTMSG1LINE(0x486, __OSIsThreadActive(currentThread) != 0, + "OSSleepThread(): current thread %p is not active.", + currentThread); + ASSERTMSG1LINE(0x488, currentThread->state == 2, + "OSSleepThread(): current thread %p is not running.", + currentThread); + ASSERTMSG1LINE(0x48A, currentThread->suspend <= 0, + "OSSleepThread(): current thread %p is suspended.", + currentThread); + + currentThread->state = 4; + currentThread->queue = queue; + ENQUEUE_THREAD_PRIO(currentThread, queue, link); + RunQueueHint = 1; + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +void OSWakeupThread(OSThreadQueue* queue) +{ + int enabled = OSDisableInterrupts(); + + while (queue->head) { + OSThread* thread = queue->head; + + DEQUEUE_HEAD(thread, queue, link); + + ASSERTLINE(0x4A7, __OSIsThreadActive(thread)); + ASSERTLINE(0x4A8, thread->state != OS_THREAD_STATE_MORIBUND); + ASSERTLINE(0x4A9, thread->queue == queue); + thread->state = 1; + if (thread->suspend <= 0) { + SetRun(thread); + } + } + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +int OSSetThreadPriority(struct OSThread * thread, long priority) { + int enabled; + + ASSERTMSGLINE(0x4C3, (priority >= 0) && (priority <= 0x1F), "OSSetThreadPriority(): priority out of range (0 <= priority <= 31)."); + + if ((priority < 0) || (priority > 0x1F)) { + return 0; + } + enabled = OSDisableInterrupts(); + + ASSERTMSG1LINE(0x4CA, __OSIsThreadActive(thread) != 0, "OSSetThreadPriority(): thread %p is not active.", thread); + ASSERTMSG1LINE(0x4CC, thread->state != 8, "OSSetThreadPriority(): thread %p is terminated.", thread); + + if (thread->base != priority) { + thread->base = priority; + UpdatePriority(thread); + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return 1; +} + +long OSGetThreadPriority(OSThread* thread) { return thread->base; } + + +static int CheckThreadQueue(struct OSThreadQueue * queue) { + struct OSThread * thread; + + if ((queue->head != NULL) && (queue->head->link.prev != NULL)) { + return 0; + } + if ((queue->tail != NULL) && (queue->tail->link.next != NULL)) { + return 0; + } + thread = queue->head; + while(thread) { + if ((thread->link.next != NULL) && (thread != thread->link.next->link.prev)) { + return 0; + } + if ((thread->link.prev != NULL) && (thread != thread->link.prev->link.next)) { + return 0; + } + thread = thread->link.next; + } + return 1; +} + +static int IsMember(struct OSThreadQueue * queue, struct OSThread * thread) { + struct OSThread * member = queue->head; + + while(member) { + if (thread == member) { + return 1; + } + member = member->link.next; + } + return 0; +} + +#define ASSERTREPORT(line, cond) \ + if (!(cond)) { \ + OSReport("OSCheckActiveThreads: Failed " #cond " in %d\n", line); \ + OSPanic(__FILE__, line, ""); \ + } + +long OSCheckActiveThreads() { + struct OSThread * thread; + long prio; + long cThread; + int enabled; + + cThread = 0; + enabled = OSDisableInterrupts(); + + for(prio = 0; prio <= 0x1F; prio++) { + if (RunQueueBits & (1 << (0x1F - prio))) { + ASSERTREPORT(0x566, RunQueue[prio].head != NULL && RunQueue[prio].tail != NULL); + } else { + ASSERTREPORT(0x56B, RunQueue[prio].head == NULL && RunQueue[prio].tail == NULL); + } + ASSERTREPORT(0x56D, CheckThreadQueue(&RunQueue[prio])); + } + + ASSERTREPORT(0x572, __OSActiveThreadQueue.head == NULL || __OSActiveThreadQueue.head->linkActive.prev == NULL); + ASSERTREPORT(0x574, __OSActiveThreadQueue.tail == NULL || __OSActiveThreadQueue.tail->linkActive.next == NULL); + + thread = __OSActiveThreadQueue.head; + while(thread) { + cThread++; + ASSERTREPORT(0x57C, thread->linkActive.next == NULL || thread == thread->linkActive.next->linkActive.prev); + ASSERTREPORT(0x57E, thread->linkActive.prev == NULL || thread == thread->linkActive.prev->linkActive.next); + ASSERTREPORT(0x581, *(thread->stackEnd) == OS_THREAD_STACK_MAGIC); + ASSERTREPORT(0x584, OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX+1); + ASSERTREPORT(0x585, 0 <= thread->suspend); + ASSERTREPORT(0x586, CheckThreadQueue(&thread->queueJoin)); + + switch(thread->state) { + case 1: + if (thread->suspend <= 0) { + ASSERTREPORT(0x58C, thread->queue == &RunQueue[thread->priority]); + ASSERTREPORT(0x58D, IsMember(&RunQueue[thread->priority], thread)); + ASSERTREPORT(0x58E, thread->priority == __OSGetEffectivePriority(thread)); + } + break; + case 2: + ASSERTREPORT(0x592, !IsSuspended(thread->suspend)); + ASSERTREPORT(0x593, thread->queue == NULL); + ASSERTREPORT(0x594, thread->priority == __OSGetEffectivePriority(thread)); + break; + case 4: + ASSERTREPORT(0x597, thread->queue != NULL); + ASSERTREPORT(0x598, CheckThreadQueue(thread->queue)); + ASSERTREPORT(0x599, IsMember(thread->queue, thread)); + if (thread->suspend <= 0) { + ASSERTREPORT(0x59C, thread->priority == __OSGetEffectivePriority(thread)); + } else { + ASSERTREPORT(0x5A0, thread->priority == 32); + } + ASSERTREPORT(0x5A2, !__OSCheckDeadLock(thread)); + break; + case 8: + ASSERTREPORT(0x5A6, thread->queueMutex.head == NULL && thread->queueMutex.tail == NULL); + break; + default: + OSReport("OSCheckActiveThreads: Failed. unkown thread state (%d) of thread %p\n", thread->state, thread); + OSPanic("OSThread.c", 0x5AC, ""); + } + ASSERTREPORT(0x5B1, __OSCheckMutexes(thread)); + thread = thread->linkActive.next; + } + OSRestoreInterrupts(enabled); + return cThread; +} diff --git a/src/static/dolphin/os/OSTime.c b/src/static/dolphin/os/OSTime.c new file mode 100644 index 00000000..e2186807 --- /dev/null +++ b/src/static/dolphin/os/OSTime.c @@ -0,0 +1,170 @@ +#include +#include +#include + +#include "os/__os.h" + +// End of each month in standard year +static int YearDays[MONTH_MAX] + = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; +// End of each month in leap year +static int LeapYearDays[MONTH_MAX] + = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; + +asm long long OSGetTime(void) +{ +#ifdef __MWERKS__ // clang-format off +jump: + nofralloc + + mftbu r3 + mftb r4 + + // Check for possible carry from TBL to TBU + mftbu r5 + cmpw r3, r5 + bne jump + + blr +#endif // clang-format on +} + +asm unsigned long OSGetTick(void) +{ +#ifdef __MWERKS__ // clang-format off + nofralloc + + mftb r3 + blr +#endif // clang-format on +} + +long long __OSGetSystemTime() +{ + int enabled; + long long* timeAdjustAddr; + long long result; + + timeAdjustAddr = (long long*)0x800030D8; + enabled = OSDisableInterrupts(); + + result = OSGetTime() + *timeAdjustAddr; + OSRestoreInterrupts(enabled); + return result; +} + +static int IsLeapYear(int year) +{ + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +static int GetYearDays(int year, int mon) { + int* md = (IsLeapYear(year)) ? LeapYearDays : YearDays; + + return md[mon]; +} + +static int GetLeapDays(int year) +{ + ASSERTLINE(260, 0 <= year); + + if (year < 1) { + return 0; + } + return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400; +} + +static void GetDates(int days, OSCalendarTime* td) +{ + int year; + int n; + int month; + int* md; + + ASSERTLINE(285, 0 <= days); + + td->wday = (days + 6) % WEEK_DAY_MAX; + + for (year = days / YEAR_DAY_MAX; + days < (n = year * YEAR_DAY_MAX + GetLeapDays(year)); year--) { + ; + } + + days -= n; + td->year = year; + td->yday = days; + + md = IsLeapYear(year) ? LeapYearDays : YearDays; + for (month = MONTH_MAX; days < md[--month];) { + ; + } + td->mon = month; + td->mday = days - md[month] + 1; +} + +void OSTicksToCalendarTime(long long ticks, OSCalendarTime* td) +{ + int days; + int secs; + long long d; + + d = ticks % OSSecondsToTicks(1); + if (d < 0) { + d += OSSecondsToTicks(1); + ASSERTLINE(330, 0 <= d); + } + + td->usec = OSTicksToMicroseconds(d) % USEC_MAX; + td->msec = OSTicksToMilliseconds(d) % MSEC_MAX; + + ASSERTLINE(334, 0 <= td->usec); + ASSERTLINE(335, 0 <= td->msec); + + ticks -= d; + + ASSERTLINE(338, ticks % OSSecondsToTicks(1) == 0); + ASSERTLINE(342, 0 <= OSTicksToSeconds(ticks) / 86400 + BIAS + && OSTicksToSeconds(ticks) / 86400 + BIAS <= INT_MAX); + + days = (OSTicksToSeconds(ticks) / SECS_IN_DAY) + BIAS; + secs = OSTicksToSeconds(ticks) % SECS_IN_DAY; + if (secs < 0) { + days -= 1; + secs += SECS_IN_DAY; + ASSERTLINE(349, 0 <= secs); + } + + GetDates(days, td); + td->hour = secs / 60 / 60; + td->min = secs / 60 % 60; + td->sec = secs % 60; +} + +OSTime OSCalendarTimeToTicks(OSCalendarTime* td) { + OSTime secs; + int ov_mon; + int mon; + int year; + + ov_mon = td->mon / MONTH_MAX; + mon = td->mon - (ov_mon * MONTH_MAX); + + if (mon < 0) { + mon += MONTH_MAX; + ov_mon--; + } + + ASSERTLINE(412, (ov_mon <= 0 && 0 <= td->year + ov_mon) || (0 < ov_mon && td->year <= INT_MAX - ov_mon)); + + year = td->year + ov_mon; + + secs = (OSTime)SECS_IN_YEAR * year + + (OSTime)SECS_IN_DAY * (GetLeapDays(year) + GetYearDays(year, mon) + td->mday - 1) + + (OSTime)SECS_IN_HOUR * td->hour + + (OSTime)SECS_IN_MIN * td->min + + td->sec - + (OSTime)0xEB1E1BF80ULL; + + return OSSecondsToTicks(secs) + OSMillisecondsToTicks((OSTime)td->msec) + + OSMicrosecondsToTicks((OSTime)td->usec); +} diff --git a/src/static/dolphin/os/__os.h b/src/static/dolphin/os/__os.h index 63ef9493..fd9ed032 100644 --- a/src/static/dolphin/os/__os.h +++ b/src/static/dolphin/os/__os.h @@ -4,11 +4,14 @@ #include // OS.c -extern char * __OSExceptionNames[15]; // D ONLY +extern char* __OSExceptionNames[15]; // D ONLY +extern OSTime __OSStartTime; unsigned long __OSIsDebuggerPresent(void); void __OSPSInit(void); -unsigned long __OSGetDIConfig(void); + +extern void* BOOT_REGION_START AT_ADDRESS(0x812FDFF0); +extern void* BOOT_REGION_END AT_ADDRESS(0x812FDFEC); // OSAlloc.c extern volatile int __OSCurrHeap; @@ -23,18 +26,24 @@ void __OSCacheInit(void); // OSContext.c void __OSContextInit(void); +// OSMemory.c +void __OSInitMemoryProtection(void); + // OSError.c -void __OSUnhandledException(unsigned char exception, struct OSContext * context, unsigned long dsisr, unsigned long dar); +void __OSUnhandledException(unsigned char exception, struct OSContext* context, + unsigned long dsisr, unsigned long dar); // OSInterrupt.c extern void __RAS_OSDisableInterrupts_begin(void); extern void __RAS_OSDisableInterrupts_end(void); extern unsigned long long __OSSpuriousInterrupts; // D ONLY -extern char * __OSInterruptNames[33]; // D ONLY -extern char * __OSPIErrors[8]; // D ONLY +extern char* __OSInterruptNames[33]; // D ONLY +extern char* __OSPIErrors[8]; // D ONLY +extern OSErrorHandlerEx __OSErrorTable[16]; -__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler); +__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, + __OSInterruptHandler handler); __OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt); void __OSInterruptInit(void); OSInterruptMask __OSMaskInterrupts(OSInterruptMask global); @@ -43,25 +52,33 @@ void __OSDispatchInterrupt(__OSException exception, OSContext* context); void __OSModuleInit(void); // OSMutex.c -void __OSUnlockAllMutex(struct OSThread *thread); -int __OSCheckDeadLock(struct OSThread *thread); -int __OSCheckMutexes(struct OSThread *thread); +void __OSUnlockAllMutex(struct OSThread* thread); +int __OSCheckDeadLock(struct OSThread* thread); +int __OSCheckMutexes(struct OSThread* thread); // OSResetSW.c -void __OSResetSWInterruptHandler(short exception, struct OSContext *context); +void __OSResetSWInterruptHandler(__OSInterrupt exception, + struct OSContext* context); + +// OSReset.c +void __OSDoHotReset(s32); + +// OSReboot.c +void __OSReboot(u32, u32); // OSRtc.c -int __OSGetRTC(unsigned long * rtc); +int __OSGetRTC(unsigned long* rtc); int __OSSetRTC(unsigned long rtc); void __OSInitSram(); -struct OSSram * __OSLockSram(void); -struct OSSramEx * __OSLockSramEx(void); +struct OSSram* __OSLockSram(void); +struct OSSramEx* __OSLockSramEx(void); int __OSUnlockSram(int commit); int __OSUnlockSramEx(int commit); int __OSSyncSram(void); int __OSCheckSram(void); -int __OSReadROM(void * buffer, long length, long offset); -int __OSReadROMAsync(void * buffer, long length, long offset, void (* callback)()); +int __OSReadROM(void* buffer, long length, long offset); +int __OSReadROMAsync(void* buffer, long length, long offset, + void (*callback)()); unsigned char __OSGetBootMode(void); void __OSSetBootMode(unsigned char ntd); @@ -73,8 +90,8 @@ void __OSInitSystemCall(void); // OSThread.c void __OSThreadInit(void); -long __OSGetEffectivePriority(struct OSThread * thread); -void __OSPromoteThread(struct OSThread * thread, long priority); +long __OSGetEffectivePriority(struct OSThread* thread); +void __OSPromoteThread(struct OSThread* thread, long priority); void __OSReschedule(void); // OSTime.c @@ -82,9 +99,12 @@ void __OSSetTime(long long time); long long __OSGetSystemTime(); void __OSSetTick(register unsigned long newTicks); +extern u32 __OSGetDIConfig(void); + // ppc_eabi_init.c __declspec(section ".init") asm void __init_hardware(void); -__declspec(section ".init") asm void __flush_cache(void *address, unsigned int size); +__declspec(section ".init") asm void __flush_cache(void* address, + unsigned int size); void __init_user(void); void __init_cpp(void); void __fini_cpp(void); @@ -94,17 +114,10 @@ void _ExitProcess(void); void __start(void); __declspec(section ".init") extern void __start(void); -__declspec(section ".init") void __copy_rom_section(void* dst, const void* src, unsigned long size); -__declspec(section ".init") void __init_bss_section(void* dst, unsigned long size); -__declspec(section ".init") extern void __init_registers(void); -__declspec(section ".init") extern void __init_data(void); // time.dolphin.c long long __get_clock(void); unsigned long __get_time(void); int __to_gm_time(void); -// EXIUart.c -void __OSEnableBarnacle(s32 chan, u32 dev); - #endif // _DOLPHIN_OS_INTERNAL_H_ diff --git a/src/static/jaudio_NES/internal/dspboot.c b/src/static/jaudio_NES/internal/dspboot.c index bf9f38a8..94b94940 100644 --- a/src/static/jaudio_NES/internal/dspboot.c +++ b/src/static/jaudio_NES/internal/dspboot.c @@ -342,7 +342,7 @@ extern void DSPInit2 (DSPTaskInfo2* task){ u16 tmp; enable = OSDisableInterrupts(); - __OSUnmaskInterrupts(OS_INTRMASK_DSP_DSP); + __OSUnmaskInterrupts(OS_INTERRUPTMASK_DSP_DSP); tmp = __DSPRegs[DSP_CONTROL_STATUS]; tmp = (tmp & ~0xA8)| 0x800;