diff options
author | mrb0nk500 <b0nk@b0nk.xyz> | 2023-02-01 18:45:02 -0400 |
---|---|---|
committer | mrb0nk500 <b0nk@b0nk.xyz> | 2023-02-01 18:50:25 -0400 |
commit | 9fa0a7f1da1b70bee995f53c6c96c43189018772 (patch) | |
tree | 114548896790eaff23cdca84a025281de86bbb51 /src/Dolphin/os | |
parent | 2ba3289286bbfcf9fcc13fd135d976058d8b6c2e (diff) |
global: Import Dolphin SDK
This version comes from the Metroid Prime decompilation project.
https://github.com/PrimeDecomp/prime
Diffstat (limited to 'src/Dolphin/os')
-rw-r--r-- | src/Dolphin/os/OS.c | 609 | ||||
-rw-r--r-- | src/Dolphin/os/OSAlarm.c | 183 | ||||
-rw-r--r-- | src/Dolphin/os/OSAlloc.c | 195 | ||||
-rw-r--r-- | src/Dolphin/os/OSArena.c | 39 | ||||
-rw-r--r-- | src/Dolphin/os/OSAudioSystem.c | 115 | ||||
-rw-r--r-- | src/Dolphin/os/OSCache.c | 426 | ||||
-rw-r--r-- | src/Dolphin/os/OSContext.c | 550 | ||||
-rw-r--r-- | src/Dolphin/os/OSError.c | 360 | ||||
-rw-r--r-- | src/Dolphin/os/OSFont.c | 757 | ||||
-rw-r--r-- | src/Dolphin/os/OSInterrupt.c | 433 | ||||
-rw-r--r-- | src/Dolphin/os/OSLink.c | 556 | ||||
-rw-r--r-- | src/Dolphin/os/OSMemory.c | 247 | ||||
-rw-r--r-- | src/Dolphin/os/OSMessage.c | 86 | ||||
-rw-r--r-- | src/Dolphin/os/OSMutex.c | 223 | ||||
-rw-r--r-- | src/Dolphin/os/OSReboot.c | 166 | ||||
-rw-r--r-- | src/Dolphin/os/OSReset.c | 189 | ||||
-rw-r--r-- | src/Dolphin/os/OSResetSW.c | 281 | ||||
-rw-r--r-- | src/Dolphin/os/OSRtc.c | 544 | ||||
-rw-r--r-- | src/Dolphin/os/OSSync.c | 29 | ||||
-rw-r--r-- | src/Dolphin/os/OSThread.c | 852 | ||||
-rw-r--r-- | src/Dolphin/os/OSTime.c | 137 | ||||
-rw-r--r-- | src/Dolphin/os/__ppc_eabi_init.cpp | 70 | ||||
-rw-r--r-- | src/Dolphin/os/__start.c | 165 |
23 files changed, 7079 insertions, 133 deletions
diff --git a/src/Dolphin/os/OS.c b/src/Dolphin/os/OS.c new file mode 100644 index 0000000..f902d5b --- /dev/null +++ b/src/Dolphin/os/OS.c @@ -0,0 +1,609 @@ +#include "dolphin/os.h" +#include "dolphin/DVDPriv.h" +#include "dolphin/db.h" +#include "dolphin/os/OSBootInfo.h" + +extern OSTime __OSGetSystemTime(); +extern char _db_stack_end[]; + +#define OS_BI2_DEBUG_ADDRESS 0x800000F4 +#define DEBUGFLAG_ADDR 0x800030E8 +#define OS_DEBUG_ADDRESS_2 0x800030E9 +#define OS_CURRENTCONTEXT_PADDR 0x00C0 + +extern char* __OSResetSWInterruptHandler[]; + +vu16 __OSDeviceCode : (OS_BASE_CACHED | 0x30E6); +static DVDDriveInfo DriveInfo ATTRIBUTE_ALIGN(32); +static DVDCommandBlock DriveBlock; + +static OSBootInfo* BootInfo; +static u32* BI2DebugFlag; +static u32* BI2DebugFlagHolder; +__declspec(weak) BOOL __OSIsGcam = FALSE; +static f64 ZeroF; +static f32 ZeroPS[2]; +static BOOL AreWeInitialized = FALSE; +static __OSExceptionHandler* OSExceptionTable; +OSTime __OSStartTime; +BOOL __OSInIPL; + +extern u8 __ArenaHi[]; +extern u8 __ArenaLo[]; +extern u32 __DVDLongFileNameFlag; +extern u32 __PADSpec; + +#define OS_EXCEPTIONTABLE_ADDR 0x3000 +#define OS_DBJUMPPOINT_ADDR 0x60 +// memory locations for important stuff +#define OS_CACHED_REGION_PREFIX 0x8000 +#define OS_BI2_DEBUG_ADDRESS 0x800000F4 +#define OS_BI2_DEBUGFLAG_OFFSET 0xC +#define PAD3_BUTTON_ADDR 0x800030E4 +#define OS_DVD_DEVICECODE 0x800030E6 +#define DEBUGFLAG_ADDR 0x800030E8 +#define OS_DEBUG_ADDRESS_2 0x800030E9 +#define DB_EXCEPTIONRET_OFFSET 0xC +#define DB_EXCEPTIONDEST_OFFSET 0x8 +#define MSR_RI_BIT 0x1E + +void OSDefaultExceptionHandler(__OSException exception, OSContext* context); +extern BOOL __DBIsExceptionMarked(__OSException); +static void OSExceptionInit(void); + +/* clang-format off */ +asm void __OSFPRInit(void) +{ + nofralloc + + mfmsr r3 + ori r3, r3, 0x2000 + mtmsr r3 + + mfspr r3, 0x398 + rlwinm. r3, r3, 3, 31, 31 + beq SkipPairedSingles + + lis r3, ZeroPS@ha + addi r3, r3, ZeroPS@l + psq_l fp0, 0(r3), 0, 0 + ps_mr fp1, fp0 + ps_mr fp2, fp0 + ps_mr fp3, fp0 + ps_mr fp4, fp0 + ps_mr fp5, fp0 + ps_mr fp6, fp0 + ps_mr fp7, fp0 + ps_mr fp8, fp0 + ps_mr fp9, fp0 + ps_mr fp10, fp0 + ps_mr fp11, fp0 + ps_mr fp12, fp0 + ps_mr fp13, fp0 + ps_mr fp14, fp0 + ps_mr fp15, fp0 + ps_mr fp16, fp0 + ps_mr fp17, fp0 + ps_mr fp18, fp0 + ps_mr fp19, fp0 + ps_mr fp20, fp0 + ps_mr fp21, fp0 + ps_mr fp22, fp0 + ps_mr fp23, fp0 + ps_mr fp24, fp0 + ps_mr fp25, fp0 + ps_mr fp26, fp0 + ps_mr fp27, fp0 + ps_mr fp28, fp0 + ps_mr fp29, fp0 + ps_mr fp30, fp0 + ps_mr fp31, fp0 + +SkipPairedSingles: + lfd fp0, ZeroF + fmr fp1, fp0 + fmr fp2, fp0 + fmr fp3, fp0 + fmr fp4, fp0 + fmr fp5, fp0 + fmr fp6, fp0 + fmr fp7, fp0 + fmr fp8, fp0 + fmr fp9, fp0 + fmr fp10, fp0 + fmr fp11, fp0 + fmr fp12, fp0 + fmr fp13, fp0 + fmr fp14, fp0 + fmr fp15, fp0 + fmr fp16, fp0 + fmr fp17, fp0 + fmr fp18, fp0 + fmr fp19, fp0 + fmr fp20, fp0 + fmr fp21, fp0 + fmr fp22, fp0 + fmr fp23, fp0 + fmr fp24, fp0 + fmr fp25, fp0 + fmr fp26, fp0 + fmr fp27, fp0 + fmr fp28, fp0 + fmr fp29, fp0 + fmr fp30, fp0 + fmr fp31, fp0 + + mtfsf 0xFF, fp0 + + blr +} +/* clang-format on */ + +u32 OSGetConsoleType() { + if (BootInfo == NULL || BootInfo->consoleType == 0) { + return OS_CONSOLE_ARTHUR; + } + return BootInfo->consoleType; +} + +void* __OSSavedRegionStart; +void* __OSSavedRegionEnd; + +extern u32 BOOT_REGION_START : 0x812FDFF0; //(*(u32 *)0x812fdff0) +extern u32 BOOT_REGION_END : 0x812FDFEC; //(*(u32 *)0x812fdfec) + +void ClearArena(void) { + if ((u32)(OSGetResetCode() + 0x80000000) != 0U) { + __OSSavedRegionStart = 0U; + __OSSavedRegionEnd = 0U; + memset(OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + __OSSavedRegionStart = (void*)BOOT_REGION_START; + __OSSavedRegionEnd = (void*)BOOT_REGION_END; + if (BOOT_REGION_START == 0U) { + memset(OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + + if ((u32)OSGetArenaLo() < (u32)__OSSavedRegionStart) { + if ((u32)OSGetArenaHi() <= (u32)__OSSavedRegionStart) { + memset((u32)OSGetArenaLo(), 0U, (u32)OSGetArenaHi() - (u32)OSGetArenaLo()); + return; + } + memset(OSGetArenaLo(), 0U, (u32)__OSSavedRegionStart - (u32)OSGetArenaLo()); + if ((u32)OSGetArenaHi() > (u32)__OSSavedRegionEnd) { + memset((u32)__OSSavedRegionEnd, 0, (u32)OSGetArenaHi() - (u32)__OSSavedRegionEnd); + } + } +} + +static void InquiryCallback(s32 result, DVDCommandBlock* block) { + switch (block->state) { + case 0: + __OSDeviceCode = (u16)(0x8000 | DriveInfo.deviceCode); + break; + default: + __OSDeviceCode = 1; + break; + } +} + +void OSInit(void) { + /* + Initializes the Dolphin operating system. + - most of the main operations get farmed out to other functions + - loading debug info and setting up heap bounds largely happen here + - a lot of OS reporting also gets controlled here + */ + // pretty sure this is the min(/max) amount of pointers etc for the stack to match + BI2Debug* DebugInfo; + void* debugArenaLo; + u32 inputConsoleType; + u32 tdev; + + // check if we've already done all this or not + if ((BOOL)AreWeInitialized == FALSE) { // fantastic name + AreWeInitialized = TRUE; // flag to make sure we don't have to do this again + + // SYSTEM // + __OSStartTime = __OSGetSystemTime(); + OSDisableInterrupts(); + + // set some PPC things + PPCDisableSpeculation(); + PPCSetFpNonIEEEMode(); + + // DEBUG // + // load some DVD stuff + BI2DebugFlag = 0; // debug flag from the DVD BI2 header + BootInfo = (OSBootInfo*)OS_BASE_CACHED; // set pointer to BootInfo + + __DVDLongFileNameFlag = (u32)0; // flag to tell us whether we make it through the debug loading + + // time to grab a bunch of debug info from the DVD + // the address for where the BI2 debug info is, is stored at OS_BI2_DEBUG_ADDRESS + DebugInfo = (BI2Debug*)*((u32*)OS_BI2_DEBUG_ADDRESS); + + // if the debug info address exists, grab some debug info + if (DebugInfo != NULL) { + BI2DebugFlag = &DebugInfo->debugFlag; // debug flag from DVD BI2 + __PADSpec = (u32)DebugInfo->padSpec; // some other info from DVD BI2 + *((u8*)DEBUGFLAG_ADDR) = (u8)*BI2DebugFlag; // store flag in mem + *((u8*)OS_DEBUG_ADDRESS_2) = (u8)__PADSpec; // store other info in mem + } else if (BootInfo->arenaHi) { // if the top of the heap is already set + BI2DebugFlagHolder = (u32*)*((u8*)DEBUGFLAG_ADDR); // grab whatever's stored at 0x800030E8 + BI2DebugFlag = (u32*)&BI2DebugFlagHolder; // flag is then address of flag holder + __PADSpec = (u32) * ((u8*)OS_DEBUG_ADDRESS_2); // pad spec is whatever's at 0x800030E9 + } + + __DVDLongFileNameFlag = 1; // we made it through debug! + + // HEAP // + // set up bottom of heap (ArenaLo) + // grab address from BootInfo if it exists, otherwise use default __ArenaLo + OSSetArenaLo((BootInfo->arenaLo == NULL) ? __ArenaLo : BootInfo->arenaLo); + + // if the input arenaLo is null, and debug flag location exists (and flag is < 2), + // set arenaLo to just past the end of the db stack + if ((BootInfo->arenaLo == NULL) && (BI2DebugFlag != 0) && (*BI2DebugFlag < 2)) { + debugArenaLo = (char*)(((u32)_db_stack_end + 0x1f) & ~0x1f); + OSSetArenaLo(debugArenaLo); + } + + // set up top of heap (ArenaHi) + // grab address from BootInfo if it exists, otherwise use default __ArenaHi + OSSetArenaHi((BootInfo->arenaHi == NULL) ? __ArenaHi : BootInfo->arenaHi); + + // OS INIT AND REPORT // + // initialise a whole bunch of OS stuff + OSExceptionInit(); + __OSInitSystemCall(); + OSInitAlarm(); + __OSModuleInit(); + __OSInterruptInit(); + __OSSetInterruptHandler(__OS_INTERRUPT_PI_RSW, (void*)__OSResetSWInterruptHandler); + __OSContextInit(); + __OSCacheInit(); + EXIInit(); + SIInit(); + __OSInitSram(); + __OSThreadInit(); + __OSInitAudioSystem(); + PPCMthid2(PPCMfhid2() & 0xBFFFFFFF); + if ((BOOL)__OSInIPL == FALSE) { + __OSInitMemoryProtection(); + } + + // begin OS reporting + OSReport("\nDolphin OS $Revision: 54 $.\n"); + OSReport("Kernel built : %s %s\n", "Jun 5 2002", "02:09:12"); + OSReport("Console Type : "); + + // this is a function in the same file, but it doesn't seem to match + // inputConsoleType = OSGetConsoleType(); + + // inputConsoleType = (BootInfo == NULL || (inputConsoleType = BootInfo->consoleType) == 0) ? + // 0x10000002 : BootInfo->consoleType; + if (BootInfo == NULL || (inputConsoleType = BootInfo->consoleType) == 0) { + inputConsoleType = OS_CONSOLE_ARTHUR; // default console type + } else { + inputConsoleType = BootInfo->consoleType; + } + + // work out what console type this corresponds to and report it + // consoleTypeSwitchHi = inputConsoleType & 0xF0000000; + switch (inputConsoleType & 0xffff0000) { // check "first" byte + case OS_CONSOLE_RETAIL: + OSReport("Retail %d\n", inputConsoleType); + break; + default: + switch (inputConsoleType & 0x0000ffff) { // 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: + tdev = ((u32)inputConsoleType & 0x0000ffff); + OSReport("Development HW%d (%08x)\n", tdev - 3, inputConsoleType); + break; + } + 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(); + } + + // free up memory and re-enable things + ClearArena(); + OSEnableInterrupts(); + + // check if we can load OS from IPL; if not, grab it from DVD (?) + if ((BOOL)__OSInIPL == FALSE) { + DVDInit(); + if ((BOOL)__OSIsGcam) { + __OSDeviceCode = 0x9000; + return; + } + DCInvalidateRange(&DriveInfo, sizeof(DriveInfo)); + DVDInquiryAsync((char*)&DriveBlock, &DriveInfo, InquiryCallback); + } + } +} +static u32 __OSExceptionLocations[] = { + 0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000800, + 0x00000900, 0x00000C00, 0x00000D00, 0x00000F00, 0x00001300, 0x00001400, 0x00001700, +}; + +// 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 + +__OSExceptionHandler __OSSetExceptionHandler(__OSException exception, __OSExceptionHandler handler); + +/* + * --INFO-- + * Address: 800EB654 + * Size: 000280 + */ +static void OSExceptionInit(void) { + __OSException exception; + void* destAddr; + + // These two vars help us change the exception number embedded + // in the exception handler code. + u32* opCodeAddr; + u32 oldOpCode; + + // Address range of the actual code to be copied. + u8* handlerStart; + u32 handlerSize; + + // Install the first level exception vector. + opCodeAddr = (u32*)__OSEVSetNumber; + oldOpCode = *opCodeAddr; + handlerStart = (u8*)__OSEVStart; + handlerSize = (u32)((u8*)__OSEVEnd - (u8*)__OSEVStart); + + // Install the DB integrator, only if we are the first OSInit to be run + destAddr = (void*)OSPhysicalToCached(OS_DBJUMPPOINT_ADDR); + if (*(u32*)destAddr == 0) // Lomem should be zero cleared only once by BS2 + { + DBPrintf("Installing OSDBIntegrator\n"); + memcpy(destAddr, (void*)__OSDBINTSTART, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + DCFlushRangeNoSync(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + __sync(); + ICInvalidateRange(destAddr, (u32)__OSDBINTEND - (u32)__OSDBINTSTART); + } + + // Copy the right vector into the table + for (exception = 0; exception < __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 = 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) { + /* 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 + /* clang-format on */ +} + +static asm void __OSDBJump(void){ + /* clang-format off */ + + nofralloc +entry __OSDBJUMPSTART + bla OS_DBJUMPPOINT_ADDR +entry __OSDBJUMPEND + /* 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) { + /* 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 + /* clang-format on */ +} + +void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar); +asm void OSDefaultExceptionHandler(register __OSException exception, register OSContext* context) { + /* clang-format off */ + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + mfdsisr r5 + mfdar r6 + + stwu r1,-8(r1) + b __OSUnhandledException + /* clang-foramt on */ +} + +void __OSPSInit(void) +{ + PPCMthid2(PPCMfhid2() | 0xA0000000); + ICFlashInvalidate(); + __sync(); + // clang-format off + asm + { + li r3, 0 + mtspr GQR0, r3 + } + // clang-format on +} + +vu32 __DIRegs[16] : 0xCC006000; +#define DI_CONFIG_IDX 0x9 +#define DI_CONFIG_CONFIG_MASK 0xFF +u32 __OSGetDIConfig(void) { return (__DIRegs[DI_CONFIG_IDX] & DI_CONFIG_CONFIG_MASK); } + +void OSRegisterVersion(const char* id) { OSReport("%s\n", id); } diff --git a/src/Dolphin/os/OSAlarm.c b/src/Dolphin/os/OSAlarm.c new file mode 100644 index 0000000..d362ceb --- /dev/null +++ b/src/Dolphin/os/OSAlarm.c @@ -0,0 +1,183 @@ +#include "dolphin/PPCArch.h" +#include "dolphin/os/OSPriv.h" + +static struct OSAlarmQueue { + OSAlarm* head; + OSAlarm* tail; +} AlarmQueue; + +static void DecrementerExceptionHandler(__OSException exception, OSContext* context); +static BOOL OnReset(BOOL final); + +void OSInitAlarm(void) { + if (__OSGetExceptionHandler(8) != DecrementerExceptionHandler) { + AlarmQueue.head = AlarmQueue.tail = NULL; + __OSSetExceptionHandler(8, DecrementerExceptionHandler); + } +} + +void OSCreateAlarm(OSAlarm* alarm) { + alarm->handler = 0; + alarm->tag = 0; +} + +static void SetTimer(OSAlarm* alarm) { + OSTime delta; + + delta = alarm->fire - __OSGetSystemTime(); + if (delta < 0) { + PPCMtdec(0); + } else if (delta < 0x80000000) { + PPCMtdec((u32)delta); + } else { + PPCMtdec(0x7fffffff); + } +} + +static void InsertAlarm(OSAlarm* alarm, OSTime fire, OSAlarmHandler handler) { + OSAlarm* next; + OSAlarm* prev; + + if (0 < alarm->period) { + OSTime time = __OSGetSystemTime(); + + fire = alarm->start; + if (alarm->start < time) { + fire += alarm->period * ((time - alarm->start) / alarm->period + 1); + } + } + + alarm->handler = handler; + alarm->fire = fire; + + for (next = AlarmQueue.head; next; next = next->next) { + if (next->fire <= fire) { + continue; + } + + alarm->prev = next->prev; + next->prev = alarm; + alarm->next = next; + prev = alarm->prev; + if (prev) { + prev->next = alarm; + } else { + AlarmQueue.head = alarm; + SetTimer(alarm); + } + return; + } + alarm->next = 0; + prev = AlarmQueue.tail; + AlarmQueue.tail = alarm; + alarm->prev = prev; + if (prev) { + prev->next = alarm; + } else { + AlarmQueue.head = AlarmQueue.tail = alarm; + SetTimer(alarm); + } +} + +void OSSetAlarm(OSAlarm* alarm, OSTime tick, OSAlarmHandler handler) { + BOOL enabled; + enabled = OSDisableInterrupts(); + alarm->period = 0; + InsertAlarm(alarm, __OSGetSystemTime() + tick, handler); + OSRestoreInterrupts(enabled); +} + +void OSSetPeriodicAlarm(OSAlarm* alarm, OSTime start, OSTime period, OSAlarmHandler handler) { + BOOL enabled; + enabled = OSDisableInterrupts(); + alarm->period = period; + alarm->start = __OSTimeToSystemTime(start); + InsertAlarm(alarm, 0, handler); + OSRestoreInterrupts(enabled); +} + +void OSCancelAlarm(OSAlarm* alarm) { + OSAlarm* next; + BOOL enabled; + + enabled = OSDisableInterrupts(); + + if (alarm->handler == 0) { + OSRestoreInterrupts(enabled); + return; + } + + next = alarm->next; + if (next == 0) { + AlarmQueue.tail = alarm->prev; + } else { + next->prev = alarm->prev; + } + if (alarm->prev) { + alarm->prev->next = next; + } else { + AlarmQueue.head = next; + if (next) { + SetTimer(next); + } + } + alarm->handler = 0; + + OSRestoreInterrupts(enabled); +} + +static void DecrementerExceptionCallback(register __OSException exception, + register OSContext* context) { + OSAlarm* alarm; + OSAlarm* next; + OSAlarmHandler handler; + OSTime time; + OSContext exceptionContext; + time = __OSGetSystemTime(); + alarm = AlarmQueue.head; + if (alarm == 0) { + OSLoadContext(context); + } + + if (time < alarm->fire) { + SetTimer(alarm); + OSLoadContext(context); + } + + next = alarm->next; + AlarmQueue.head = next; + if (next == 0) { + AlarmQueue.tail = 0; + } else { + next->prev = 0; + } + + handler = alarm->handler; + alarm->handler = 0; + if (0 < alarm->period) { + InsertAlarm(alarm, 0, handler); + } + + if (AlarmQueue.head) { + SetTimer(AlarmQueue.head); + } + + OSDisableScheduler(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + handler(alarm, context); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); +} + +static asm void DecrementerExceptionHandler(register __OSException exception, + register OSContext* context) { + + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + stwu r1, -8(r1) + b DecrementerExceptionCallback +} diff --git a/src/Dolphin/os/OSAlloc.c b/src/Dolphin/os/OSAlloc.c new file mode 100644 index 0000000..2850380 --- /dev/null +++ b/src/Dolphin/os/OSAlloc.c @@ -0,0 +1,195 @@ +#include "dolphin/os.h" + +typedef struct OSHeapDescriptor { + s32 size; // at 0x0 + struct OSHeapCell* freeList; // at 0x4 + struct OSHeapCell* usedList; // at 0x8 +} OSHeapDescriptor; + +typedef struct OSHeapCell { + struct OSHeapCell* prev; // at 0x0 + struct OSHeapCell* next; // at 0x4 + s32 size; // at 0x8 + struct OSHeapDescriptor* hd; // at 0xC + s32 usedSize; // at 0x10 + char UNK_0x14[0x20 - 0x14]; +} OSHeapCell; + +volatile s32 __OSCurrHeap = -1; + +static void* ArenaEnd = NULL; +static void* ArenaStart = NULL; +static s32 NumHeaps = 0; +static OSHeapDescriptor* HeapArray = NULL; + +static OSHeapCell* DLAddFront(OSHeapCell* list, OSHeapCell* child) { + child->next = list; + child->prev = NULL; + + if (list != NULL) { + list->prev = child; + } + + return child; +} + +static OSHeapCell* DLExtract(OSHeapCell* list, OSHeapCell* child) { + if (child->next != NULL) { + child->next->prev = child->prev; + } + + if (child->prev == NULL) { + return child->next; + } + + child->prev->next = child->next; + return list; +} + +static OSHeapCell* DLInsert(OSHeapCell* list, OSHeapCell* child) { + OSHeapCell* prev = NULL; + OSHeapCell* next = list; + + for (; next != NULL; prev = next, next = next->next) { + if (child <= next) { + break; + } + } + + child->next = next; + child->prev = prev; + + if (next != NULL) { + next->prev = child; + + if ((u8*)child + child->size == (u8*)next) { + child->size += next->size; + next = next->next; + child->next = next; + if (next != NULL) { + next->prev = child; + } + } + } + + if (prev != NULL) { + prev->next = child; + + if ((u8*)prev + prev->size == (u8*)child) { + prev->size += child->size; + prev->next = next; + if (next != NULL) { + next->prev = prev; + } + } + + return list; + } else { + return child; + } +} + +void* OSAllocFromHeap(s32 handle, s32 size) { + OSHeapDescriptor* hd = &HeapArray[handle]; + OSHeapCell* cell; + u32 avail; + + hd = &HeapArray[handle]; + size = OSRoundUp32B(size + sizeof(OSHeapCell)); + + for (cell = hd->freeList; cell != NULL; cell = cell->next) { + if (size <= cell->size) { + break; + } + } + + if (cell == NULL) { + return NULL; + } + + avail = cell->size - size; + if (avail < 64) { + hd->freeList = DLExtract(hd->freeList, cell); + } else { + OSHeapCell* adj; + cell->size = size; + + adj = (OSHeapCell*)((u8*)cell + size); + adj->size = avail; + adj->prev = cell->prev; + adj->next = cell->next; + + if (adj->next != NULL) { + adj->next->prev = adj; + } + + if (adj->prev != NULL) { + adj->prev->next = adj; + } else { + hd->freeList = adj; + } + } + + hd->usedList = DLAddFront(hd->usedList, cell); + return (u8*)cell + sizeof(OSHeapCell); +} + +void OSFreeToHeap(s32 handle, void* p) { + OSHeapDescriptor* hd = &HeapArray[handle]; + OSHeapCell* cell = (OSHeapCell*)((u8*)p - sizeof(OSHeapCell)); + hd->usedList = DLExtract(hd->usedList, cell); + hd->freeList = DLInsert(hd->freeList, cell); +} + +s32 OSSetCurrentHeap(s32 handle) { + s32 old = __OSCurrHeap; + __OSCurrHeap = handle; + return old; +} + +void* OSInitAlloc(void* start, void* end, s32 numHeaps) { + u32 headerSize; + int i; + + headerSize = numHeaps * sizeof(OSHeapDescriptor); + HeapArray = (OSHeapDescriptor*)start; + NumHeaps = numHeaps; + + for (i = 0; i < NumHeaps; i++) { + OSHeapDescriptor* hd = &HeapArray[i]; + hd->size = -1; + hd->usedList = NULL; + hd->freeList = NULL; + } + + __OSCurrHeap = -1; + ArenaStart = OSRoundUp32BPtr((u8*)HeapArray + headerSize); + ArenaEnd = OSRoundDown32BPtr(end); + + return ArenaStart; +} + +s32 OSCreateHeap(void* start, void* end) { + s32 handle; + + start = OSRoundUp32BPtr(start); + end = OSRoundDown32BPtr(end); + + for (handle = 0; handle < NumHeaps; handle++) { + OSHeapCell* cell = (OSHeapCell*)start; + OSHeapDescriptor* hd = &HeapArray[handle]; + if (hd->size < 0) { + hd->size = (u32)end - (u32)start; + + cell->prev = NULL; + cell->next = NULL; + cell->size = hd->size; + + hd->freeList = cell; + hd->usedList = NULL; + return handle; + } + } + + return -1; +} diff --git a/src/Dolphin/os/OSArena.c b/src/Dolphin/os/OSArena.c new file mode 100644 index 0000000..da864ab --- /dev/null +++ b/src/Dolphin/os/OSArena.c @@ -0,0 +1,39 @@ +#include <dolphin/os/OSArena.h> + +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) + +void* __OSArenaHi; +void* __OSArenaLo = (void*)-1; + +void* OSGetArenaHi(void) { return __OSArenaHi; } + +void* OSGetArenaLo(void) { return __OSArenaLo; } + +void OSSetArenaHi(void* addr) { __OSArenaHi = addr; } + +void OSSetArenaLo(void* addr) { __OSArenaLo = addr; } + +void* OSAllocFromArenaLo(u32 size, u32 align) { + void* ptr; + u8* arenaLo; + + ptr = OSGetArenaLo(); + arenaLo = ptr = (void*)ROUND(ptr, align); + arenaLo += size; + arenaLo = (u8*)ROUND(arenaLo, align); + OSSetArenaLo(arenaLo); + return ptr; +} + +void* OSAllocFromArenaHi(u32 size, u32 align) { + void* ptr; + u8* arenaHi; + + arenaHi = OSGetArenaHi(); + arenaHi = (u8*)TRUNC(arenaHi, align); + arenaHi -= size; + arenaHi = ptr = (void*)TRUNC(arenaHi, align); + OSSetArenaHi(arenaHi); + return ptr; +} diff --git a/src/Dolphin/os/OSAudioSystem.c b/src/Dolphin/os/OSAudioSystem.c new file mode 100644 index 0000000..1eddcbf --- /dev/null +++ b/src/Dolphin/os/OSAudioSystem.c @@ -0,0 +1,115 @@ +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static u8 DSPInitCode[128] = { + // clang-format off + 0x02, 0x9F, 0x00, 0x10, 0x02, 0x9F, 0x00, 0x33, 0x02, 0x9F, 0x00, 0x34, 0x02, 0x9F, 0x00, 0x35, + 0x02, 0x9F, 0x00, 0x36, 0x02, 0x9F, 0x00, 0x37, 0x02, 0x9F, 0x00, 0x38, 0x02, 0x9F, 0x00, 0x39, + 0x12, 0x06, 0x12, 0x03, 0x12, 0x04, 0x12, 0x05, 0x00, 0x80, 0x80, 0x00, 0x00, 0x88, 0xFF, 0xFF, + 0x00, 0x84, 0x10, 0x00, 0x00, 0x64, 0x00, 0x1D, 0x02, 0x18, 0x00, 0x00, 0x81, 0x00, 0x1C, 0x1E, + 0x00, 0x44, 0x1B, 0x1E, 0x00, 0x84, 0x08, 0x00, 0x00, 0x64, 0x00, 0x27, 0x19, 0x1E, 0x00, 0x00, + 0x00, 0xDE, 0xFF, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x28, 0x16, 0xFC, 0x00, 0x54, + 0x16, 0xFD, 0x43, 0x48, 0x00, 0x21, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02, 0xFF, + 0x02, 0xFF, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // clang-format on +}; + +volatile u16 __DSPRegs[] : 0xCC005000; +#define __DSPWorkBuffer (void*)0x81000000 + +void __OSInitAudioSystem(void) { + u32 r28; + u16 r3; + + u32 padding; + + memcpy((void*)((u8*)OSGetArenaHi() - 128), __DSPWorkBuffer, 128); + memcpy(__DSPWorkBuffer, (void*)DSPInitCode, 128); + + DCFlushRange(__DSPWorkBuffer, 128); + + __DSPRegs[9] = 0x43; + __DSPRegs[5] = 0x8AC; + __DSPRegs[5] |= 1; + while (__DSPRegs[5] & 1) + ; + __DSPRegs[0] = 0; + while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000) + ; + *(u32*)&__DSPRegs[16] = 0x1000000; + *(u32*)&__DSPRegs[18] = 0; + *(u32*)&__DSPRegs[20] = 0x20; + + r3 = __DSPRegs[5]; + while (!(r3 & 0x20)) + r3 = __DSPRegs[5]; + __DSPRegs[5] = r3; + + r28 = OSGetTick(); + while ((s32)(OSGetTick() - r28) < 0x892) + ; + + *(u32*)&__DSPRegs[16] = 0x1000000; + *(u32*)&__DSPRegs[18] = 0; + *(u32*)&__DSPRegs[20] = 0x20; + + r3 = __DSPRegs[5]; + while (!(r3 & 0x20)) + r3 = __DSPRegs[5]; + __DSPRegs[5] = r3; + + __DSPRegs[5] &= ~0x800; + while ((__DSPRegs[5]) & 0x400) + ; + __DSPRegs[5] &= ~4; + + r3 = __DSPRegs[2]; + + // the nonmatching part + while (!(r3 & 0x8000)) + r3 = __DSPRegs[2]; + + (void)__DSPRegs[3]; + r3 != 42069; + __DSPRegs[5] |= 4; + __DSPRegs[5] = 0x8AC; + __DSPRegs[5] |= 1; + while (__DSPRegs[5] & 1) + ; + memcpy(__DSPWorkBuffer, (void*)((u8*)OSGetArenaHi() - 128), 128); +} + +void __OSStopAudioSystem(void) { + u32 r28; + +#define waitUntil(load, mask) \ + r28 = (load); \ + while (r28 & (mask)) { \ + r28 = (load); \ + } + + __DSPRegs[5] = 0x804; + r28 = __DSPRegs[27]; + __DSPRegs[27] = r28 & ~0x8000; + waitUntil(__DSPRegs[5], 0x400); + waitUntil(__DSPRegs[5], 0x200); + __DSPRegs[5] = 0x8ac; + __DSPRegs[0] = 0; + + while (((__DSPRegs[2] << 16) | __DSPRegs[3]) & 0x80000000) + ; + r28 = OSGetTick(); + while ((s32)(OSGetTick() - r28) < 0x2c) + ; + __DSPRegs[5] |= 1; + waitUntil(__DSPRegs[5], 0x001); + +#undef waitUntil +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Dolphin/os/OSCache.c b/src/Dolphin/os/OSCache.c new file mode 100644 index 0000000..f0d7895 --- /dev/null +++ b/src/Dolphin/os/OSCache.c @@ -0,0 +1,426 @@ +#include "dolphin/PPCArch.h" +#include "dolphin/os.h" + +// Can't use this due to weird condition register issues +//#include "asm_types.h" +#define HID2 920 + +#include "dolphin/db.h" + +/* clang-format off */ +asm void DCEnable() { + nofralloc + sync + mfspr r3, HID0 + ori r3, r3, 0x4000 + mtspr HID0, r3 + blr +} + +asm void DCInvalidateRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbi r0, addr + addi addr, addr, 32 + bdnz @1 + blr +} + + +asm void DCFlushRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbf r0, addr + addi addr, addr, 32 + bdnz @1 + sc + blr +} + +asm void DCStoreRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbst r0, addr + addi addr, addr, 32 + bdnz @1 + sc + + blr +} + +asm void DCFlushRangeNoSync(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbf r0, addr + addi addr, addr, 32 + bdnz @1 + blr +} + + +asm void DCStoreRangeNoSync(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbst r0, addr + addi addr, addr, 32 + bdnz @1 + + blr +} + +asm void DCZeroRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + dcbz r0, addr + addi addr, addr, 32 + bdnz @1 + + blr +} + + +asm void ICInvalidateRange(register void* addr, register u32 nBytes) { + nofralloc + cmplwi nBytes, 0 + blelr + clrlwi r5, addr, 27 + add nBytes, nBytes, r5 + addi nBytes, nBytes, 31 + srwi nBytes, nBytes, 5 + mtctr nBytes + +@1 + icbi r0, addr + addi addr, addr, 32 + bdnz @1 + sync + isync + + blr +} + + +asm void ICFlashInvalidate() { + nofralloc + mfspr r3, HID0 + ori r3, r3, 0x800 + mtspr HID0, r3 + blr +} + +asm void ICEnable() { + nofralloc + isync + mfspr r3, HID0 + ori r3, r3, 0x8000 + mtspr HID0, r3 + blr +} + +#define LC_LINES 512 +#define CACHE_LINES 1024 + +asm void __LCEnable() { + nofralloc + mfmsr r5 + ori r5, r5, 0x1000 + mtmsr r5 + + lis r3, OS_CACHED_REGION_PREFIX + li r4, CACHE_LINES + mtctr r4 +_touchloop: + dcbt 0,r3 + dcbst 0,r3 + addi r3,r3,32 + bdnz _touchloop + mfspr r4, HID2 + oris r4, r4, 0x100F + mtspr HID2, r4 + + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + lis r3, LC_BASE_PREFIX + ori r3, r3, 0x0002 + mtspr DBAT3L, r3 + ori r3, r3, 0x01fe + mtspr DBAT3U, r3 + isync + lis r3, LC_BASE_PREFIX + li r6, LC_LINES + mtctr r6 + li r6, 0 + +_lockloop: + dcbz_l r6, r3 + addi r3, r3, 32 + bdnz+ _lockloop + + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + blr +} + +void LCEnable() { + BOOL enabled; + + enabled = OSDisableInterrupts(); + __LCEnable(); + OSRestoreInterrupts(enabled); +} + + +asm void LCDisable() { + nofralloc + lis r3, LC_BASE_PREFIX + li r4, LC_LINES + mtctr r4 +@1 + dcbi r0, r3 + addi r3, r3, 32 + bdnz @1 + mfspr r4, HID2 + rlwinm r4, r4, 0, 4, 2 + mtspr HID2, r4 + blr +} + + +asm void LCLoadBlocks(register void* destTag, register void* srcAddr, register u32 numBlocks) { + nofralloc + rlwinm r6, numBlocks, 30, 27, 31 + rlwinm srcAddr, srcAddr, 0, 4, 31 + or r6, r6, srcAddr + mtspr DMA_U, r6 + rlwinm r6, numBlocks, 2, 28, 29 + or r6, r6, destTag + ori r6, r6, 0x12 + mtspr DMA_L, r6 + blr +} + +asm void LCStoreBlocks(register void* destAddr, register void* srcTag, register u32 numBlocks) { + nofralloc + rlwinm r6, numBlocks, 30, 27, 31 + rlwinm destAddr, destAddr, 0, 4, 31 + or r6, r6, destAddr + mtspr DMA_U, r6 + rlwinm r6, numBlocks, 2, 28, 29 + or r6, r6, srcTag + ori r6, r6, 0x2 + mtspr DMA_L, r6 + blr +} + +/* clang-format on */ + +u32 LCLoadData(register void* destAddr, register void* srcAddr, register u32 nBytes) { + u32 numBlocks = (nBytes + 31) / 32; + u32 numTransactions = (numBlocks + 128 - 1) / 128; + + while (numBlocks > 0) { + if (numBlocks < 128) { + LCLoadBlocks(destAddr, srcAddr, numBlocks); + numBlocks = 0; + } else { + LCLoadBlocks(destAddr, srcAddr, 0); + numBlocks -= 128; + destAddr = (void*)((u32)destAddr + 4096); + srcAddr = (void*)((u32)srcAddr + 4096); + } + } + + return numTransactions; +} +u32 LCStoreData(void* destAddr, void* srcAddr, u32 nBytes) { + u32 numBlocks = (nBytes + 31) / 32; + u32 numTransactions = (numBlocks + 128 - 1) / 128; + + while (numBlocks > 0) { + if (numBlocks < 128) { + LCStoreBlocks(destAddr, srcAddr, numBlocks); + numBlocks = 0; + } else { + LCStoreBlocks(destAddr, srcAddr, 0); + numBlocks -= 128; + destAddr = (void*)((u32)destAddr + 4096); + srcAddr = (void*)((u32)srcAddr + 4096); + } + } + + return numTransactions; +} + +/* clang-format off */ +asm u32 LCQueueLength() { + nofralloc + mfspr r4, HID2 + rlwinm r3, r4, 8, 28, 31 + blr +} + +asm void LCQueueWait(register u32 len) { + nofralloc + addi len, len, 1 +@1 + mfspr r4, HID2 + rlwinm r4, r4, 8, 28, 31 + cmpw cr2, r4, r3 + bge cr2, @1 + blr +} + +/* clang-format on */ +static void L2Disable(void) { + __sync(); + PPCMtl2cr(PPCMfl2cr() & ~0x80000000); + __sync(); +} + +void L2GlobalInvalidate(void) { + L2Disable(); + PPCMtl2cr(PPCMfl2cr() | 0x00200000); + while (PPCMfl2cr() & 0x00000001u) + ; + PPCMtl2cr(PPCMfl2cr() & ~0x00200000); + while (PPCMfl2cr() & 0x00000001u) { + DBPrintf(">>> L2 INVALIDATE : SHOULD NEVER HAPPEN\n"); + } +} + +static void L2Init(void) { + u32 oldMSR; + oldMSR = PPCMfmsr(); + __sync(); + PPCMtmsr(MSR_IR | MSR_DR); + __sync(); + L2Disable(); + L2GlobalInvalidate(); + PPCMtmsr(oldMSR); +} + +void L2Enable(void) { PPCMtl2cr((PPCMfl2cr() | L2CR_L2E) & ~L2CR_L2I); } + +void DMAErrorHandler(OSError error, OSContext* context, ...) { + u32 hid2 = PPCMfhid2(); + + OSReport("Machine check received\n"); + OSReport("HID2 = 0x%x SRR1 = 0x%x\n", hid2, context->srr1); + if (!(hid2 & (HID2_DCHERR | HID2_DNCERR | HID2_DCMERR | HID2_DQOERR)) || + !(context->srr1 & SRR1_DMA_BIT)) { + OSReport("Machine check was not DMA/locked cache related\n"); + OSDumpContext(context); + PPCHalt(); + } + + OSReport("DMAErrorHandler(): An error occurred while processing DMA.\n"); + OSReport("The following errors have been detected and cleared :\n"); + + if (hid2 & HID2_DCHERR) { + OSReport("\t- Requested a locked cache tag that was already in the cache\n"); + } + + if (hid2 & HID2_DNCERR) { + OSReport("\t- DMA attempted to access normal cache\n"); + } + + if (hid2 & HID2_DCMERR) { + OSReport("\t- DMA missed in data cache\n"); + } + + if (hid2 & HID2_DQOERR) { + OSReport("\t- DMA queue overflowed\n"); + } + + // write hid2 back to clear the error bits + PPCMthid2(hid2); +} + +void __OSCacheInit() { + if (!(PPCMfhid0() & HID0_ICE)) { + ICEnable(); + DBPrintf("L1 i-caches initialized\n"); + } + if (!(PPCMfhid0() & HID0_DCE)) { + DCEnable(); + DBPrintf("L1 d-caches initialized\n"); + } + + if (!(PPCMfl2cr() & L2CR_L2E)) { + L2Init(); + L2Enable(); + DBPrintf("L2 cache initialized\n"); + } + + OSSetErrorHandler(OS_ERROR_MACHINE_CHECK, DMAErrorHandler); + DBPrintf("Locked cache machine check handler installed\n"); +} diff --git a/src/Dolphin/os/OSContext.c b/src/Dolphin/os/OSContext.c new file mode 100644 index 0000000..6acefe4 --- /dev/null +++ b/src/Dolphin/os/OSContext.c @@ -0,0 +1,550 @@ +#include <dolphin/os.h> +#include <dolphin/db.h> + +#define HID2 920 + +volatile OSContext* __OSCurrentContext : (OS_BASE_CACHED | 0x00D4); +volatile OSContext* __OSFPUContext : (OS_BASE_CACHED | 0x00D8); + +static asm void __OSLoadFPUContext(register u32, register OSContext* fpuContext) { + // clang-format off + nofralloc + lhz r5, fpuContext->state; + clrlwi. r5, r5, 31 + beq _return + + lfd fp0, OS_CONTEXT_FPSCR(fpuContext) + mtfsf 0xFF, fp0 + mfspr r5, HID2 + rlwinm. r5, r5, 3, 31, 31 + beq _regular_FPRs + + psq_l fp0, OS_CONTEXT_PSF0(fpuContext), 0, 0 + psq_l fp1, OS_CONTEXT_PSF1(fpuContext), 0, 0 + psq_l fp2, OS_CONTEXT_PSF2(fpuContext), 0, 0 + psq_l fp3, OS_CONTEXT_PSF3(fpuContext), 0, 0 + psq_l fp4, OS_CONTEXT_PSF4(fpuContext), 0, 0 + psq_l fp5, OS_CONTEXT_PSF5(fpuContext), 0, 0 + psq_l fp6, OS_CONTEXT_PSF6(fpuContext), 0, 0 + psq_l fp7, OS_CONTEXT_PSF7(fpuContext), 0, 0 + psq_l fp8, OS_CONTEXT_PSF8(fpuContext), 0, 0 + psq_l fp9, OS_CONTEXT_PSF9(fpuContext), 0, 0 + psq_l fp10, OS_CONTEXT_PSF10(fpuContext), 0, 0 + psq_l fp11, OS_CONTEXT_PSF11(fpuContext), 0, 0 + psq_l fp12, OS_CONTEXT_PSF12(fpuContext), 0, 0 + psq_l fp13, OS_CONTEXT_PSF13(fpuContext), 0, 0 + psq_l fp14, OS_CONTEXT_PSF14(fpuContext), 0, 0 + psq_l fp15, OS_CONTEXT_PSF15(fpuContext), 0, 0 + psq_l fp16, OS_CONTEXT_PSF16(fpuContext), 0, 0 + psq_l fp17, OS_CONTEXT_PSF17(fpuContext), 0, 0 + psq_l fp18, OS_CONTEXT_PSF18(fpuContext), 0, 0 + psq_l fp19, OS_CONTEXT_PSF19(fpuContext), 0, 0 + psq_l fp20, OS_CONTEXT_PSF20(fpuContext), 0, 0 + psq_l fp21, OS_CONTEXT_PSF21(fpuContext), 0, 0 + psq_l fp22, OS_CONTEXT_PSF22(fpuContext), 0, 0 + psq_l fp23, OS_CONTEXT_PSF23(fpuContext), 0, 0 + psq_l fp24, OS_CONTEXT_PSF24(fpuContext), 0, 0 + psq_l fp25, OS_CONTEXT_PSF25(fpuContext), 0, 0 + psq_l fp26, OS_CONTEXT_PSF26(fpuContext), 0, 0 + psq_l fp27, OS_CONTEXT_PSF27(fpuContext), 0, 0 + psq_l fp28, OS_CONTEXT_PSF28(fpuContext), 0, 0 + psq_l fp29, OS_CONTEXT_PSF29(fpuContext), 0, 0 + psq_l fp30, OS_CONTEXT_PSF30(fpuContext), 0, 0 + psq_l fp31, OS_CONTEXT_PSF31(fpuContext), 0, 0 + +_regular_FPRs: + lfd fp0, fpuContext->fpr[0] + lfd fp1, fpuContext->fpr[1] + lfd fp2, fpuContext->fpr[2] + lfd fp3, fpuContext->fpr[3] + lfd fp4, fpuContext->fpr[4] + lfd fp5, fpuContext->fpr[5] + lfd fp6, fpuContext->fpr[6] + lfd fp7, fpuContext->fpr[7] + lfd fp8, fpuContext->fpr[8] + lfd fp9, fpuContext->fpr[9] + lfd fp10, fpuContext->fpr[10] + lfd fp11, fpuContext->fpr[11] + lfd fp12, fpuContext->fpr[12] + lfd fp13, fpuContext->fpr[13] + lfd fp14, fpuContext->fpr[14] + lfd fp15, fpuContext->fpr[15] + lfd fp16, fpuContext->fpr[16] + lfd fp17, fpuContext->fpr[17] + lfd fp18, fpuContext->fpr[18] + lfd fp19, fpuContext->fpr[19] + lfd fp20, fpuContext->fpr[20] + lfd fp21, fpuContext->fpr[21] + lfd fp22, fpuContext->fpr[22] + lfd fp23, fpuContext->fpr[23] + lfd fp24, fpuContext->fpr[24] + lfd fp25, fpuContext->fpr[25] + lfd fp26, fpuContext->fpr[26] + lfd fp27, fpuContext->fpr[27] + lfd fp28, fpuContext->fpr[28] + lfd fp29, fpuContext->fpr[29] + lfd fp30, fpuContext->fpr[30] + lfd fp31, fpuContext->fpr[31] +_return: + blr + // clang-format on +} + +static asm void __OSSaveFPUContext(register u32, register u32, register OSContext* fpuContext) { + // clang-format off + nofralloc + + lhz r3, fpuContext->state + ori r3, r3, 1 + sth r3, fpuContext->state + + stfd fp0, fpuContext->fpr[0] + stfd fp1, fpuContext->fpr[1] + stfd fp2, fpuContext->fpr[2] + stfd fp3, fpuContext->fpr[3] + stfd fp4, fpuContext->fpr[4] + stfd fp5, fpuContext->fpr[5] + stfd fp6, fpuContext->fpr[6] + stfd fp7, fpuContext->fpr[7] + stfd fp8, fpuContext->fpr[8] + stfd fp9, fpuContext->fpr[9] + stfd fp10, fpuContext->fpr[10] + stfd fp11, fpuContext->fpr[11] + stfd fp12, fpuContext->fpr[12] + stfd fp13, fpuContext->fpr[13] + stfd fp14, fpuContext->fpr[14] + stfd fp15, fpuContext->fpr[15] + stfd fp16, fpuContext->fpr[16] + stfd fp17, fpuContext->fpr[17] + stfd fp18, fpuContext->fpr[18] + stfd fp19, fpuContext->fpr[19] + stfd fp20, fpuContext->fpr[20] + stfd fp21, fpuContext->fpr[21] + stfd fp22, fpuContext->fpr[22] + stfd fp23, fpuContext->fpr[23] + stfd fp24, fpuContext->fpr[24] + stfd fp25, fpuContext->fpr[25] + stfd fp26, fpuContext->fpr[26] + stfd fp27, fpuContext->fpr[27] + stfd fp28, fpuContext->fpr[28] + stfd fp29, fpuContext->fpr[29] + stfd fp30, fpuContext->fpr[30] + stfd fp31, fpuContext->fpr[31] + + mffs fp0 + stfd fp0, OS_CONTEXT_FPSCR(fpuContext) + + lfd fp0, fpuContext->fpr[0] + + mfspr r3, HID2 + rlwinm. r3, r3, 3, 31, 31 + bc 12, 2, _return + + psq_st fp0, OS_CONTEXT_PSF0(fpuContext), 0, 0 + psq_st fp1, OS_CONTEXT_PSF1(fpuContext), 0, 0 + psq_st fp2, OS_CONTEXT_PSF2(fpuContext), 0, 0 + psq_st fp3, OS_CONTEXT_PSF3(fpuContext), 0, 0 + psq_st fp4, OS_CONTEXT_PSF4(fpuContext), 0, 0 + psq_st fp5, OS_CONTEXT_PSF5(fpuContext), 0, 0 + psq_st fp6, OS_CONTEXT_PSF6(fpuContext), 0, 0 + psq_st fp7, OS_CONTEXT_PSF7(fpuContext), 0, 0 + psq_st fp8, OS_CONTEXT_PSF8(fpuContext), 0, 0 + psq_st fp9, OS_CONTEXT_PSF9(fpuContext), 0, 0 + psq_st fp10, OS_CONTEXT_PSF10(fpuContext), 0, 0 + psq_st fp11, OS_CONTEXT_PSF11(fpuContext), 0, 0 + psq_st fp12, OS_CONTEXT_PSF12(fpuContext), 0, 0 + psq_st fp13, OS_CONTEXT_PSF13(fpuContext), 0, 0 + psq_st fp14, OS_CONTEXT_PSF14(fpuContext), 0, 0 + psq_st fp15, OS_CONTEXT_PSF15(fpuContext), 0, 0 + psq_st fp16, OS_CONTEXT_PSF16(fpuContext), 0, 0 + psq_st fp17, OS_CONTEXT_PSF17(fpuContext), 0, 0 + psq_st fp18, OS_CONTEXT_PSF18(fpuContext), 0, 0 + psq_st fp19, OS_CONTEXT_PSF19(fpuContext), 0, 0 + psq_st fp20, OS_CONTEXT_PSF20(fpuContext), 0, 0 + psq_st fp21, OS_CONTEXT_PSF21(fpuContext), 0, 0 + psq_st fp22, OS_CONTEXT_PSF22(fpuContext), 0, 0 + psq_st fp23, OS_CONTEXT_PSF23(fpuContext), 0, 0 + psq_st fp24, OS_CONTEXT_PSF24(fpuContext), 0, 0 + psq_st fp25, OS_CONTEXT_PSF25(fpuContext), 0, 0 + psq_st fp26, OS_CONTEXT_PSF26(fpuContext), 0, 0 + psq_st fp27, OS_CONTEXT_PSF27(fpuContext), 0, 0 + psq_st fp28, OS_CONTEXT_PSF28(fpuContext), 0, 0 + psq_st fp29, OS_CONTEXT_PSF29(fpuContext), 0, 0 + psq_st fp30, OS_CONTEXT_PSF30(fpuContext), 0, 0 + psq_st fp31, OS_CONTEXT_PSF31(fpuContext), 0, 0 + +_return: + blr + // clang-format on +} + +asm void OSLoadFPUContext(register OSContext* fpuContext) { + // clang-format off + nofralloc + addi r4, fpuContext, 0 + b __OSLoadFPUContext + // clang-format on +} + +asm void OSSaveFPUContext(register OSContext* fpuContext) { + // clang-format off + nofralloc + addi r5, fpuContext, 0 + b __OSSaveFPUContext + // clang-format on +} + +asm void OSSetCurrentContext(register OSContext* context){ + // clang-format off + nofralloc + + addis r4, r0, OS_CACHED_REGION_PREFIX + + stw context, 0x00D4(r4) + + clrlwi r5, context, 2 + stw r5, 0x00C0(r4) + + lwz r5, 0x00D8(r4) + cmpw r5, context + bne _disableFPU + + lwz r6, context->srr1 + ori r6, r6, 0x2000 + stw r6, context->srr1 + mfmsr r6 + ori r6, r6, 2 + mtmsr r6 + blr + +_disableFPU: + lwz r6, context->srr1 + rlwinm r6, r6, 0, 19, 17 + stw r6, context->srr1 + mfmsr r6 + rlwinm r6, r6, 0, 19, 17 + ori r6, r6, 2 + mtmsr r6 + isync + blr + // clang-format on +} + +OSContext* OSGetCurrentContext(void) { + return (OSContext*)__OSCurrentContext; +} + +asm u32 OSSaveContext(register OSContext* context) { + // clang-format off + nofralloc + stmw r13, context->gpr[13] + mfspr r0, GQR1 + stw r0, context->gqr[1] + mfspr r0, GQR2 + stw r0, context->gqr[2] + mfspr r0, GQR3 + stw r0, context->gqr[3] + mfspr r0, GQR4 + stw r0, context->gqr[4] + mfspr r0, GQR5 + stw r0, context->gqr[5] + mfspr r0, GQR6 + stw r0, context->gqr[6] + mfspr r0, GQR7 + stw r0, context->gqr[7] + mfcr r0 + stw r0, context->cr + mflr r0 + stw r0, context->lr + stw r0, context->srr0 + mfmsr r0 + stw r0, context->srr1 + mfctr r0 + stw r0, context->ctr + mfxer r0 + stw r0, context->xer + stw r1, context->gpr[1] + stw r2, context->gpr[2] + li r0, 0x1 + stw r0, context->gpr[3] + li r3, 0 + blr + // clang-format on +} + +extern void __RAS_OSDisableInterrupts_begin(); +extern void __RAS_OSDisableInterrupts_end(); + +asm void OSLoadContext(register OSContext* context) { + // clang-format off + nofralloc + + lis r4,__RAS_OSDisableInterrupts_begin@ha + lwz r6,context->srr0 + addi r5,r4,__RAS_OSDisableInterrupts_begin@l + cmplw r6,r5 + ble _notInRAS + lis r4,__RAS_OSDisableInterrupts_end@ha + addi r0,r4,__RAS_OSDisableInterrupts_end@l + cmplw r6,r0 + bge _notInRAS + stw r5,context->srr0 + +_notInRAS: + + lwz r0, context->gpr[0] + lwz r1, context->gpr[1] + lwz r2, context->gpr[2] + + lhz r4, context->state + rlwinm. r5, r4, 0, 30, 30 + beq notexc + rlwinm r4, r4, 0, 31, 29 + sth r4, context->state + lmw r5, context->gpr[5] + b misc +notexc: + lmw r13, context->gpr[13] +misc: + + lwz r4, context->gqr[1] + mtspr GQR1, r4 + lwz r4, context->gqr[2] + mtspr GQR2, r4 + lwz r4, context->gqr[3] + mtspr GQR3, r4 + lwz r4, context->gqr[4] + mtspr GQR4, r4 + lwz r4, context->gqr[5] + mtspr GQR5, r4 + lwz r4, context->gqr[6] + mtspr GQR6, r4 + lwz r4, context->gqr[7] + mtspr GQR7, r4 + + lwz r4, context->cr + mtcr r4 + lwz r4, context->lr + mtlr r4 + lwz r4, context->ctr + mtctr r4 + lwz r4, context->xer + mtxer r4 + + mfmsr r4 + rlwinm r4, r4, 0, 17, 15 + rlwinm r4, r4, 0, 31, 29 + mtmsr r4 + + lwz r4, context->srr0 + mtsrr0 r4 + lwz r4, context->srr1 + mtsrr1 r4 + + lwz r4, context->gpr[4] + lwz r3, context->gpr[3] + + rfi + // clang-format on +} + +asm u32 OSGetStackPointer() { + // clang-format off + nofralloc + mr r3, r1 + blr + // clang-format on +} + +asm u32 OSSwitchStack(register u32 newsp) { + // clang-format off + nofralloc + mr r5, r1 + mr r1, newsp + mr r3, r5 + blr + // clang-format on +} + +asm int OSSwitchFiber(register u32 pc, register u32 newsp) { + // clang-format off + nofralloc + mflr r0 + mr r5, r1 + stwu r5, -8(newsp) + mr r1, newsp + stw r0, 4(r5) + mtlr pc + blrl + lwz r5, 0(r1) + lwz r0, 4(r5) + mtlr r0 + mr r1, r5 + blr + // clang-format on +} + +void OSClearContext(register OSContext* context) { + context->mode = 0; + context->state = 0; + if (context == __OSFPUContext) + __OSFPUContext = NULL; +} + +asm void OSInitContext(register OSContext* context, register u32 pc, register u32 newsp) { + // clang-format off + nofralloc + + stw pc, OS_CONTEXT_SRR0(context) + stw newsp, OS_CONTEXT_R1(context) + li r11, 0 + ori r11, r11, 0x00008000 | 0x00000020 | 0x00000010 | 0x00000002 | 0x00001000 + stw r11, OS_CONTEXT_SRR1(context) + li r0, 0x0 + stw r0, OS_CONTEXT_CR(context) + stw r0, OS_CONTEXT_XER(context) + + + stw r2, OS_CONTEXT_R2(context) + stw r13, OS_CONTEXT_R13(context) + + stw r0, OS_CONTEXT_R3(context) + stw r0, OS_CONTEXT_R4(context) + stw r0, OS_CONTEXT_R5(context) + stw r0, OS_CONTEXT_R6(context) + stw r0, OS_CONTEXT_R7(context) + stw r0, OS_CONTEXT_R8(context) + stw r0, OS_CONTEXT_R9(context) + stw r0, OS_CONTEXT_R10(context) + stw r0, OS_CONTEXT_R11(context) + stw r0, OS_CONTEXT_R12(context) + + stw r0, OS_CONTEXT_R14(context) + stw r0, OS_CONTEXT_R15(context) + stw r0, OS_CONTEXT_R16(context) + stw r0, OS_CONTEXT_R17(context) + stw r0, OS_CONTEXT_R18(context) + stw r0, OS_CONTEXT_R19(context) + stw r0, OS_CONTEXT_R20(context) + stw r0, OS_CONTEXT_R21(context) + stw r0, OS_CONTEXT_R22(context) + stw r0, OS_CONTEXT_R23(context) + stw r0, OS_CONTEXT_R24(context) + stw r0, OS_CONTEXT_R25(context) + stw r0, OS_CONTEXT_R26(context) + stw r0, OS_CONTEXT_R27(context) + stw r0, OS_CONTEXT_R28(context) + stw r0, OS_CONTEXT_R29(context) + stw r0, OS_CONTEXT_R30(context) + stw r0, OS_CONTEXT_R31(context) + + stw r0, OS_CONTEXT_GQR0(context) + stw r0, OS_CONTEXT_GQR1(context) + stw r0, OS_CONTEXT_GQR2(context) + stw r0, OS_CONTEXT_GQR3(context) + stw r0, OS_CONTEXT_GQR4(context) + stw r0, OS_CONTEXT_GQR5(context) + stw r0, OS_CONTEXT_GQR6(context) + stw r0, OS_CONTEXT_GQR7(context) + + b OSClearContext + // clang-format on +} + +void OSDumpContext(OSContext* context) { + u32 i; + u32* p; + + OSReport("------------------------- Context 0x%08x -------------------------\n", context); + + for (i = 0; i < 16; ++i) { + OSReport("r%-2d = 0x%08x (%14d) r%-2d = 0x%08x (%14d)\n", i, context->gpr[i], + context->gpr[i], i + 16, context->gpr[i + 16], context->gpr[i + 16]); + } + + OSReport("LR = 0x%08x CR = 0x%08x\n", context->lr, context->cr); + OSReport("SRR0 = 0x%08x SRR1 = 0x%08x\n", context->srr0, context->srr1); + + OSReport("\nGQRs----------\n"); + for (i = 0; i < 4; ++i) { + OSReport("gqr%d = 0x%08x \t gqr%d = 0x%08x\n", i, context->gqr[i], i + 4, context->gqr[i + 4]); + } + + if (context->state & OS_CONTEXT_STATE_FPSAVED) { + OSContext* currentContext; + OSContext fpuContext; + BOOL enabled; + + enabled = OSDisableInterrupts(); + currentContext = OSGetCurrentContext(); + OSClearContext(&fpuContext); + OSSetCurrentContext(&fpuContext); + + OSReport("\n\nFPRs----------\n"); + for (i = 0; i < 32; i += 2) { + OSReport("fr%d \t= %d \t fr%d \t= %d\n", i, (u32)context->fpr[i], i + 1, + (u32)context->fpr[i + 1]); + } + OSReport("\n\nPSFs----------\n"); + for (i = 0; i < 32; i += 2) { + OSReport("ps%d \t= 0x%x \t ps%d \t= 0x%x\n", i, (u32)context->psf[i], i + 1, + (u32)context->psf[i + 1]); + } + + OSClearContext(&fpuContext); + OSSetCurrentContext(currentContext); + OSRestoreInterrupts(enabled); + } + + OSReport("\nAddress: Back Chain LR Save\n"); + for (i = 0, p = (u32*)context->gpr[1]; p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) { + OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]); + } +} + +static asm void OSSwitchFPUContext(register __OSException exception, register OSContext* context) { + // clang-format off + nofralloc + mfmsr r5 + ori r5, r5, 0x2000 + mtmsr r5 + isync + lwz r5, OS_CONTEXT_SRR1(context) + ori r5, r5, 0x2000 + mtsrr1 r5 + addis r3, r0, OS_CACHED_REGION_PREFIX + lwz r5, 0x00D8(r3) + stw context, 0x00D8(r3) + cmpw r5, r4 + beq _restoreAndExit + cmpwi r5, 0x0 + beq _loadNewFPUContext + bl __OSSaveFPUContext +_loadNewFPUContext: + bl __OSLoadFPUContext +_restoreAndExit: + lwz r3, OS_CONTEXT_CR(context) + mtcr r3 + lwz r3, OS_CONTEXT_LR(context) + mtlr r3 + lwz r3, OS_CONTEXT_SRR0(context) + mtsrr0 r3 + lwz r3, OS_CONTEXT_CTR(context) + mtctr r3 + lwz r3, OS_CONTEXT_XER(context) + mtxer r3 + lhz r3, context->state + rlwinm r3, r3, 0, 31, 29 + sth r3, context->state + lwz r5, OS_CONTEXT_R5(context) + lwz r3, OS_CONTEXT_R3(context) + lwz r4, OS_CONTEXT_R4(context) + rfi + // clang-format on +} + +void __OSContextInit(void) { + __OSSetExceptionHandler(__OS_EXCEPTION_FLOATING_POINT, OSSwitchFPUContext); + __OSFPUContext = NULL; + DBPrintf("FPU-unavailable handler installed\n"); +} diff --git a/src/Dolphin/os/OSError.c b/src/Dolphin/os/OSError.c new file mode 100644 index 0000000..3859a62 --- /dev/null +++ b/src/Dolphin/os/OSError.c @@ -0,0 +1,360 @@ +#include <dolphin/PPCArch.h> +#include <dolphin/dsp_regs.h> +#include <dolphin/dvd_regs.h> +#include <dolphin/os.h> +#include <stdio.h> + +OSThread* __OSCurrentThread : (OS_BASE_CACHED | 0x00E4); +OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC); +volatile OSContext* __OSFPUContext : (OS_BASE_CACHED | 0x00D8); + +OSErrorHandler __OSErrorTable[OS_ERROR_MAX]; +#define FPSCR_ENABLE (FPSCR_VE | FPSCR_OE | FPSCR_UE | FPSCR_ZE | FPSCR_XE) +u32 __OSFpscrEnableBits = FPSCR_ENABLE; + +__declspec(weak) void OSReport(const char* msg, ...) { + va_list args; + va_start(args, msg); + vprintf(msg, args); + va_end(args); +} + +__declspec(weak) void OSVReport(const char* msg, va_list list) { vprintf(msg, list); } + +__declspec(weak) void OSPanic(const char* file, int line, const char* msg, ...) { + va_list marker; + u32 i; + u32* p; + + OSDisableInterrupts(); + va_start(marker, msg); + vprintf(msg, marker); + va_end(marker); + OSReport(" in \"%s\" on line %d.\n", file, line); + + OSReport("\nAddress: Back Chain LR Save\n"); + for (i = 0, p = (u32*)OSGetStackPointer(); p && (u32)p != 0xffffffff && i++ < 16; p = (u32*)*p) { + OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]); + } + + PPCHalt(); +} + +#ifdef FULL_FRANK +OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler) { + OSErrorHandler oldHandler; + BOOL enabled; + + enabled = OSDisableInterrupts(); + oldHandler = __OSErrorTable[error]; + __OSErrorTable[error] = handler; + + if (error == OS_ERROR_FPE) { + u32 msr; + u32 fpscr; + OSThread* thread; + + msr = PPCMfmsr(); + PPCMtmsr(msr | MSR_FP); + fpscr = PPCMffpscr(); + if (handler) { + for (thread = __OSActiveThreadQueue.head; thread; thread = thread->linkActive.next) { + thread->context.srr1 |= MSR_FE0 | MSR_FE1; + if ((thread->context.state & OS_CONTEXT_STATE_FPSAVED) == 0) { + int i; + thread->context.state |= OS_CONTEXT_STATE_FPSAVED; + for (i = 0; i < 32; ++i) { + *(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL; + *(u64*)&thread->context.psf[i] = (u64)0xffffffffffffffffLL; + } + thread->context.fpscr = FPSCR_NI; + } + thread->context.fpscr |= __OSFpscrEnableBits & FPSCR_ENABLE; + thread->context.fpscr &= + ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | FPSCR_VXSNAN | + FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | FPSCR_ZX | FPSCR_UX | + FPSCR_OX | FPSCR_FX | FPSCR_FI); + } + fpscr |= __OSFpscrEnableBits & FPSCR_ENABLE; + msr |= MSR_FE0 | MSR_FE1; + } else { + for (thread = __OSActiveThreadQueue.head; thread; thread = thread->linkActive.next) { + thread->context.srr1 &= ~(MSR_FE0 | MSR_FE1); + thread->context.fpscr &= ~FPSCR_ENABLE; + thread->context.fpscr &= + ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | FPSCR_VXSNAN | + FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | FPSCR_ZX | FPSCR_UX | + FPSCR_OX | FPSCR_FX | FPSCR_FI); + } + fpscr &= ~FPSCR_ENABLE; + msr &= ~(MSR_FE0 | MSR_FE1); + } + + fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | FPSCR_VXSNAN | + FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | FPSCR_ZX | FPSCR_UX | + FPSCR_OX | FPSCR_FX | FPSCR_FI); + + PPCMtfpscr(fpscr); + PPCMtmsr(msr); + } + + OSRestoreInterrupts(enabled); + return oldHandler; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level 0 +#pragma optimizewithasm off +asm OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler) { + nofralloc + mflr r0 + stw r0, 4(r1) + stwu r1, -0x30(r1) + stw r31, 0x2c(r1) + stw r30, 0x28(r1) + stw r29, 0x24(r1) + addi r29, r3, 0 + stw r28, 0x20(r1) + addi r28, r4, 0 + bl OSDisableInterrupts + lis r4, __OSErrorTable@ha + rlwinm r5, r29, 2, 0xe, 0x1d + addi r0, r4, __OSErrorTable@l + clrlwi r6, r29, 0x10 + add r4, r0, r5 + lwz r30, 0(r4) + cmplwi r6, 0x10 + mr r29, r3 + stw r28, 0(r4) + bne lbl_8037FD44 + bl PPCMfmsr + addi r31, r3, 0 + ori r3, r31, 0x2000 + bl PPCMtmsr + bl PPCMffpscr + cmplwi r28, 0 + beq lbl_8037FCD8 + lis r5, __OSActiveThreadQueue@ha + lis r4, 0x6005F8FF@ha + lwz r6, __OSActiveThreadQueue@l(r5) + addi r4, r4, 0x6005F8FF@l + b lbl_8037FCBC +lbl_8037FBD8: + lwz r0, 0x19c(r6) + ori r0, r0, 0x900 + stw r0, 0x19c(r6) + lhz r5, 0x1a2(r6) + clrlwi. r0, r5, 0x1f + bne lbl_8037FC98 + ori r5, r5, 1 + li r0, 4 + sth r5, 0x1a2(r6) + mtctr r0 + addi r5, r6, 0 +lbl_8037FC04: + li r0, -1 + stw r0, 0x94(r5) + stw r0, 0x90(r5) + stw r0, 0x1cc(r5) + stw r0, 0x1c8(r5) + stw r0, 0x9c(r5) + stw r0, 0x98(r5) + stw r0, 0x1d4(r5) + stw r0, 0x1d0(r5) + stw r0, 0xa4(r5) + stw r0, 0xa0(r5) + stw r0, 0x1dc(r5) + stw r0, 0x1d8(r5) + stw r0, 0xac(r5) + stw r0, 0xa8(r5) + stw r0, 0x1e4(r5) + stw r0, 0x1e0(r5) + stw r0, 0xb4(r5) + stw r0, 0xb0(r5) + stw r0, 0x1ec(r5) + stw r0, 0x1e8(r5) + stw r0, 0xbc(r5) + stw r0, 0xb8(r5) + stw r0, 0x1f4(r5) + stw r0, 0x1f0(r5) + stw r0, 0xc4(r5) + stw r0, 0xc0(r5) + stw r0, 0x1fc(r5) + stw r0, 0x1f8(r5) + stw r0, 0xcc(r5) + stw r0, 0xc8(r5) + stw r0, 0x204(r5) + stw r0, 0x200(r5) + addi r5, r5, 0x40 + bdnz lbl_8037FC04 + li r0, 4 + stw r0, 0x194(r6) +lbl_8037FC98: + lwz r0, __OSFpscrEnableBits + lwz r5, 0x194(r6) + rlwinm r0, r0, 0, 0x18, 0x1c + or r0, r5, r0 + stw r0, 0x194(r6) + lwz r0, 0x194(r6) + and r0, r0, r4 + stw r0, 0x194(r6) + lwz r6, 0x2fc(r6) +lbl_8037FCBC: + cmplwi r6, 0 + bne lbl_8037FBD8 + lwz r0, __OSFpscrEnableBits + ori r31, r31, 0x900 + rlwinm r0, r0, 0, 0x18, 0x1c + or r3, r3, r0 + b lbl_8037FD2C +lbl_8037FCD8: + lis r5, __OSActiveThreadQueue@ha + lis r4, 0x6005F8FF@ha + lwz r6, __OSActiveThreadQueue@l(r5) + addi r4, r4, 0x6005F8FF@l + li r5, -2305 + b lbl_8037FD18 +lbl_8037FCF0: + lwz r0, 0x19c(r6) + and r0, r0, r5 + stw r0, 0x19c(r6) + lwz r0, 0x194(r6) + rlwinm r0, r0, 0, 0x1d, 0x17 + stw r0, 0x194(r6) + lwz r0, 0x194(r6) + and r0, r0, r4 + stw r0, 0x194(r6) + lwz r6, 0x2fc(r6) +lbl_8037FD18: + cmplwi r6, 0 + bne lbl_8037FCF0 + li r0, -2305 + rlwinm r3, r3, 0, 0x1d, 0x17 + and r31, r31, r0 +lbl_8037FD2C: + lis r4, 0x6005F8FF@ha + addi r0, r4, 0x6005F8FF@l + and r3, r3, r0 + bl PPCMtfpscr + mr r3, r31 + bl PPCMtmsr +lbl_8037FD44: + mr r3, r29 + bl OSRestoreInterrupts + mr r3, r30 + lwz r0, 0x34(r1) + lwz r31, 0x2c(r1) + lwz r30, 0x28(r1) + lwz r29, 0x24(r1) + lwz r28, 0x20(r1) + addi r1, r1, 0x30 + mtlr r0 + blr +} +#pragma pop +/* clang-format on */ +#endif +void __OSUnhandledException(__OSException exception, OSContext* context, u32 dsisr, u32 dar) { + OSTime now; + + now = OSGetTime(); + + if (!(context->srr1 & MSR_RI)) { + OSReport("Non-recoverable Exception %d", exception); + } else { + if (exception == __OS_EXCEPTION_PROGRAM && (context->srr1 & (0x80000000 >> 11)) && + __OSErrorTable[OS_ERROR_FPE] != 0) { + u32 fpscr; + u32 msr; + + exception = OS_ERROR_FPE; + + msr = PPCMfmsr(); + PPCMtmsr(msr | MSR_FP); + + if (__OSFPUContext) { + OSSaveFPUContext((OSContext*)__OSFPUContext); + } + + fpscr = PPCMffpscr(); + fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | FPSCR_VXSNAN | + FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | FPSCR_ZX | FPSCR_UX | + FPSCR_OX | FPSCR_FX | FPSCR_FI); + PPCMtfpscr(fpscr); + + PPCMtmsr(msr); + + if (__OSFPUContext == context) { + OSDisableScheduler(); + __OSErrorTable[exception](exception, context, dsisr, dar); + context->srr1 &= ~MSR_FP; + __OSFPUContext = NULL; + + context->fpscr &= ~(FPSCR_VXVC | FPSCR_VXIMZ | FPSCR_VXZDZ | FPSCR_VXIDI | FPSCR_VXISI | + FPSCR_VXSNAN | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI | FPSCR_XX | + FPSCR_ZX | FPSCR_UX | FPSCR_OX | FPSCR_FX | FPSCR_FI); + OSEnableScheduler(); + __OSReschedule(); + } else { + context->srr1 &= ~MSR_FP; + __OSFPUContext = NULL; + } + + OSLoadContext(context); + } + + if (__OSErrorTable[exception]) { + OSDisableScheduler(); + __OSErrorTable[exception](exception, context, dsisr, dar); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + + if (exception == OS_ERROR_DECREMENTER) { + OSLoadContext(context); + } + + OSReport("Unhandled Exception %d", exception); + } + + OSReport("\n"); + OSDumpContext(context); + OSReport("\nDSISR = 0x%08x DAR = 0x%08x\n", dsisr, dar); + OSReport("TB = 0x%016llx\n", now); + + switch (exception) { + case __OS_EXCEPTION_DSI: + OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access " + "invalid address 0x%x (read from DAR)\n", + context->srr0, dar); + break; + case __OS_EXCEPTION_ISI: + OSReport("\nAttempted to fetch instruction from invalid address 0x%x " + "(read from SRR0)\n", + context->srr0); + break; + case __OS_EXCEPTION_ALIGNMENT: + OSReport("\nInstruction at 0x%x (read from SRR0) attempted to access " + "unaligned address 0x%x (read from DAR)\n", + context->srr0, dar); + break; + case __OS_EXCEPTION_PROGRAM: + OSReport("\nProgram exception : Possible illegal instruction/operation " + "at or around 0x%x (read from SRR0)\n", + context->srr0, dar); + break; + case OS_ERROR_PROTECTION: + OSReport("\n"); + OSReport("AI DMA Address = 0x%04x%04x\n", __DSPRegs[0x00000018], __DSPRegs[0x00000018 + 1]); + OSReport("ARAM DMA Address = 0x%04x%04x\n", __DSPRegs[0x00000010], __DSPRegs[0x00000010 + 1]); + OSReport("DI DMA Address = 0x%08x\n", __DIRegs[0x00000005]); + break; + } + + OSReport("\nLast interrupt (%d): SRR0 = 0x%08x TB = 0x%016llx\n", __OSLastInterrupt, + __OSLastInterruptSrr0, __OSLastInterruptTime); + + PPCHalt(); +} diff --git a/src/Dolphin/os/OSFont.c b/src/Dolphin/os/OSFont.c new file mode 100644 index 0000000..34224bf --- /dev/null +++ b/src/Dolphin/os/OSFont.c @@ -0,0 +1,757 @@ +#include <OS.h> +#include <gx.h> +#include <vi.h> + +#define ROM_FONT_SJIS_START ((void*)0x001AFF00) +#define ROM_FONT_SJIS_SIZE 0x0004D000 +#define ROM_FONT_ANSI_START ((void*)0x001FCF00) +#define ROM_FONT_ANSI_SIZE 0x00003000 + +typedef const u8* (*ParseStringFunc)(u16, const u8*, OSFontData**, u32*); + +static u16 FontEncode = 0xFFFF; + +static OSFontData* FontDataAnsi; +static OSFontData* FontDataSjis; +static BOOL FixedPitch; +static ParseStringFunc ParseString; + +extern u16 HankakuToCode[]; +extern u16 Zenkaku2Code[]; + +static const u8* ParseStringS(u16, const u8*, OSFontData**, u32*); +static const u8* ParseStringW(u16, const u8*, OSFontData**, u32*); + +static BOOL IsSjisLeadByte(u8 ch) { + return (0x81 <= ch && ch <= 0x9F) || (0xE0 <= ch && ch <= 0xFC); +} + +static BOOL IsSjisTrailByte(u8 ch) { + return (0x40 <= ch && ch <= 0xFC) && (ch != 0x7F); +} + +static u32 GetFontCode(u16 encode, u16 code) { + u32 tmp; + s32 trail; + + if (encode == OS_FONT_ENCODE_SJIS) { + if (code >= 0x20 && code <= 0xDF) { + return HankakuToCode[code - 0x20]; + } else if (code > 0x889E && code <= 0x9872) { + tmp = ((code >> 8) - 0x88) * 0xBC; + trail = code & 0xFF; + + if (!IsSjisTrailByte(trail)) { + return 0; + } + + trail -= 0x40; + if (trail >= 0x40) { + trail--; + } + + return tmp + trail + 0x2BE; + } else if (code >= 0x8140 && code < 0x879E) { + tmp = ((code >> 8) - 0x81) * 0xBC; + trail = code & 0xFF; + + if (!IsSjisTrailByte(trail)) { + return 0; + } + + trail -= 0x40; + if (trail >= 0x40) { + trail--; + } + + return Zenkaku2Code[tmp + trail]; + } + } else if (code > 0x20 && code <= 0xFF) { + return code - 0x20; + } + + return 0; +} + +// 'Yay0' decompression (See YAGCD sections 16.1.1, 16.1.2) +static void Decode(u8* src, u8* dst) { + int j; + s32 linkOfs; + s32 chunkPos; + int i; + s32 chunksOfs; + u32 maskTblPos; + s32 expandSize; + s32 linkTblOfs; + s32 count; + u32 maskBits; + u32 mask; + + expandSize = *(s32*)(src + 0x4); + linkTblOfs = *(s32*)(src + 0x8); + chunksOfs = *(s32*)(src + 0xC); + + i = 0; + maskBits = 0; + maskTblPos = 16; + + do { + // Get next mask + if (maskBits == 0) { + mask = *(u32*)(src + maskTblPos); + maskTblPos += sizeof(u32); + maskBits = sizeof(u32) * 8; + } + + // Non-linked chunk + if (mask & 0x80000000) { + dst[i++] = src[chunksOfs++]; + } + // Linked chunk + else { + // Read offset from link table + linkOfs = src[linkTblOfs] << 8 | src[linkTblOfs + 1]; + linkTblOfs += sizeof(u16); + + // Apply offset + chunkPos = i - (linkOfs & 0x0FFF); + count = linkOfs >> 12; + if (count == 0) { + count = src[chunksOfs++] + 0x12; + } else { + count += 2; + } + + // Copy chunk + for (j = 0; j < count; j++, i++, chunkPos++) { + dst[i] = dst[chunkPos - 1]; + } + } + + // Prepare next mask bit + mask <<= 1; + maskBits--; + } while (i < expandSize); +} + +static u32 GetFontSize(const u8* font) { + if (font[0] == 'Y' && font[1] == 'a' && font[2] == 'y') { + return *(u32*)(font + 0x4); + } + + return 0; +} + +u16 OSGetFontEncode(void) { + if (FontEncode != 0xFFFF) { + return FontEncode; + } + + switch (*(u32*)OSPhysicalToCached(0xcc)) { + case VI_NTSC: + FontEncode = ((__VIRegs[55] & 2) != 0) + ? OS_FONT_ENCODE_SJIS + : OS_FONT_ENCODE_ANSI; + break; + case VI_PAL: + case VI_MPAL: + case VI_DEBUG: + case VI_DEBUG_PAL: + case VI_EURGB60: + default: + FontEncode = OS_FONT_ENCODE_ANSI; + } + + ParseString = ParseStringS; + + return FontEncode; +} + +u16 OSSetFontEncode(u16 encode) { + u16 old = OSGetFontEncode(); + + if (encode <= OS_FONT_ENCODE_UTF32) { + FontEncode = encode; + + if (encode >= OS_FONT_ENCODE_UTF8 && encode <= OS_FONT_ENCODE_UTF32) { + ParseString = ParseStringW; + } + } + + return old; +} + +static void ReadROM(void* dst, s32 size, const void* src) { + s32 blockSize; + + while (size > 0) { + blockSize = (size <= 256) ? size : 256; + size -= blockSize; + + while (!__OSReadROM(dst, blockSize, src)) { + ; + } + + src = (u8*)src + blockSize; + dst = (u8*)dst + blockSize; + } +} + +static u32 ReadFont(void* dst, u16 encode, OSFontData* font) { + u8* tex; + int i; + u32 code; + u32 size; + s32 sheet; + s32 numRestTex; + s32 row; + s32 col; + u8* tmp; + + if (encode == OS_FONT_ENCODE_SJIS) { + ReadROM(dst, ROM_FONT_SJIS_SIZE, ROM_FONT_SJIS_START); + } else { + ReadROM(dst, ROM_FONT_ANSI_SIZE, ROM_FONT_ANSI_START); + } + + size = GetFontSize(dst); + if (size == 0) { + return 0; + } + + Decode(dst, (u8*)font); + + if (encode == OS_FONT_ENCODE_SJIS) { + u16 sp28[] = {0x2ABE, 0x003D, 0x003D, 0x003D}; + + /** + * Find 'T' texture (See OSGetFontTexture) + */ + code = GetFontCode(encode, 'T'); + // Font sheet on which the texture resides + sheet = (s32)code / (font->texNumCol * font->texNumRow); + // Number of succeeding textures on the sheet + numRestTex = code - (sheet * (font->texNumCol * font->texNumRow)); + // Texture position on sheet + row = numRestTex / font->texNumCol; + col = numRestTex - row * font->texNumCol; + // Texture position + row *= font->cellHeight; + col *= font->cellWidth; + // Font code texture + tex = (u8*)font + font->fontSheetOfs; + tex += sheet * font->texSize / 2; + + // Editing the texture at runtime? + for (i = 4; i < 8; i++) { + tmp = tex + (((font->texWidth / 8) * 32) / 2) * ((row + i) / 8); + tmp += (col / 8) * 16; + tmp += ((row + i) % 8) * 2; + tmp += (col % 8) / 4; + *(u16*)tmp = sp28[i - 4]; + } + } + + return size; +} + +u32 OSLoadFont(OSFontData* font, void* dst) { + u32 size; + + switch (OSGetFontEncode()) { + case OS_FONT_ENCODE_ANSI: + FontDataAnsi = font; + size = ReadFont(dst, OS_FONT_ENCODE_ANSI, FontDataAnsi); + break; + case OS_FONT_ENCODE_SJIS: + FontDataSjis = font; + size = ReadFont(dst, OS_FONT_ENCODE_SJIS, FontDataSjis); + break; + case OS_FONT_ENCODE_UTF8: + case OS_FONT_ENCODE_UTF16: + case OS_FONT_ENCODE_UTF32: + FontDataAnsi = font; + size = ReadFont(dst, OS_FONT_ENCODE_ANSI, FontDataAnsi); + if (size == 0) { + break; + } + + FontDataSjis = (OSFontData*)((u8*)FontDataAnsi + size); + size += ReadFont(dst, OS_FONT_ENCODE_SJIS, FontDataSjis); + break; + case OS_FONT_ENCODE_2: + default: + size = 0; + break; + } + + return size; +} + +static const u8* ParseStringS(u16 encode, const u8* str, OSFontData** fontOut, + u32* codeOut) { + OSFontData* font; + u16 code = 0; + + switch (encode) { + case OS_FONT_ENCODE_ANSI: + font = FontDataAnsi; + code = *str; + if (code != 0) { + str++; + } + break; + case OS_FONT_ENCODE_SJIS: + font = FontDataSjis; + code = *str; + if (code == 0) { + break; + } + str++; + + if (IsSjisLeadByte(code) && IsSjisTrailByte(*str)) { + code = (code << 8 | *str++); + } + break; + } + + *fontOut = font; + *codeOut = GetFontCode(encode, code); + + return str; +} + +static const u8* ParseStringW(u16 encode, const u8* str, OSFontData** fontOut, + u32* codeOut) { + OSFontData* font; + u16 code = 0; + u32 utf32 = 0; + + switch (encode) { + case OS_FONT_ENCODE_ANSI: + font = FontDataAnsi; + code = *str; + if (code != 0) { + str++; + } + break; + case OS_FONT_ENCODE_SJIS: + font = FontDataSjis; + code = *str; + if (code == 0) { + break; + } + str++; + + if (IsSjisLeadByte(code) && IsSjisTrailByte(*str)) { + code = (code << 8 | *str++); + } + break; + case OS_FONT_ENCODE_UTF8: + str = (u8 *)OSUTF8to32(str, &utf32); + break; + case OS_FONT_ENCODE_UTF16: + str = (const u8*)OSUTF16to32((const u16*)str, &utf32); + break; + case OS_FONT_ENCODE_UTF32: + utf32 = *(u32*)str; + if (utf32 != 0) { + str += sizeof(u32); + } + break; + } + + if (utf32 != 0) { + encode = OS_FONT_ENCODE_ANSI; + font = FontDataAnsi; + code = OSUTF32toANSI(utf32); + + if (code == 0 || (FixedPitch && utf32 <= 0x7F)) { + code = OSUTF32toSJIS(utf32); + if (code != 0) { + encode = OS_FONT_ENCODE_SJIS; + font = FontDataSjis; + } + } + } + + *fontOut = font; + *codeOut = GetFontCode(encode, code); + + return str; +} + +const char* OSGetFontTexel(const char* str, void* dst, s32 xOfs, s32 arg3, + u32* widthOut) { + OSFontData* font; + s32 numRestTex; + u8* local_24; + s32 row; + u8* local_20; + s32 col; + s32 local_48; + u32 code; + int j; + int i; + u32 sheet; + u8* local_4C; + u8* font_u8; + u8* tex; + s32 local_44; + + str = (const char*)ParseString(OSGetFontEncode(), (const u8*)str, &font, + &code); + local_4C = (u8*)font + sizeof(OSFontData); + + /** + * Find font code texture (See OSGetFontTexture) + */ + // Font sheet on which the texture resides + sheet = (s32)code / (font->texNumCol * font->texNumRow); + // Number of succeeding textures on the sheet + numRestTex = code - (sheet * (font->texNumCol * font->texNumRow)); + // Texture position on sheet + row = numRestTex / font->texNumCol; + col = numRestTex - row * font->texNumCol; + // Texture position + row *= font->cellHeight; + col *= font->cellWidth; + // Font code texture + tex = (u8*)font + font->fontSheetOfs; + tex += sheet * font->texSize / 2; + + for (i = 0; i < font->cellHeight; i++) { + for (j = 0; j < font->cellWidth; j++) { + local_20 = + tex + (((font->texWidth / 8) * 32) / 2) * ((row + i) / 8); + local_20 += ((col + j) / 8) * 16; + local_20 += ((row + i) % 8) * 2; + local_20 += ((col + j) % 8) / 4; + + local_44 = (col + j) % 4; + + local_24 = (u8*)dst + ((i / 8) * (((arg3 * 4) / 8) * 32)); + local_24 += (((xOfs + j) / 8) * 32); + local_24 += ((i % 8) * 4); + local_24 += ((xOfs + j) % 8) / 2; + + local_48 = (xOfs + j) % 2; + + *local_24 |= + (u8)(local_4C[(*local_20 >> (6 - (local_44 * 2))) & 3] & + (local_48 != 0 ? 0x0F : 0xF0)); + } + } + + if (widthOut != NULL) { + // TODO: Permuter fake(?)match + font_u8 = (u8*)font; + *widthOut = (font_u8 + font->charWidthTblOfs)[code]; + } + + return str; +} + +static void ExpandFontSheet(const OSFontData* font, u8* src, u8* dst) { + int i; + const u8* tmp = (const u8*)font + sizeof(OSFontData); + + if (font->texFmt == GX_TF_I4) { + for (i = (s32)font->fontSheetSize / 2 - 1; i >= 0; i--) { + dst[i * 2 + 0] = + tmp[src[i] >> 6 & 3] & 0xF0 | tmp[src[i] >> 4 & 3] & 0x0F; + dst[i * 2 + 1] = + tmp[src[i] >> 2 & 3] & 0xF0 | tmp[src[i] >> 0 & 3] & 0x0F; + } + } else if (font->texFmt == GX_TF_IA4) { + for (i = (s32)font->fontSheetSize / 4 - 1; i >= 0; i--) { + dst[i * 4 + 0] = tmp[src[i] >> 6 & 3]; + dst[i * 4 + 1] = tmp[src[i] >> 4 & 3]; + dst[i * 4 + 2] = tmp[src[i] >> 2 & 3]; + dst[i * 4 + 3] = tmp[src[i] >> 0 & 3]; + } + } + + DCStoreRange(dst, font->fontSheetSize); +} + +BOOL OSInitFont(OSFontData* font) { + u8* sheets; + + switch (OSGetFontEncode()) { + case OS_FONT_ENCODE_ANSI: + FontDataAnsi = font; + if (ReadFont((u8*)font + 0x1D120, OS_FONT_ENCODE_ANSI, FontDataAnsi) == + 0) { + return FALSE; + } + + sheets = (u8*)FontDataAnsi + FontDataAnsi->fontSheetOfs; + FontDataAnsi->fontSheetOfs = ROUND_UP(FontDataAnsi->fontSheetOfs, 32); + ExpandFontSheet(FontDataAnsi, sheets, + (u8*)FontDataAnsi + FontDataAnsi->fontSheetOfs); + break; + case OS_FONT_ENCODE_SJIS: + FontDataSjis = font; + if (ReadFont((u8*)font + 0xD3F00, OS_FONT_ENCODE_SJIS, FontDataSjis) == + 0) { + return FALSE; + } + + sheets = (u8*)FontDataSjis + FontDataSjis->fontSheetOfs; + FontDataSjis->fontSheetOfs = ROUND_UP(FontDataSjis->fontSheetOfs, 32); + ExpandFontSheet(FontDataSjis, sheets, + (u8*)FontDataSjis + FontDataSjis->fontSheetOfs); + break; + case OS_FONT_ENCODE_2: + break; + case OS_FONT_ENCODE_UTF8: + case OS_FONT_ENCODE_UTF16: + case OS_FONT_ENCODE_UTF32: + FontDataAnsi = font; + if (ReadFont((u8*)font + 0xF4020, OS_FONT_ENCODE_ANSI, FontDataAnsi) == + 0) { + return FALSE; + } + + sheets = (u8*)FontDataAnsi + FontDataAnsi->fontSheetOfs; + FontDataAnsi->fontSheetOfs = ROUND_UP(FontDataAnsi->fontSheetOfs, 32); + ExpandFontSheet(FontDataAnsi, sheets, + (u8*)FontDataAnsi + FontDataAnsi->fontSheetOfs); + + FontDataSjis = (OSFontData*)((u8*)FontDataAnsi + 0x20120); + if (ReadFont((u8*)font + 0xF4020, OS_FONT_ENCODE_SJIS, FontDataSjis) == + 0) { + return FALSE; + } + + sheets = (u8*)FontDataSjis + FontDataSjis->fontSheetOfs; + FontDataSjis->fontSheetOfs = ROUND_UP(FontDataSjis->fontSheetOfs, 32); + ExpandFontSheet(FontDataSjis, sheets, + (u8*)FontDataSjis + FontDataSjis->fontSheetOfs); + break; + } + + return TRUE; +} + +const char* OSGetFontTexture(const char* str, void** texOut, u32* xOut, + u32* yOut, u32* widthOut) { + OSFontData* font; + s32 numRestTex; + u8* font_u8; + u32 code; + u32 sheet; + u32 row; + u32 col; + u32 tmp; + + str = (const char*)ParseString(OSGetFontEncode(), (const u8*)str, &font, + &code); + + // Font sheet on which the texture resides + sheet = (s32)code / (font->texNumCol * font->texNumRow); + // Font code texture + *texOut = (font->texSize * sheet) + ((u8*)font + font->fontSheetOfs); + + // Number of succeeding textures on the sheet + // TODO: Permuter fake(?)match + tmp = font->texNumRow; + numRestTex = code - (sheet * (font->texNumCol * tmp)); + + // Sheet row on which the texure resides + row = numRestTex / font->texNumCol; + // Sheet column on which the texture resides + col = numRestTex - row * font->texNumCol; + + // Texture position + *xOut = col * font->cellWidth; + *yOut = row * font->cellHeight; + + if (widthOut != NULL) { + // TODO: Permuter fake(?)match + font_u8 = (u8*)font; + *widthOut = (font_u8 + font->charWidthTblOfs)[code]; + } + + return str; +} + +const char* OSGetFontWidth(const char* str, u32* widthOut) { + OSFontData* font; + u8* font_u8; + u32 code; + + str = (const char*)ParseString(OSGetFontEncode(), (const u8*)str, &font, + &code); + + if (widthOut != NULL) { + // TODO: Permuter fake(?)match + font_u8 = (u8*)font; + *widthOut = (font_u8 + font->charWidthTblOfs)[code]; + } + + return str; +} + +static u16 HankakuToCode[] = { + 0x020C, 0x020D, 0x020E, 0x020F, 0x0210, 0x0211, 0x0212, 0x0213, 0x0214, + 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021A, 0x021B, 0x021C, 0x021D, + 0x021E, 0x021F, 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0226, + 0x0227, 0x0228, 0x0229, 0x022A, 0x022B, 0x022C, 0x022D, 0x022E, 0x022F, + 0x0230, 0x0231, 0x0232, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237, 0x0238, + 0x0239, 0x023A, 0x023B, 0x023C, 0x023D, 0x023E, 0x023F, 0x0240, 0x0241, + 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024A, + 0x024B, 0x024C, 0x024D, 0x024E, 0x024F, 0x0250, 0x0251, 0x0252, 0x0253, + 0x0254, 0x0255, 0x0256, 0x0257, 0x0258, 0x0259, 0x025A, 0x025B, 0x025C, + 0x025D, 0x025E, 0x025F, 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, + 0x0266, 0x0267, 0x0268, 0x0269, 0x026A, 0x020C, 0x020C, 0x020C, 0x020C, + 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, + 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, + 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, 0x020C, + 0x020C, 0x020C, 0x020C, 0x026B, 0x026C, 0x026D, 0x026E, 0x026F, 0x0270, + 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, 0x0279, + 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F, 0x0280, 0x0281, 0x0282, + 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, 0x028A, 0x028B, + 0x028C, 0x028D, 0x028E, 0x028F, 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, + 0x0295, 0x0296, 0x0297, 0x0298, 0x0299, 0x029A, 0x029B, 0x029C, 0x029D, + 0x029E, 0x029F, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x02A4, 0x02A5, 0x02A6, + 0x02A7, 0x02A8, 0x02A9}; + +static u16 Zenkaku2Code[] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, + 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, 0x0022, 0x0023, + 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, + 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, + 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, + 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, + 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, + 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062, + 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, + 0x0073, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, 0x0080, 0x0081, 0x0082, 0x0083, + 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, + 0x008F, 0x0090, 0x0091, 0x0000, 0x0000, 0x0000, 0x0000, 0x0092, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0093, 0x0094, 0x0095, 0x0096, + 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x009D, 0x009E, 0x009F, 0x00A0, 0x00A1, + 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, + 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, + 0x00B4, 0x00B5, 0x00B6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, + 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, + 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, + 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, + 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, + 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, 0x0100, 0x0101, 0x0102, 0x0103, + 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, + 0x010D, 0x010E, 0x010F, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, + 0x0116, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, + 0x011F, 0x0120, 0x0121, 0x0122, 0x0123, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0125, + 0x0126, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, + 0x012F, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, + 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x013F, 0x0140, + 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, + 0x014A, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F, 0x0150, 0x0151, 0x0152, + 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, + 0x015C, 0x015D, 0x015E, 0x015F, 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, + 0x0165, 0x0166, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, + 0x016E, 0x016F, 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, + 0x0177, 0x0178, 0x0179, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F, 0x0180, + 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187, 0x0188, 0x0189, + 0x018A, 0x018B, 0x018C, 0x018D, 0x018E, 0x018F, 0x0190, 0x0191, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0193, + 0x0194, 0x0195, 0x0196, 0x0197, 0x0198, 0x0199, 0x019A, 0x019B, 0x019C, + 0x019D, 0x019E, 0x019F, 0x01A0, 0x01A1, 0x01A2, 0x01A3, 0x01A4, 0x01A5, + 0x01A6, 0x01A7, 0x01A8, 0x01A9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01AA, 0x01AB, 0x01AC, + 0x01AD, 0x01AE, 0x01AF, 0x01B0, 0x01B1, 0x01B2, 0x01B3, 0x01B4, 0x01B5, + 0x01B6, 0x01B7, 0x01B8, 0x01B9, 0x01BA, 0x01BB, 0x01BC, 0x01BD, 0x01BE, + 0x01BF, 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C5, 0x01C6, 0x01C7, + 0x01C8, 0x01C9, 0x01CA, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x01CB, 0x01CC, 0x01CD, 0x01CE, 0x01CF, 0x01D0, 0x01D1, 0x01D2, 0x01D3, + 0x01D4, 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, + 0x01DD, 0x01DE, 0x01DF, 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E4, 0x01E5, + 0x01E6, 0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x01EC, 0x01ED, 0x01EE, 0x01EF, 0x01F0, 0x01F1, 0x01F2, 0x01F3, + 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, + 0x01FD, 0x01FE, 0x01FF, 0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, + 0x0206, 0x0207, 0x0208, 0x0209, 0x020A, 0x020B, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x020C, 0x020D, 0x020E, 0x020F, 0x0210, + 0x0211, 0x0212, 0x0213, 0x0214, 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, + 0x021A, 0x021B, 0x021C, 0x021D, 0x021E, 0x021F, 0x0220, 0x0221, 0x0222, + 0x0223, 0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022A, 0x022B, + 0x022C, 0x022D, 0x022E, 0x022F, 0x0230, 0x0231, 0x0232, 0x0233, 0x0234, + 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023A, 0x023B, 0x023C, 0x023D, + 0x023E, 0x023F, 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, + 0x0247, 0x0248, 0x0249, 0x024A, 0x024B, 0x024C, 0x024D, 0x024E, 0x024F, + 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, 0x0258, + 0x0259, 0x025A, 0x025B, 0x025C, 0x025D, 0x025E, 0x025F, 0x0260, 0x0261, + 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026A, + 0x026B, 0x026C, 0x026D, 0x026E, 0x026F, 0x0270, 0x0271, 0x0272, 0x0273, + 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, 0x0279, 0x027A, 0x027B, 0x027C, + 0x027D, 0x027E, 0x027F, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, + 0x0286, 0x0287, 0x0288, 0x0289, 0x028A, 0x028B, 0x028C, 0x028D, 0x028E, + 0x028F, 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, + 0x0298, 0x0299, 0x029A, 0x029B, 0x029C, 0x029D, 0x029E, 0x029F, 0x02A0, + 0x02A1, 0x02A2, 0x02A3, 0x02A4, 0x02A5, 0x02A6, 0x02A7, 0x02A8, 0x02A9, + 0x02AA, 0x02AB, 0x02AC, 0x02AD, 0x02AE, 0x02AF, 0x02B0, 0x02B1, 0x02B2, + 0x02B3, 0x02B4, 0x02B5, 0x02B6, 0x02B7, 0x02B8, 0x02B9, 0x02BA, 0x02BB, + 0x02BC, 0x02BD, 0x02BE, 0x02BF, 0x02C0, 0x02C1, 0x02C2, 0x02C3, 0x02C4, + 0x02C5, 0x02C6, 0x02C7, 0x02C8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x02C9, 0x02CA, 0x02CB, 0x02CC, 0x02CD, 0x02CE, + 0x02CF, 0x02D0, 0x02D1, 0x02D2, 0x02D3, 0x02D4, 0x02D5, 0x02D6, 0x02D7, + 0x02D8, 0x02D9, 0x02DA, 0x02DB, 0x02DC, 0x02DD, 0x02DE, 0x02DF, 0x02E0, + 0x02E1, 0x02E2, 0x02E3, 0x02E4, 0x02E5, 0x02E6, 0x0000, 0x02E7, 0x02E8, + 0x02E9, 0x02EA, 0x02EB, 0x02EC, 0x02ED, 0x02EE, 0x02EF, 0x02F0, 0x02F1, + 0x02F2, 0x02F3, 0x02F4, 0x02F5, 0x02F6, 0x02F7, 0x02F8, 0x02F9, 0x02FA, + 0x02FB, 0x02FC, 0x02FD, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x02FE, 0x02FF, 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, + 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, + 0x030E, 0x030F, 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, + 0x0317, 0x0318, 0x0319, 0x031A, 0x031B, 0x0000}; diff --git a/src/Dolphin/os/OSInterrupt.c b/src/Dolphin/os/OSInterrupt.c new file mode 100644 index 0000000..30b6e81 --- /dev/null +++ b/src/Dolphin/os/OSInterrupt.c @@ -0,0 +1,433 @@ +#include <dolphin/os.h> + +static asm void ExternalInterruptHandler(register __OSException exception, + register OSContext* context); + +// TODO: Move these to a more appropriate location +vu32 __PIRegs[12] : 0xCC003000; +vu32 __EXIRegs[16] : 0xCC006800; +vu16 __MEMRegs[64] : 0xCC004000; +vu16 __DSPRegs[32] : 0xCC005000; +vu32 __AIRegs[8] : 0xCC006C00; + +extern void __RAS_OSDisableInterrupts_begin(void); +extern void __RAS_OSDisableInterrupts_end(void); + +static __OSInterruptHandler* InterruptHandlerTable; + +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) { + // clang-format off + nofralloc +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 +} +asm BOOL OSEnableInterrupts(void) { + // clang-format off + nofralloc + + mfmsr r3 + ori r4, r3, 0x8000 + mtmsr r4 + rlwinm r3, r3, 17, 31, 31 + blr + // clang-format on +} + +asm BOOL OSRestoreInterrupts(register BOOL level){ + // 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 + // 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 = 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); +} + +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 OSGetInterruptMask(void) { return *(OSInterruptMask*)OSPhysicalToCached(0x00C8); } + +OSInterruptMask OSSetInterruptMask(OSInterruptMask local) { + BOOL enabled; + OSInterruptMask global; + OSInterruptMask prev; + OSInterruptMask mask; + + enabled = OSDisableInterrupts(); + global = *(OSInterruptMask*)OSPhysicalToCached(0x00C4); + prev = *(OSInterruptMask*)OSPhysicalToCached(0x00C8); + mask = (global | prev) ^ local; + *(OSInterruptMask*)OSPhysicalToCached(0x00C8) = local; + while (mask) { + mask = SetInterruptMask(mask, global | local); + } + OSRestoreInterrupts(enabled); + return prev; +} + +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; +} + +volatile OSTime __OSLastInterruptTime; +volatile __OSInterrupt __OSLastInterrupt; +volatile u32 __OSLastInterruptSrr0; + +void __OSDispatchInterrupt(__OSException exception, OSContext* context) { + u32 intsr; + u32 reg; + OSInterruptMask cause; + OSInterruptMask unmasked; + OSInterruptMask* prio; + __OSInterrupt interrupt; + __OSInterruptHandler handler; + intsr = __PIRegs[0]; + intsr &= ~0x00010000; + + if (intsr == 0 || (intsr & __PIRegs[1]) == 0) { + OSLoadContext(context); + } + + cause = 0; + + if (intsr & 0x00000080) { + reg = __MEMRegs[15]; + if (reg & 0x1) + cause |= OS_INTERRUPTMASK_MEM_0; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_MEM_1; + if (reg & 0x4) + cause |= OS_INTERRUPTMASK_MEM_2; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_MEM_3; + if (reg & 0x10) + cause |= OS_INTERRUPTMASK_MEM_ADDRESS; + } + + if (intsr & 0x00000040) { + reg = __DSPRegs[5]; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_DSP_AI; + if (reg & 0x20) + cause |= OS_INTERRUPTMASK_DSP_ARAM; + if (reg & 0x80) + cause |= OS_INTERRUPTMASK_DSP_DSP; + } + + if (intsr & 0x00000020) { + reg = __AIRegs[0]; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_AI_AI; + } + + if (intsr & 0x00000010) { + reg = __EXIRegs[0]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_0_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_0_TC; + if (reg & 0x800) + cause |= OS_INTERRUPTMASK_EXI_0_EXT; + reg = __EXIRegs[5]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_1_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_1_TC; + if (reg & 0x800) + cause |= OS_INTERRUPTMASK_EXI_1_EXT; + reg = __EXIRegs[10]; + if (reg & 0x2) + cause |= OS_INTERRUPTMASK_EXI_2_EXI; + if (reg & 0x8) + cause |= OS_INTERRUPTMASK_EXI_2_TC; + } + + if (intsr & 0x00002000) + cause |= OS_INTERRUPTMASK_PI_HSP; + if (intsr & 0x00001000) + cause |= OS_INTERRUPTMASK_PI_DEBUG; + if (intsr & 0x00000400) + cause |= OS_INTERRUPTMASK_PI_PE_FINISH; + if (intsr & 0x00000200) + cause |= OS_INTERRUPTMASK_PI_PE_TOKEN; + if (intsr & 0x00000100) + cause |= OS_INTERRUPTMASK_PI_VI; + if (intsr & 0x00000008) + cause |= OS_INTERRUPTMASK_PI_SI; + if (intsr & 0x00000004) + cause |= OS_INTERRUPTMASK_PI_DI; + if (intsr & 0x00000002) + cause |= OS_INTERRUPTMASK_PI_RSW; + if (intsr & 0x00000800) + cause |= OS_INTERRUPTMASK_PI_CP; + if (intsr & 0x00000001) + cause |= OS_INTERRUPTMASK_PI_ERROR; + + unmasked = cause & ~(*(OSInterruptMask*)OSPhysicalToCached(0x00C4) | + *(OSInterruptMask*)OSPhysicalToCached(0x00C8)); + if (unmasked) { + for (prio = InterruptPrioTable;; ++prio) { + if (unmasked & *prio) { + interrupt = (__OSInterrupt)__cntlzw(unmasked & *prio); + break; + } + } + + handler = __OSGetInterruptHandler(interrupt); + if (handler) { + if (__OS_INTERRUPT_MEM_ADDRESS < interrupt) { + __OSLastInterrupt = interrupt; + __OSLastInterruptTime = OSGetTime(); + __OSLastInterruptSrr0 = context->srr0; + } + + OSDisableScheduler(); + handler(interrupt, context); + OSEnableScheduler(); + __OSReschedule(); + OSLoadContext(context); + } + } + + OSLoadContext(context); +} + +static asm void ExternalInterruptHandler(register __OSException exception, + register OSContext* context) { +#pragma unused(exception) + // clang-format off + nofralloc + OS_EXCEPTION_SAVE_GPRS(context) + + stwu r1, -8(r1) + b __OSDispatchInterrupt + // clang-format on +} diff --git a/src/Dolphin/os/OSLink.c b/src/Dolphin/os/OSLink.c new file mode 100644 index 0000000..933e55b --- /dev/null +++ b/src/Dolphin/os/OSLink.c @@ -0,0 +1,556 @@ +#include "dolphin/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 + +OSModuleQueue __OSModuleInfoList : (OS_BASE_CACHED | 0x30C8); +const void* __OSStringTable : (OS_BASE_CACHED | 0x30D0); + +#pragma dont_inline on +__declspec(weak) void OSNotifyLink(OSModuleInfo* module) {} + +__declspec(weak) void OSNotifyUnlink(OSModuleInfo* module) {} + +#pragma dont_inline reset + +#define EnqueueTail(queue, moduleInfo, link) \ + do { \ + OSModuleInfo* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (moduleInfo); \ + else \ + __prev->link.next = (moduleInfo); \ + (moduleInfo)->link.prev = __prev; \ + (moduleInfo)->link.next = NULL; \ + (queue)->tail = (moduleInfo); \ + } while (0) + +#define DequeueItem(queue, moduleInfo, link) \ + do { \ + OSModuleInfo* __next; \ + OSModuleInfo* __prev; \ + \ + __next = (moduleInfo)->link.next; \ + __prev = (moduleInfo)->link.prev; \ + \ + if (__next == NULL) \ + (queue)->tail = __prev; \ + else \ + __next->link.prev = __prev; \ + \ + if (__prev == NULL) \ + (queue)->head = __next; \ + else \ + __prev->link.next = __next; \ + } while (0) + +void OSSetStringTable(const void* stringTable) { __OSStringTable = stringTable; } + +static BOOL Relocate(OSModuleHeader* newModule, OSModuleHeader* module) { + OSModuleID idNew; + OSImportInfo* imp; + OSRel* rel; + OSSectionInfo* si; + OSSectionInfo* siFlush; + u32* p; + u32 offset; + u32 x; + + idNew = newModule ? newModule->info.id : 0; + for (imp = (OSImportInfo*)module->impOffset; + imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++) { + if (imp->id == idNew) { + goto Found; + } + } + return FALSE; + +Found: + siFlush = 0; + for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) { + (u8*)p += rel->offset; + if (idNew) { + si = &OSGetSectionInfo(newModule)[rel->section]; + offset = OS_SECTIONINFO_OFFSET(si->offset); + } else { + offset = 0; + } + switch (rel->type) { + case R_PPC_NONE: + break; + case R_PPC_ADDR32: + x = offset + rel->addend; + *p = x; + break; + case R_PPC_ADDR24: + x = offset + rel->addend; + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_ADDR16: + x = offset + rel->addend; + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_LO: + x = offset + rel->addend; + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_HI: + x = offset + rel->addend; + *(u16*)p = (u16)(((x >> 16) & 0xffff)); + break; + case R_PPC_ADDR16_HA: + x = offset + rel->addend; + *(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff); + break; + case R_PPC_ADDR14: + case R_PPC_ADDR14_BRTAKEN: + case R_PPC_ADDR14_BRNTAKEN: + x = offset + rel->addend; + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_PPC_REL24: + x = offset + rel->addend - (u32)p; + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + x = offset + rel->addend - (u32)p; + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_DOLPHIN_NOP: + break; + case R_DOLPHIN_SECTION: + si = &OSGetSectionInfo(module)[rel->section]; + p = (u32*)OS_SECTIONINFO_OFFSET(si->offset); + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0; + break; + default: + OSReport("OSLink: unknown relocation type %3d\n", rel->type); + break; + } + } + + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + + return TRUE; +} + +#if OS_MODULE_VERSION >= 3 +static BOOL Link(OSModuleInfo* newModule, void* bss, BOOL fixed) { + u32 i; + OSSectionInfo* si; + OSModuleHeader* moduleHeader; + OSModuleInfo* moduleInfo; + OSImportInfo* imp; + + moduleHeader = (OSModuleHeader*)newModule; + moduleHeader->bssSection = 0; + + if (OS_MODULE_VERSION < newModule->version || + 2 <= newModule->version && + (moduleHeader->align && (u32)newModule % moduleHeader->align != 0 || + moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)) { + return FALSE; + } + + EnqueueTail(&__OSModuleInfoList, newModule, link); + newModule->sectionInfoOffset += (u32)moduleHeader; + moduleHeader->relOffset += (u32)moduleHeader; + moduleHeader->impOffset += (u32)moduleHeader; + if (3 <= newModule->version) { + moduleHeader->fixSize += (u32)moduleHeader; + } + for (i = 1; i < newModule->numSections; i++) { + si = &OSGetSectionInfo(newModule)[i]; + if (si->offset != 0) { + si->offset += (u32)moduleHeader; + } else if (si->size != 0) { + moduleHeader->bssSection = (u8)i; + si->offset = (u32)bss; + 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); + } + } + + if (fixed) { + for (imp = (OSImportInfo*)moduleHeader->impOffset; + imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) { + if (imp->id == 0 || imp->id == newModule->id) { + moduleHeader->impSize = (u32)((u8*)imp - (u8*)moduleHeader->impOffset); + break; + } + } + } + + memset(bss, 0, moduleHeader->bssSize); + + OSNotifyLink(newModule); + + return TRUE; +} + +BOOL OSLink(OSModuleInfo* newModule, void* bss) { return Link(newModule, bss, FALSE); } + +BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss) { + if (OS_MODULE_VERSION < newModule->version || newModule->version < 3) { + return FALSE; + } + return Link(newModule, bss, TRUE); +} +#else +BOOL OSLink(OSModuleInfo* newModule, void* bss) { + u32 i; + OSSectionInfo* si; + OSModuleHeader* moduleHeader; + OSModuleInfo* moduleInfo; + OSImportInfo* imp; + + moduleHeader = (OSModuleHeader*)newModule; + moduleHeader->bssSection = 0; + + if (OS_MODULE_VERSION < newModule->version || + 2 <= newModule->version && + (moduleHeader->align && (u32)newModule % moduleHeader->align != 0 || + moduleHeader->bssAlign && (u32)bss % moduleHeader->bssAlign != 0)) { + return FALSE; + } + + EnqueueTail(&__OSModuleInfoList, newModule, link); + memset(bss, 0, moduleHeader->bssSize); + newModule->sectionInfoOffset += (u32)moduleHeader; + moduleHeader->relOffset += (u32)moduleHeader; + moduleHeader->impOffset += (u32)moduleHeader; + + for (i = 1; i < newModule->numSections; i++) { + si = &OSGetSectionInfo(newModule)[i]; + if (si->offset != 0) { + si->offset += (u32)moduleHeader; + } else if (si->size != 0) { + moduleHeader->bssSection = (u8)i; + si->offset = (u32)bss; + 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(newModule); + + return TRUE; +} +#endif + +static BOOL Undo(OSModuleHeader* newModule, OSModuleHeader* module) { + OSModuleID idNew; + OSImportInfo* imp; + OSRel* rel; + OSSectionInfo* si; + OSSectionInfo* siFlush; + u32* p; + u32 offset; + u32 x; + + idNew = newModule->info.id; + for (imp = (OSImportInfo*)module->impOffset; + imp < (OSImportInfo*)(module->impOffset + module->impSize); imp++) { + if (imp->id == idNew) { + goto Found; + } + } + return FALSE; + +Found: + siFlush = 0; + for (rel = (OSRel*)imp->offset; rel->type != R_DOLPHIN_END; rel++) { + (u8*)p += rel->offset; + si = &OSGetSectionInfo(newModule)[rel->section]; + offset = OS_SECTIONINFO_OFFSET(si->offset); + x = 0; + switch (rel->type) { + case R_PPC_NONE: + break; + case R_PPC_ADDR32: + *p = x; + break; + case R_PPC_ADDR24: + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_ADDR16: + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_LO: + *(u16*)p = (u16)(x & 0xffff); + break; + case R_PPC_ADDR16_HI: + *(u16*)p = (u16)(((x >> 16) & 0xffff)); + break; + case R_PPC_ADDR16_HA: + *(u16*)p = (u16)(((x >> 16) + ((x & 0x8000) ? 1 : 0)) & 0xffff); + break; + case R_PPC_ADDR14: + case R_PPC_ADDR14_BRTAKEN: + case R_PPC_ADDR14_BRNTAKEN: + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_PPC_REL24: + if (module->unresolvedSection != SHN_UNDEF) { + x = (u32)module->unresolved - (u32)p; + } + *p = (*p & ~0x03fffffc) | (x & 0x03fffffc); + break; + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + *p = (*p & ~0x0000fffc) | (x & 0x0000fffc); + break; + case R_DOLPHIN_NOP: + break; + case R_DOLPHIN_SECTION: + si = &OSGetSectionInfo(module)[rel->section]; + p = (u32*)OS_SECTIONINFO_OFFSET(si->offset); + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + siFlush = (si->offset & OS_SECTIONINFO_EXEC) ? si : 0; + break; + default: + OSReport("OSUnlink: unknown relocation type %3d\n", rel->type); + break; + } + } + + if (siFlush) { + offset = OS_SECTIONINFO_OFFSET(siFlush->offset); + DCFlushRange((void*)offset, siFlush->size); + ICInvalidateRange((void*)offset, siFlush->size); + } + + return TRUE; +} + +BOOL OSUnlink(OSModuleInfo* oldModule) { + OSModuleHeader* moduleHeader; + OSModuleInfo* moduleInfo; + u32 i; + OSSectionInfo* si; + OSImportInfo* imp; + + moduleHeader = (OSModuleHeader*)oldModule; + + DequeueItem(&__OSModuleInfoList, oldModule, link); + + for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) { + Undo(moduleHeader, (OSModuleHeader*)moduleInfo); + } + + OSNotifyUnlink(oldModule); + + if (__OSStringTable) { + oldModule->nameOffset -= (u32)__OSStringTable; + } + if (moduleHeader->prologSection != SHN_UNDEF) { + moduleHeader->prolog -= + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->prologSection].offset); + } + if (moduleHeader->epilogSection != SHN_UNDEF) { + moduleHeader->epilog -= + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->epilogSection].offset); + } + if (moduleHeader->unresolvedSection != SHN_UNDEF) { + moduleHeader->unresolved -= + OS_SECTIONINFO_OFFSET(OSGetSectionInfo(oldModule)[moduleHeader->unresolvedSection].offset); + } + for (imp = (OSImportInfo*)moduleHeader->impOffset; + imp < (OSImportInfo*)(moduleHeader->impOffset + moduleHeader->impSize); imp++) { + imp->offset -= (u32)moduleHeader; + } + for (i = 1; i < oldModule->numSections; i++) { + si = &OSGetSectionInfo(oldModule)[i]; + if (i == moduleHeader->bssSection) { + moduleHeader->bssSection = 0; + si->offset = 0; + } else if (si->offset != 0) { + si->offset -= (u32)moduleHeader; + } + } + moduleHeader->relOffset -= (u32)moduleHeader; + moduleHeader->impOffset -= (u32)moduleHeader; + oldModule->sectionInfoOffset -= (u32)moduleHeader; + + return TRUE; +} + +void __OSModuleInit(void) { + __OSModuleInfoList.head = __OSModuleInfoList.tail = 0; + __OSStringTable = 0; +} + +OSModuleInfo* OSSearchModule(void* ptr, u32* section, u32* offset) { + OSModuleInfo* moduleInfo; + OSSectionInfo* sectionInfo; + u32 i; + u32 baseSection; + + if (ptr == NULL) { + return NULL; + } + + for (moduleInfo = __OSModuleInfoList.head; moduleInfo; moduleInfo = moduleInfo->link.next) { + sectionInfo = OSGetSectionInfo(moduleInfo); + for (i = 0; i < moduleInfo->numSections; ++i) { + if (sectionInfo->size) { + baseSection = OS_SECTIONINFO_OFFSET(sectionInfo->offset); + if (baseSection <= (u32)ptr && (u32)ptr < baseSection + sectionInfo->size) { + if (section) { + *section = i; + } + if (offset) { + *offset = (u32)ptr - baseSection; + } + return moduleInfo; + } + } + sectionInfo++; + } + } + + return NULL; +} diff --git a/src/Dolphin/os/OSMemory.c b/src/Dolphin/os/OSMemory.c new file mode 100644 index 0000000..8f76aa8 --- /dev/null +++ b/src/Dolphin/os/OSMemory.c @@ -0,0 +1,247 @@ +#include <dolphin/os.h> + +#define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) +#define ROUND(n, a) (((u32)(n) + (a)-1) & ~((a)-1)) + +vu16 __MEMRegs[64] : 0xCC004000; +extern OSErrorHandler __OSErrorTable[16]; + +static BOOL OnReset(BOOL final); + +static OSResetFunctionInfo ResetFunctionInfo = { + OnReset, + 127, +}; + +#ifdef FULL_FRANK +static BOOL OnReset(BOOL final) { + if (final != FALSE) { + __MEMRegs[8] = 0xFF; + __OSMaskInterrupts(0xf0000000); + } + return TRUE; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level 0 +#pragma optimizewithasm off +static asm BOOL OnReset(BOOL final) { + nofralloc + mflr r0 + cmpwi r3, 0 + stw r0, 4(r1) + stwu r1, -8(r1) + beq @1 + lis r3, __MEMRegs+16@ha + li r0, 0xff + sth r0, __MEMRegs+16@l(r3) + lis r3, 0xf000 + bl __OSMaskInterrupts +@1 + li r3, 1 + lwz r0, 0xc(r1) + addi r1, r1, 8 + mtlr r0 + blr +} +#pragma pop +/* clang-format on */ +#endif + +u32 OSGetPhysicalMemSize() { return *(u32*)(OSPhysicalToCached(0x0028)); } + +u32 OSGetConsoleSimulatedMemSize() { return *(u32*)(OSPhysicalToCached(0x00F0)); } + +static void MEMIntrruptHandler(__OSInterrupt interrupt, OSContext* context) { + u32 addr; + u32 cause; + + cause = __MEMRegs[0xf]; + addr = (((u32)__MEMRegs[0x12] & 0x3ff) << 16) | __MEMRegs[0x11]; + __MEMRegs[0x10] = 0; + + if (__OSErrorTable[OS_ERROR_PROTECTION]) { + __OSErrorTable[OS_ERROR_PROTECTION](OS_ERROR_PROTECTION, context, cause, addr); + return; + } + + __OSUnhandledException(OS_ERROR_PROTECTION, context, cause, addr); +} + +void OSProtectRange(u32 chan, void* addr, u32 nBytes, u32 control) { + BOOL enabled; + u32 start; + u32 end; + u16 reg; + if (4 <= chan) { + return; + } + + control &= OS_PROTECT_CONTROL_RDWR; + + end = (u32)addr + nBytes; + start = TRUNC(addr, 1u << 10); + end = ROUND(end, 1u << 10); + + DCFlushRange((void*)start, end - start); + + enabled = OSDisableInterrupts(); + + __OSMaskInterrupts(OS_INTERRUPTMASK(__OS_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); +} + +asm void Config24MB() { + // clang-format off + nofralloc + + addi r7,r0,0 + + addis r4,r0,0x00000002@ha + addi r4,r4,0x00000002@l + addis r3,r0,0x800001ff@ha + addi r3,r3,0x800001ff@l + + addis r6,r0,0x01000002@ha + addi r6,r6,0x01000002@l + addis r5,r0,0x810000ff@ha + addi r5,r5,0x810000ff@l + + isync + + mtspr dbat0u,r7 + mtspr dbat0l,r4 + mtspr dbat0u,r3 + isync + + mtspr ibat0u,r7 + mtspr ibat0l,r4 + mtspr ibat0u,r3 + isync + + mtspr dbat2u,r7 + mtspr dbat2l,r6 + mtspr dbat2u,r5 + isync + + mtspr ibat2u,r7 + mtspr ibat2l,r6 + mtspr ibat2u,r5 + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi + // clang-format on +} + +asm void Config48MB() { + // clang-format off + nofralloc + + addi r7,r0,0x0000 + + addis r4,r0,0x00000002@ha + addi r4,r4,0x00000002@l + addis r3,r0,0x800003ff@ha + addi r3,r3,0x800003ff@l + + addis r6,r0,0x02000002@ha + addi r6,r6,0x02000002@l + addis r5,r0,0x820001ff@ha + addi r5,r5,0x820001ff@l + + isync + + mtspr dbat0u,r7 + mtspr dbat0l,r4 + mtspr dbat0u,r3 + isync + + mtspr ibat0u,r7 + mtspr ibat0l,r4 + mtspr ibat0u,r3 + isync + + mtspr dbat2u,r7 + mtspr dbat2l,r6 + mtspr dbat2u,r5 + isync + + mtspr ibat2u,r7 + mtspr ibat2l,r6 + mtspr ibat2u,r5 + isync + + mfmsr r3 + ori r3, r3, 0x30 + mtsrr1 r3 + + mflr r3 + mtsrr0 r3 + rfi + // clang-format on +} + +asm void RealMode(register u32 addr) { + // clang-format off + nofralloc + clrlwi r3, r3, 2 + mtsrr0 r3 + mfmsr r3 + rlwinm r3, r3, 0, 28, 25 + mtsrr1 r3 + rfi + // clang-format on +} + +void __OSInitMemoryProtection() { + u32 padding[8]; + 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); + + if (OSGetConsoleSimulatedMemSize() < OSGetPhysicalMemSize() && + OSGetConsoleSimulatedMemSize() == 0x1800000) { + __MEMRegs[20] = 2; + } + + __OSUnmaskInterrupts(OS_INTERRUPTMASK_MEM_ADDRESS); + OSRestoreInterrupts(enabled); +} diff --git a/src/Dolphin/os/OSMessage.c b/src/Dolphin/os/OSMessage.c new file mode 100644 index 0000000..db4d2fd --- /dev/null +++ b/src/Dolphin/os/OSMessage.c @@ -0,0 +1,86 @@ +#include <dolphin/os.h> + +void OSInitMessageQueue(OSMessageQueue* mq, OSMessage* msgArray, s32 msgCount) { + OSInitThreadQueue(&mq->queueSend); + OSInitThreadQueue(&mq->queueReceive); + mq->msgArray = msgArray; + mq->msgCount = msgCount; + mq->firstIndex = 0; + mq->usedCount = 0; +} + +BOOL OSSendMessage(OSMessageQueue* mq, OSMessage msg, s32 flags) { + BOOL enabled; + s32 lastIndex; + + enabled = OSDisableInterrupts(); + + while (mq->msgCount <= mq->usedCount) { + if (!(flags & OS_MESSAGE_BLOCK)) { + OSRestoreInterrupts(enabled); + return FALSE; + } else { + OSSleepThread(&mq->queueSend); + } + } + + lastIndex = (mq->firstIndex + mq->usedCount) % mq->msgCount; + mq->msgArray[lastIndex] = msg; + mq->usedCount++; + + OSWakeupThread(&mq->queueReceive); + + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL OSReceiveMessage(OSMessageQueue* mq, OSMessage* msg, s32 flags) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + + while (mq->usedCount == 0) { + if (!(flags & OS_MESSAGE_BLOCK)) { + OSRestoreInterrupts(enabled); + return FALSE; + } else { + OSSleepThread(&mq->queueReceive); + } + } + + if (msg != NULL) { + *msg = mq->msgArray[mq->firstIndex]; + } + mq->firstIndex = (mq->firstIndex + 1) % mq->msgCount; + mq->usedCount--; + + OSWakeupThread(&mq->queueSend); + + OSRestoreInterrupts(enabled); + return TRUE; +} + +BOOL OSJamMessage(OSMessageQueue* mq, OSMessage msg, s32 flags) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + + while (mq->msgCount <= mq->usedCount) + { + if (!(flags & OS_MESSAGE_BLOCK)) { + OSRestoreInterrupts(enabled); + return FALSE; + } else { + OSSleepThread(&mq->queueSend); + } + } + + mq->firstIndex = (mq->firstIndex + mq->msgCount - 1) % mq->msgCount; + mq->msgArray[mq->firstIndex] = msg; + mq->usedCount++; + + OSWakeupThread(&mq->queueReceive); + + OSRestoreInterrupts(enabled); + return TRUE; +} diff --git a/src/Dolphin/os/OSMutex.c b/src/Dolphin/os/OSMutex.c new file mode 100644 index 0000000..f853729 --- /dev/null +++ b/src/Dolphin/os/OSMutex.c @@ -0,0 +1,223 @@ +#include "dolphin/os.h" + +#define PushTail(queue, mutex, link) \ + do { \ + OSMutex* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (mutex); \ + else \ + __prev->link.next = (mutex); \ + (mutex)->link.prev = __prev; \ + (mutex)->link.next = NULL; \ + (queue)->tail = (mutex); \ + } while (0) + +#define PopHead(queue, mutex, link) \ + do { \ + OSMutex* __next; \ + \ + (mutex) = (queue)->head; \ + __next = (mutex)->link.next; \ + if (__next == NULL) \ + (queue)->tail = NULL; \ + else \ + __next->link.prev = NULL; \ + (queue)->head = __next; \ + } while (0) + +#define PopItem(queue, mutex, link) \ + do { \ + OSMutex* __next; \ + OSMutex* __prev; \ + \ + __next = (mutex)->link.next; \ + __prev = (mutex)->link.prev; \ + \ + if (__next == NULL) \ + (queue)->tail = __prev; \ + else \ + __next->link.prev = __prev; \ + \ + if (__prev == NULL) \ + (queue)->head = __next; \ + else \ + __prev->link.next = __next; \ + } while (0) + +void OSInitMutex(OSMutex* mutex) { + OSInitThreadQueue(&mutex->queue); + mutex->thread = 0; + mutex->count = 0; +} + +void OSLockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + OSThread* ownerThread; + + while (TRUE) { + ownerThread = ((OSMutex*)mutex)->thread; + if (ownerThread == 0) { + mutex->thread = currentThread; + mutex->count++; + PushTail(¤tThread->queueMutex, mutex, link); + break; + } else if (ownerThread == currentThread) { + mutex->count++; + break; + } else { + currentThread->mutex = mutex; + __OSPromoteThread(mutex->thread, currentThread->priority); + OSSleepThread(&mutex->queue); + currentThread->mutex = 0; + } + } + OSRestoreInterrupts(enabled); +} + +void OSUnlockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + if (mutex->thread == currentThread && --mutex->count == 0) { + PopItem(¤tThread->queueMutex, mutex, link); + mutex->thread = NULL; + if (currentThread->priority < currentThread->base) { + currentThread->priority = __OSGetEffectivePriority(currentThread); + } + + OSWakeupThread(&mutex->queue); + } + OSRestoreInterrupts(enabled); +} + +void __OSUnlockAllMutex(OSThread* thread) { + OSMutex* mutex; + + while (thread->queueMutex.head) { + PopHead(&thread->queueMutex, mutex, link); + mutex->count = 0; + mutex->thread = NULL; + OSWakeupThread(&mutex->queue); + } +} + +BOOL OSTryLockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + BOOL locked; + if (mutex->thread == 0) { + mutex->thread = currentThread; + mutex->count++; + PushTail(¤tThread->queueMutex, mutex, link); + locked = TRUE; + } else if (mutex->thread == currentThread) { + mutex->count++; + locked = TRUE; + } else { + locked = FALSE; + } + OSRestoreInterrupts(enabled); + return locked; +} + +void OSInitCond(OSCond* cond) { OSInitThreadQueue(&cond->queue); } + +void OSWaitCond(OSCond* cond, OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + s32 count; + + if (mutex->thread == currentThread) { + count = mutex->count; + mutex->count = 0; + PopItem(¤tThread->queueMutex, mutex, link); + mutex->thread = NULL; + + 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(OSCond* cond) { OSWakeupThread(&cond->queue); } + +static BOOL IsMember(OSMutexQueue* queue, OSMutex* mutex) { + OSMutex* member; + + for (member = queue->head; member; member = member->link.next) { + if (mutex == member) + return TRUE; + } + return FALSE; +} + +BOOL __OSCheckMutex(OSMutex* mutex) { + OSThread* thread; + OSThreadQueue* queue; + OSPriority priority = 0; + + queue = &mutex->queue; + if (!(queue->head == NULL || queue->head->link.prev == NULL)) + return FALSE; + if (!(queue->tail == NULL || queue->tail->link.next == NULL)) + return FALSE; + for (thread = queue->head; thread; thread = thread->link.next) { + if (!(thread->link.next == NULL || thread == thread->link.next->link.prev)) + return FALSE; + if (!(thread->link.prev == NULL || thread == thread->link.prev->link.next)) + return FALSE; + + if (thread->state != OS_THREAD_STATE_WAITING) + return FALSE; + + if (thread->priority < priority) + return FALSE; + priority = thread->priority; + } + + if (mutex->thread) { + if (mutex->count <= 0) + return FALSE; + } else { + if (0 != mutex->count) + return FALSE; + } + + return TRUE; +} + +BOOL __OSCheckDeadLock(OSThread* thread) { + OSMutex* mutex; + + mutex = thread->mutex; + while (mutex && mutex->thread) { + if (mutex->thread == thread) + return TRUE; + mutex = mutex->thread->mutex; + } + return FALSE; +} + +BOOL __OSCheckMutexes(OSThread* thread) { + OSMutex* mutex; + + for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) { + if (mutex->thread != thread) + return FALSE; + if (!__OSCheckMutex(mutex)) + return FALSE; + } + return TRUE; +} diff --git a/src/Dolphin/os/OSReboot.c b/src/Dolphin/os/OSReboot.c new file mode 100644 index 0000000..4b952cf --- /dev/null +++ b/src/Dolphin/os/OSReboot.c @@ -0,0 +1,166 @@ +#include <os.h> +#include <dvd.h> + +/*#include <dolphin/dvd/dvd.h> +#include <dolphin/os/OSCache.h> +#include <dolphin/os/OSInterrupt.h> +#include <dolphin/os/OSReset.h>*/ + +static void *Header[0x20 / sizeof(void *)]; +static void *SaveStart; +static void *SaveEnd; +static BOOL Prepared; + +void Run(register Event callback) +{ + OSDisableInterrupts(); + ICFlashInvalidate(); + __sync(); + __isync(); + asm { + mtlr callback + blr + } +} + +static void Callback(void) +{ + Prepared = TRUE; +} + +#pragma push +asm void __OSReboot(u32 resetCode, BOOL forceMenu) +{ // clang-format off + nofralloc +/* 80348144 00344D24 7C 08 02 A6 */ mflr r0 +/* 80348148 00344D28 90 01 00 04 */ stw r0, 4(r1) +/* 8034814C 00344D2C 94 21 FC B8 */ stwu r1, -0x348(r1) +/* 80348150 00344D30 93 E1 03 44 */ stw r31, 0x344(r1) +/* 80348154 00344D34 93 C1 03 40 */ stw r30, 0x340(r1) +/* 80348158 00344D38 93 A1 03 3C */ stw r29, 0x33c(r1) +/* 8034815C 00344D3C 7C 7D 1B 78 */ mr r29, r3 +/* 80348160 00344D40 3C 60 80 4A */ lis r3, Header@ha +/* 80348164 00344D44 3B C3 7D 40 */ addi r30, r3, Header@l +/* 80348168 00344D48 4B FF F1 FD */ bl OSDisableInterrupts +/* 8034816C 00344D4C 80 AD BC F0 */ lwz r5, SaveStart(r13) +/* 80348170 00344D50 3F E0 81 80 */ lis r31, 0x817FFFFC@ha +/* 80348174 00344D54 38 60 00 00 */ li r3, 0 +/* 80348178 00344D58 80 0D BC F4 */ lwz r0, SaveEnd(r13) +/* 8034817C 00344D5C 3C 80 81 30 */ lis r4, 0x812FDFF0@ha +/* 80348180 00344D60 38 E0 00 01 */ li r7, 1 +/* 80348184 00344D64 93 BF FF FC */ stw r29, 0x817FFFFC@l(r31) +/* 80348188 00344D68 3C C0 80 00 */ lis r6, 0x800030E2@ha +/* 8034818C 00344D6C 90 7F FF F8 */ stw r3, -8(r31) +/* 80348190 00344D70 38 61 00 70 */ addi r3, r1, 0x70 +/* 80348194 00344D74 98 E6 30 E2 */ stb r7, 0x800030E2@l(r6) +/* 80348198 00344D78 90 A4 DF F0 */ stw r5, 0x812FDFF0@l(r4) +/* 8034819C 00344D7C 90 04 DF EC */ stw r0, -0x2014(r4) +/* 803481A0 00344D80 4B FF D0 B5 */ bl OSClearContext +/* 803481A4 00344D84 38 61 00 70 */ addi r3, r1, 0x70 +/* 803481A8 00344D88 4B FF CE E5 */ bl OSSetCurrentContext +/* 803481AC 00344D8C 4B FE FC 3D */ bl DVDInit +/* 803481B0 00344D90 38 60 00 01 */ li r3, 1 +/* 803481B4 00344D94 4B FF 1A 45 */ bl DVDSetAutoInvalidation +/* 803481B8 00344D98 3C 60 80 35 */ lis r3, Callback@ha +/* 803481BC 00344D9C 38 63 81 38 */ addi r3, r3, Callback@l +/* 803481C0 00344DA0 4B FF 1E 75 */ bl __DVDPrepareResetAsync +/* 803481C4 00344DA4 4B FF 1D 8D */ bl DVDCheckDisk +/* 803481C8 00344DA8 2C 03 00 00 */ cmpwi r3, 0 +/* 803481CC 00344DAC 40 82 00 0C */ bne lbl_803481D8 +/* 803481D0 00344DB0 80 7F FF FC */ lwz r3, -4(r31) +/* 803481D4 00344DB4 48 00 02 31 */ bl __OSDoHotReset +lbl_803481D8: +/* 803481D8 00344DB8 38 60 FF E0 */ li r3, -32 +/* 803481DC 00344DBC 4B FF F5 51 */ bl __OSMaskInterrupts +/* 803481E0 00344DC0 38 60 04 00 */ li r3, 0x400 +/* 803481E4 00344DC4 4B FF F5 D1 */ bl __OSUnmaskInterrupts +/* 803481E8 00344DC8 4B FF F1 91 */ bl OSEnableInterrupts +/* 803481EC 00344DCC 48 00 00 04 */ b lbl_803481F0 +lbl_803481F0: +/* 803481F0 00344DD0 48 00 00 04 */ b lbl_803481F4 +lbl_803481F4: +/* 803481F4 00344DD4 80 0D BC F8 */ lwz r0, Prepared(r13) +/* 803481F8 00344DD8 2C 00 00 00 */ cmpwi r0, 0 +/* 803481FC 00344DDC 41 82 FF F8 */ beq lbl_803481F4 +/* 80348200 00344DE0 7F C4 F3 78 */ mr r4, r30 +/* 80348204 00344DE4 38 61 00 40 */ addi r3, r1, 0x40 +/* 80348208 00344DE8 38 A0 00 20 */ li r5, 0x20 +/* 8034820C 00344DEC 38 C0 24 40 */ li r6, 0x2440 +/* 80348210 00344DF0 38 E0 00 00 */ li r7, 0 +/* 80348214 00344DF4 4B FF 17 51 */ bl DVDReadAbsAsyncForBS +/* 80348218 00344DF8 3F E0 81 80 */ lis r31, 0x8180 +/* 8034821C 00344DFC 48 00 00 04 */ b lbl_80348220 +lbl_80348220: +/* 80348220 00344E00 48 00 00 04 */ b lbl_80348224 +lbl_80348224: +/* 80348224 00344E04 80 01 00 4C */ lwz r0, 0x4c(r1) +/* 80348228 00344E08 2C 00 00 01 */ cmpwi r0, 1 +/* 8034822C 00344E0C 41 82 FF F8 */ beq lbl_80348224 +/* 80348230 00344E10 40 80 00 14 */ bge lbl_80348244 +/* 80348234 00344E14 2C 00 FF FF */ cmpwi r0, -1 +/* 80348238 00344E18 41 82 00 18 */ beq lbl_80348250 +/* 8034823C 00344E1C 40 80 00 20 */ bge lbl_8034825C +/* 80348240 00344E20 4B FF FF E4 */ b lbl_80348224 +lbl_80348244: +/* 80348244 00344E24 2C 00 00 0C */ cmpwi r0, 0xc +/* 80348248 00344E28 40 80 FF DC */ bge lbl_80348224 +/* 8034824C 00344E2C 48 00 00 04 */ b lbl_80348250 +lbl_80348250: +/* 80348250 00344E30 80 7F FF FC */ lwz r3, -4(r31) +/* 80348254 00344E34 48 00 01 B1 */ bl __OSDoHotReset +/* 80348258 00344E38 4B FF FF CC */ b lbl_80348224 +lbl_8034825C: +/* 8034825C 00344E3C 80 7E 00 18 */ lwz r3, 0x18(r30) +/* 80348260 00344E40 80 9E 00 14 */ lwz r4, 0x14(r30) +/* 80348264 00344E44 38 03 00 1F */ addi r0, r3, 0x1f +/* 80348268 00344E48 38 84 00 20 */ addi r4, r4, 0x20 +/* 8034826C 00344E4C 54 1E 00 34 */ rlwinm r30, r0, 0, 0, 0x1a +/* 80348270 00344E50 48 00 00 04 */ b lbl_80348274 +lbl_80348274: +/* 80348274 00344E54 48 00 00 04 */ b lbl_80348278 +lbl_80348278: +/* 80348278 00344E58 80 0D BC F8 */ lwz r0, Prepared(r13) +/* 8034827C 00344E5C 2C 00 00 00 */ cmpwi r0, 0 +/* 80348280 00344E60 41 82 FF F8 */ beq lbl_80348278 +/* 80348284 00344E64 7F C5 F3 78 */ mr r5, r30 +/* 80348288 00344E68 38 61 00 10 */ addi r3, r1, 0x10 +/* 8034828C 00344E6C 38 C4 24 40 */ addi r6, r4, 0x2440 +/* 80348290 00344E70 3C 80 81 30 */ lis r4, 0x8130 +/* 80348294 00344E74 38 E0 00 00 */ li r7, 0 +/* 80348298 00344E78 4B FF 16 CD */ bl DVDReadAbsAsyncForBS +/* 8034829C 00344E7C 3F E0 81 80 */ lis r31, 0x8180 +/* 803482A0 00344E80 48 00 00 04 */ b lbl_803482A4 +lbl_803482A4: +/* 803482A4 00344E84 48 00 00 04 */ b lbl_803482A8 +lbl_803482A8: +/* 803482A8 00344E88 80 01 00 1C */ lwz r0, 0x1c(r1) +/* 803482AC 00344E8C 2C 00 00 01 */ cmpwi r0, 1 +/* 803482B0 00344E90 41 82 FF F8 */ beq lbl_803482A8 +/* 803482B4 00344E94 40 80 00 14 */ bge lbl_803482C8 +/* 803482B8 00344E98 2C 00 FF FF */ cmpwi r0, -1 +/* 803482BC 00344E9C 41 82 00 18 */ beq lbl_803482D4 +/* 803482C0 00344EA0 40 80 00 20 */ bge lbl_803482E0 +/* 803482C4 00344EA4 4B FF FF E4 */ b lbl_803482A8 +lbl_803482C8: +/* 803482C8 00344EA8 2C 00 00 0C */ cmpwi r0, 0xc +/* 803482CC 00344EAC 40 80 FF DC */ bge lbl_803482A8 +/* 803482D0 00344EB0 48 00 00 04 */ b lbl_803482D4 +lbl_803482D4: +/* 803482D4 00344EB4 80 7F FF FC */ lwz r3, -4(r31) +/* 803482D8 00344EB8 48 00 01 2D */ bl __OSDoHotReset +/* 803482DC 00344EBC 4B FF FF CC */ b lbl_803482A8 +lbl_803482E0: +/* 803482E0 00344EC0 3C 60 81 30 */ lis r3, 0x8130 +/* 803482E4 00344EC4 7F C4 F3 78 */ mr r4, r30 +/* 803482E8 00344EC8 4B FF C5 ED */ bl ICInvalidateRange +/* 803482EC 00344ECC 3C 60 81 30 */ lis r3, 0x8130 +/* 803482F0 00344ED0 4B FF FE 09 */ bl Run +/* 803482F4 00344ED4 80 01 03 4C */ lwz r0, 0x34c(r1) +/* 803482F8 00344ED8 83 E1 03 44 */ lwz r31, 0x344(r1) +/* 803482FC 00344EDC 83 C1 03 40 */ lwz r30, 0x340(r1) +/* 80348300 00344EE0 7C 08 03 A6 */ mtlr r0 +/* 80348304 00344EE4 83 A1 03 3C */ lwz r29, 0x33c(r1) +/* 80348308 00344EE8 38 21 03 48 */ addi r1, r1, 0x348 +/* 8034830C 00344EEC 4E 80 00 20 */ blr +} // clang-format on +#pragma pop diff --git a/src/Dolphin/os/OSReset.c b/src/Dolphin/os/OSReset.c index a9cc186..ebd0b04 100644 --- a/src/Dolphin/os/OSReset.c +++ b/src/Dolphin/os/OSReset.c @@ -1,5 +1,190 @@ -#include "dolphin/OSReset.h" +#include "dolphin/OSRtcPriv.h" +#include "dolphin/os.h" +#include "dolphin/vi.h" -void OSResetSystem(int reset, unsigned int resetCode, int forceMenu) { +volatile u8 DAT_800030e2 : 0x800030e2; +typedef struct Unk { + u8 pad[0x24]; + u32 resetCode; +} Unk; +volatile Unk DAT_cc003000 : 0xcc003000; +typedef struct Unk2 { + u16 _0; + u16 _2; +} Unk2; + +volatile Unk2 DAT_cc002000 : 0xcc002000; + +typedef struct OSResetQueue { + OSResetFunctionInfo* first; + OSResetFunctionInfo* last; +} OSResetQueue; + +OSResetQueue ResetFunctionQueue; + +void OSRegisterResetFunction(OSResetFunctionInfo* func) { + OSResetFunctionInfo* tmp; + OSResetFunctionInfo* iter; + + for (iter = ResetFunctionQueue.first; iter && iter->priority <= func->priority; iter = iter->next) + ; + + if (iter == NULL) { + tmp = ResetFunctionQueue.last; + if (tmp == NULL) { + ResetFunctionQueue.first = func; + } else { + tmp->next = func; + } + func->prev = tmp; + func->next = NULL; + ResetFunctionQueue.last = func; + return; + } + + func->next = iter; + tmp = iter->prev; + iter->prev = func; + func->prev = tmp; + if (tmp == NULL) { + ResetFunctionQueue.first = func; + return; + } + tmp->next = func; +} + +BOOL __OSCallResetFunctions(u32 arg0) { + OSResetFunctionInfo* iter; + s32 retCode = 0; + + for (iter = ResetFunctionQueue.first; iter != NULL; iter = iter->next) { + retCode |= !iter->func(arg0); + } + retCode |= !__OSSyncSram(); + if (retCode) { + return 0; + } + return 1; +} + +asm void Reset(register s32 resetCode) { + // clang-format off + nofralloc + b lbl_8038315C +lbl_80383140: + mfspr r8, HID0 + ori r8, r8, 8 + mtspr HID0, r8 + isync + sync + nop + b lbl_80383160 +lbl_8038315C: + b lbl_8038317C +lbl_80383160: + mftb r5, 268 +lbl_80383164: + mftb r6, 268 + subf r7, r5, r6 + cmplwi r7, 0x1124 + blt lbl_80383164 + nop + b lbl_80383180 +lbl_8038317C: + b lbl_8038319C +lbl_80383180: + lis r8, 0xCC003000@h + ori r8, r8, 0xCC003000@l + li r4, 3 + stw r4, 0x24(r8) + stw r3, 0x24(r8) + nop + b lbl_803831A0 +lbl_8038319C: + b lbl_803831A8 +lbl_803831A0: + nop + b lbl_803831A0 +lbl_803831A8: + b lbl_80383140 + // clang-format on +} + +OSThreadQueue __OSActiveThreadQueue : (OS_BASE_CACHED | 0x00DC); + +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); + break; + default: + break; + } + } +} + +void __OSDoHotReset(s32 arg0) { + OSDisableInterrupts(); + __VIRegs[1] = 0; + ICFlashInvalidate(); + Reset(arg0 * 8); +} + +void OSResetSystem(int reset, u32 resetCode, BOOL forceMenu) { + BOOL rc; + BOOL disableRecalibration; + u32 unk[3]; + OSDisableScheduler(); + __OSStopAudioSystem(); + + if (reset == OS_RESET_SHUTDOWN) { + disableRecalibration = __PADDisableRecalibration(TRUE); + } + + while (!__OSCallResetFunctions(FALSE)) + ; + + if (reset == OS_RESET_HOTRESET && forceMenu) { + OSSram* sram; + + sram = __OSLockSram(); + sram->flags |= 0x40; + __OSUnlockSram(TRUE); + + while (!__OSSyncSram()) + ; + } + OSDisableInterrupts(); + __OSCallResetFunctions(TRUE); + LCDisable(); + if (reset == OS_RESET_HOTRESET) { + __OSDoHotReset(resetCode); + } else if (reset == OS_RESET_RESTART) { + KillThreads(); + OSEnableScheduler(); + __OSReboot(resetCode, forceMenu); + } + KillThreads(); + memset(OSPhysicalToCached(0x40), 0, 0xcc - 0x40); + memset(OSPhysicalToCached(0xd4), 0, 0xe8 - 0xd4); + memset(OSPhysicalToCached(0xf4), 0, 0xf8 - 0xf4); + memset(OSPhysicalToCached(0x3000), 0, 0xc0); + memset(OSPhysicalToCached(0x30c8), 0, 0xd4 - 0xc8); + memset(OSPhysicalToCached(0x30e2), 0, 1); + + __PADDisableRecalibration(disableRecalibration); +} + +u32 OSGetResetCode(void) { + if (DAT_800030e2 != 0) { + return 0x80000000; + } + return ((DAT_cc003000.resetCode & ~7) >> 3); } diff --git a/src/Dolphin/os/OSResetSW.c b/src/Dolphin/os/OSResetSW.c new file mode 100644 index 0000000..9752213 --- /dev/null +++ b/src/Dolphin/os/OSResetSW.c @@ -0,0 +1,281 @@ +#include <dolphin/os.h> + +extern OSTime __OSGetSystemTime(); + +u8 GameChoice : (OS_BASE_CACHED | 0x30E3); + +vu32 __PIRegs[12] : 0xCC003000; + +extern OSTime __OSStartTime; + +static OSResetCallback ResetCallback; +static BOOL Down; +static BOOL LastState; +static OSTime HoldUp; +static OSTime HoldDown; + +void __OSResetSWInterruptHandler(__OSInterrupt interrupt, OSContext* context) { + OSResetCallback callback; + + HoldDown = __OSGetSystemTime(); + while (__OSGetSystemTime() - HoldDown < OSMicrosecondsToTicks(100) && + !(__PIRegs[0] & 0x00010000)) { + ; + } + if (!(__PIRegs[0] & 0x00010000)) { + LastState = Down = TRUE; + __OSMaskInterrupts(OS_INTERRUPTMASK_PI_RSW); + if (ResetCallback) { + callback = ResetCallback; + ResetCallback = NULL; + callback(); + } + } + __PIRegs[0] = 2; +} + +#ifdef FULL_FRANK +BOOL OSGetResetButtonState(void) { + BOOL enabled; + BOOL state; + u32 reg; + OSTime now; + + enabled = OSDisableInterrupts(); + + now = __OSGetSystemTime(); + + 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; +} +#else +extern void __div2i(void); +/* clang-format off */ +#pragma push +#pragma optimization_level +#pragma optimizewithasm off +asm BOOL OSGetResetButtonState(void) { + nofralloc + mflr r0 + stw r0, 4(r1) + stwu r1, -0x18(r1) + stw r31, 0x14(r1) + stw r30, 0x10(r1) + stw r29, 0xc(r1) + bl OSDisableInterrupts + mr r30, r3 + bl __OSGetSystemTime + lis r5, __PIRegs@ha + lwz r0, __PIRegs@l(r5) + rlwinm. r0, r0, 0, 0xf, 0xf + bne lbl_8038369C + lwz r0, Down + cmpwi r0, 0 + bne lbl_8038360C + lwz r0, HoldUp + li r6, 0 + lwz r5, HoldUp+4 + li r7, 1 + xor r0, r0, r6 + xor r5, r5, r6 + stw r7, Down + or. r0, r5, r0 + beq lbl_803835F8 + b lbl_803835FC +lbl_803835F8: + mr r7, r6 +lbl_803835FC: + stw r4, HoldDown+4 + mr r29, r7 + stw r3, HoldDown + b lbl_80383750 +lbl_8038360C: + lwz r0, HoldUp + li r9, 0 + lwz r5, HoldUp+4 + li r10, 1 + xor r0, r0, r9 + xor r5, r5, r9 + or. r0, r5, r0 + bne lbl_80383680 + lis r6, __OSBusClock@ha + lwz r5, HoldDown+4 + lwz r7, __OSBusClock@l(r6) + lis r6, 0x431BDE83@ha + addi r8, r6, 0x431BDE83@l + lwz r0, HoldDown + srwi r6, r7, 2 + mulhwu r6, r8, r6 + srwi r6, r6, 0xf + mulli r6, r6, 0x64 + subfc r7, r5, r4 + subfe r0, r0, r3 + srwi r8, r6, 3 + xoris r5, r0, 0x8000 + xoris r6, r9, 0x8000 + subfc r0, r7, r8 + subfe r5, r5, r6 + subfe r5, r6, r6 + neg. r5, r5 + bne lbl_80383680 + mr r10, r9 +lbl_80383680: + cmpwi r10, 0 + beq lbl_80383690 + li r0, 1 + b lbl_80383694 +lbl_80383690: + li r0, 0 +lbl_80383694: + mr r29, r0 + b lbl_80383750 +lbl_8038369C: + lwz r0, Down + cmpwi r0, 0 + beq lbl_803836D8 + lwz r5, LastState + li r0, 0 + stw r0, Down + cmpwi r5, 0 + addi r29, r5, 0 + beq lbl_803836CC + stw r4, HoldUp+4 + stw r3, HoldUp + b lbl_80383750 +lbl_803836CC: + stw r0, HoldUp+4 + stw r0, HoldUp + b lbl_80383750 +lbl_803836D8: + lwz r6, HoldUp + li r8, 0 + lwz r7, HoldUp+4 + xor r0, r6, r8 + xor r5, r7, r8 + or. r0, r5, r0 + beq lbl_80383740 + lis r5, __OSBusClock@ha + lwz r0, __OSBusClock@l(r5) + lis r5, 0x10624DD3@ha + addi r5, r5, 0x10624DD3@l + srwi r0, r0, 2 + mulhwu r0, r5, r0 + srwi r0, r0, 6 + mulli r0, r0, 0x28 + subfc r7, r7, r4 + subfe r5, r6, r3 + xoris r6, r5, 0x8000 + xoris r5, r8, 0x8000 + subfc r0, r0, r7 + subfe r5, r5, r6 + subfe r5, r6, r6 + neg. r5, r5 + beq lbl_80383740 + li r29, 1 + b lbl_80383750 +lbl_80383740: + li r0, 0 + stw r0, HoldUp+4 + li r29, 0 + stw r0, HoldUp +lbl_80383750: + lis r5, GameChoice@ha + stw r29, LastState + lbz r0, GameChoice@l(r5) + clrlwi. r0, r0, 0x1a + beq lbl_80383800 + mulli r10, r0, 0x3c + lwz r0, 0xf8(r5) + lwz r9, __OSStartTime+4 + lwz r8, __OSStartTime + srwi r6, r0, 2 + srawi r0, r10, 0x1f + mullw r7, r0, r6 + mulhwu r0, r10, r6 + mullw r5, r10, r6 + addc r9, r9, r5 + li r31, 0 + add r7, r7, r0 + mullw r0, r10, r31 + add r0, r7, r0 + adde r8, r8, r0 + xoris r7, r8, 0x8000 + xoris r5, r3, 0x8000 + subfc r0, r4, r9 + subfe r5, r5, r7 + subfe r5, r7, r7 + neg. r5, r5 + beq lbl_80383800 + subfc r4, r9, r4 + subfe r3, r8, r3 + li r5, 0 + bl __div2i + li r5, 0 + li r6, 2 + bl __div2i + li r0, 1 + and r4, r4, r0 + and r0, r3, r31 + xor r3, r4, r31 + xor r0, r0, r31 + or. r0, r3, r0 + bne lbl_803837FC + li r29, 1 + b lbl_80383800 +lbl_803837FC: + li r29, 0 +lbl_80383800: + mr r3, r30 + bl OSRestoreInterrupts + mr r3, r29 + lwz r0, 0x1c(r1) + lwz r31, 0x14(r1) + lwz r30, 0x10(r1) + lwz r29, 0xc(r1) + addi r1, r1, 0x18 + mtlr r0 + blr +} +#pragma pop +/* clang-format on */ +#endif diff --git a/src/Dolphin/os/OSRtc.c b/src/Dolphin/os/OSRtc.c new file mode 100644 index 0000000..be14670 --- /dev/null +++ b/src/Dolphin/os/OSRtc.c @@ -0,0 +1,544 @@ +#include "dolphin/OSRtcPriv.h" +#include "dolphin/os.h" + +#define RTC_CMD_READ 0x20000000 +#define RTC_CMD_WRITE 0xa0000000 + +#define RTC_SRAM_ADDR 0x00000100 +#define RTC_SRAM_SIZE 64 + +#define RTC_CHAN 0 +#define RTC_DEV 1 +#define RTC_FREQ 3 // EXI_FREQ_8M + +typedef struct SramControlBlock { + u8 sram[RTC_SRAM_SIZE]; + u32 offset; + BOOL enabled; + BOOL locked; + BOOL sync; + void (*callback)(void); +} SramControlBlock; + +static SramControlBlock Scb ATTRIBUTE_ALIGN(32); + +static BOOL GetRTC(u32* rtc) { + BOOL err; + u32 cmd; + + if (!EXILock(RTC_CHAN, RTC_DEV, 0)) { + return FALSE; + } + if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + cmd = RTC_CMD_READ; + err = FALSE; + err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIImm(RTC_CHAN, &cmd, 4, 0, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + + *rtc = cmd; + + return !err; +} + +BOOL __OSGetRTC(u32* rtc) { + BOOL err; + u32 t0; + u32 t1; + int i; + + for (i = 0; i < 16; i++) { + err = FALSE; + err |= !GetRTC(&t0); + err |= !GetRTC(&t1); + if (err) { + break; + } + if (t0 == t1) { + *rtc = t0; + return TRUE; + } + } + return FALSE; +} + +BOOL __OSSetRTC(u32 rtc) { + BOOL err; + u32 cmd; + + if (!EXILock(RTC_CHAN, RTC_DEV, 0)) { + return FALSE; + } + if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + cmd = RTC_CMD_WRITE; + err = FALSE; + err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIImm(RTC_CHAN, &rtc, 4, 1, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + + return !err; +} + +static BOOL ReadSram(void* buffer) { + BOOL err; + u32 cmd; + + DCInvalidateRange(buffer, RTC_SRAM_SIZE); + + if (!EXILock(RTC_CHAN, RTC_DEV, 0)) { + return FALSE; + } + if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + cmd = RTC_CMD_READ | RTC_SRAM_ADDR; + err = FALSE; + err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDma(RTC_CHAN, buffer, RTC_SRAM_SIZE, 0, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + + return !err; +} + +BOOL WriteSram(void* buffer, u32 offset, u32 size); +static void WriteSramCallback(s32 chan, OSContext* context) { + Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset); + if (Scb.sync) { + Scb.offset = RTC_SRAM_SIZE; + } +} + +BOOL WriteSram(void* buffer, u32 offset, u32 size) { + BOOL err; + u32 cmd; + + if (!EXILock(RTC_CHAN, RTC_DEV, WriteSramCallback)) { + return FALSE; + } + if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + offset <<= 6; + cmd = RTC_CMD_WRITE | RTC_SRAM_ADDR + offset; + err = FALSE; + err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIImmEx(RTC_CHAN, buffer, (s32)size, 1); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + + return !err; +} + +void __OSInitSram() { + Scb.locked = Scb.enabled = FALSE; + Scb.sync = ReadSram(Scb.sram); + Scb.offset = RTC_SRAM_SIZE; +} + +static void* LockSram(u32 offset) { + BOOL enabled; + enabled = OSDisableInterrupts(); + + if (Scb.locked != FALSE) { + OSRestoreInterrupts(enabled); + return NULL; + } + + Scb.enabled = enabled; + Scb.locked = TRUE; + + return Scb.sram + offset; +} + +#ifdef FULL_FRANK +OSSram* __OSLockSram() { return LockSram(0); } +#else +/* clang-format off */ +#pragma push +#pragma optimization_level 0 +#pragma optimizewithasm off +asm OSSram* __OSLockSram() { + nofralloc + mflr r0 + lis r3, Scb@ha + stw r0, 4(r1) + stwu r1, -0x10(r1) + stw r31, 0xc(r1) + addi r31, r3, Scb@l + bl OSDisableInterrupts + lwz r0, 0x48(r31) + addi r4, r31, 0x48 + cmpwi r0, 0 + beq lbl_80383B0C + bl OSRestoreInterrupts + li r31, 0 + b lbl_80383B18 +lbl_80383B0C: + stw r3, 0x44(r31) + li r0, 1 + stw r0, 0(r4) +lbl_80383B18: + mr r3, r31 + lwz r0, 0x14(r1) + lwz r31, 0xc(r1) + addi r1, r1, 0x10 + mtlr r0 + blr +} +/* clang-format on */ +#pragma pop +#endif + +OSSramEx* __OSLockSramEx() { return LockSram(sizeof(OSSram)); } + +static BOOL UnlockSram(BOOL commit, u32 offset) { + u16* p; + + if (commit) { + if (offset == 0) { + OSSram* sram = (OSSram*)Scb.sram; + + if (2u < (sram->flags & 3)) { + sram->flags &= ~3; + } + + sram->checkSum = sram->checkSumInv = 0; + for (p = (u16*)&sram->counterBias; p < (u16*)(Scb.sram + sizeof(OSSram)); p++) { + sram->checkSum += *p; + sram->checkSumInv += ~*p; + } + } + + if (offset < Scb.offset) { + Scb.offset = offset; + } + + Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset); + if (Scb.sync) { + Scb.offset = RTC_SRAM_SIZE; + } + } + Scb.locked = FALSE; + OSRestoreInterrupts(Scb.enabled); + return Scb.sync; +} + +BOOL __OSUnlockSram(BOOL commit) { return UnlockSram(commit, 0); } + +BOOL __OSUnlockSramEx(BOOL commit) { return UnlockSram(commit, sizeof(OSSram)); } + +BOOL __OSSyncSram() { return Scb.sync; } + +BOOL __OSReadROM(void* buffer, s32 length, s32 offset) { + BOOL err; + u32 cmd; + + DCInvalidateRange(buffer, (u32)length); + + if (!EXILock(RTC_CHAN, RTC_DEV, 0)) { + return FALSE; + } + if (!EXISelect(RTC_CHAN, RTC_DEV, RTC_FREQ)) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + cmd = (u32)(offset << 6); + err = FALSE; + err |= !EXIImm(RTC_CHAN, &cmd, 4, 1, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDma(RTC_CHAN, buffer, length, 0, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + + return !err; +} + +inline OSSram* __OSLockSramHACK() { return LockSram(0); } +#ifdef FULL_FRANK +u32 OSGetSoundMode() { + OSSram* sram; + u32 mode; + + sram = __OSLockSramHACK(); + mode = (sram->flags & 0x4) ? OS_SOUND_MODE_STEREO : OS_SOUND_MODE_MONO; + __OSUnlockSram(FALSE); + return mode; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level +#pragma optimizewithasm off +asm u32 OSGetSoundMode() { + nofralloc + mflr r0 + lis r3, Scb@ha + stw r0, 4(r1) + stwu r1, -0x20(r1) + stw r31, 0x1c(r1) + addi r31, r3, Scb@l + bl OSDisableInterrupts + lwz r0, 0x48(r31) + addi r4, r31, 0x48 + cmpwi r0, 0 + beq lbl_80384048 + bl OSRestoreInterrupts + li r31, 0 + b lbl_80384054 +lbl_80384048: + stw r3, 0x44(r31) + li r0, 1 + stw r0, 0(r4) +lbl_80384054: + lbz r0, 0x13(r31) + rlwinm. r0, r0, 0, 0x1d, 0x1d + beq lbl_80384068 + li r31, 1 + b lbl_8038406C +lbl_80384068: + li r31, 0 +lbl_8038406C: + li r3, 0 + li r4, 0 + bl UnlockSram + mr r3, r31 + lwz r0, 0x24(r1) + lwz r31, 0x1c(r1) + addi r1, r1, 0x20 + mtlr r0 + blr + +} +#pragma pop +/* clang-format on */ +#endif +void OSSetSoundMode(u32 mode) { + OSSram* sram; + mode <<= 2; + mode &= 4; + + sram = __OSLockSramHACK(); + if (mode == (sram->flags & 4)) { + __OSUnlockSram(FALSE); + return; + } + + sram->flags &= ~4; + sram->flags |= mode; + __OSUnlockSram(TRUE); +} + +#ifdef FULL_FRANK +u32 OSGetProgressiveMode() { + OSSram* sram; + u32 mode; + + sram = __OSLockSramHACK(); + mode = (sram->flags & 0x80) >> 7; + __OSUnlockSram(FALSE); + return mode; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level +#pragma optimizewithasm off +asm u32 OSGetProgressiveMode() { + nofralloc +/* 80384134 00381094 7C 08 02 A6 */ mflr r0 +/* 80384138 00381098 3C 60 80 54 */ lis r3, Scb@ha +/* 8038413C 0038109C 90 01 00 04 */ stw r0, 4(r1) +/* 80384140 003810A0 94 21 FF E8 */ stwu r1, -0x18(r1) +/* 80384144 003810A4 93 E1 00 14 */ stw r31, 0x14(r1) +/* 80384148 003810A8 3B E3 15 A0 */ addi r31, r3, Scb@l +/* 8038414C 003810AC 4B FF D5 15 */ bl OSDisableInterrupts +/* 80384150 003810B0 80 1F 00 48 */ lwz r0, 0x48(r31) +/* 80384154 003810B4 38 9F 00 48 */ addi r4, r31, 0x48 +/* 80384158 003810B8 2C 00 00 00 */ cmpwi r0, 0 +/* 8038415C 003810BC 41 82 00 10 */ beq lbl_8038416C +/* 80384160 003810C0 4B FF D5 29 */ bl OSRestoreInterrupts +/* 80384164 003810C4 3B E0 00 00 */ li r31, 0 +/* 80384168 003810C8 48 00 00 10 */ b lbl_80384178 +lbl_8038416C: +/* 8038416C 003810CC 90 7F 00 44 */ stw r3, 0x44(r31) +/* 80384170 003810D0 38 00 00 01 */ li r0, 1 +/* 80384174 003810D4 90 04 00 00 */ stw r0, 0(r4) +lbl_80384178: +/* 80384178 003810D8 88 1F 00 13 */ lbz r0, 0x13(r31) +/* 8038417C 003810DC 38 60 00 00 */ li r3, 0 +/* 80384180 003810E0 38 80 00 00 */ li r4, 0 +/* 80384184 003810E4 54 1F CF FE */ rlwinm r31, r0, 0x19, 0x1f, 0x1f +/* 80384188 003810E8 4B FF FA 05 */ bl UnlockSram +/* 8038418C 003810EC 7F E3 FB 78 */ mr r3, r31 +/* 80384190 003810F0 80 01 00 1C */ lwz r0, 0x1c(r1) +/* 80384194 003810F4 83 E1 00 14 */ lwz r31, 0x14(r1) +/* 80384198 003810F8 38 21 00 18 */ addi r1, r1, 0x18 +/* 8038419C 003810FC 7C 08 03 A6 */ mtlr r0 +/* 803841A0 00381100 4E 80 00 20 */ blr +} +#pragma pop +/* clang-format on */ +#endif + +void OSSetProgressiveMode(u32 mode) { + OSSram* sram; + mode <<= 7; + mode &= 0x80; + + sram = __OSLockSramHACK(); + if (mode == (sram->flags & 0x80)) { + __OSUnlockSram(FALSE); + return; + } + + sram->flags &= ~0x80; + sram->flags |= mode; + __OSUnlockSram(TRUE); +} + +#ifdef FULL_FRANK +u8 OSGetLanguage() { + OSSram* sram; + u8 language; + + sram = __OSLockSramHACK(); + language = sram->language; + __OSUnlockSram(FALSE); + return language; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level +#pragma optimizewithasm off +asm u8 OSGetLanguage() { + nofralloc + mflr r0 + lis r3, Scb@ha + stw r0, 4(r1) + stwu r1, -0x18(r1) + stw r31, 0x14(r1) + addi r31, r3, Scb@l + bl OSDisableInterrupts + lwz r0, 0x48(r31) + addi r4, r31, 0x48 + cmpwi r0, 0 + beq lbl_80384280 + bl OSRestoreInterrupts + li r31, 0 + b lbl_8038428C +lbl_80384280: + stw r3, 0x44(r31) + li r0, 1 + stw r0, 0(r4) +lbl_8038428C: + lbz r31, 0x12(r31) + li r3, 0 + li r4, 0 + bl UnlockSram + mr r3, r31 + lwz r0, 0x1c(r1) + lwz r31, 0x14(r1) + addi r1, r1, 0x18 + mtlr r0 + blr +} +#pragma pop +/* clang-format on */ +#endif + +#ifdef FULL_FRANK +u16 OSGetWirelessID(s32 channel) { + OSSramEx* sram; + u16 id; + + sram = __OSLockSramEx(); + id = sram->wirelessPadID[channel]; + __OSUnlockSramEx(FALSE); + return id; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level +#pragma optimizewithasm off + +asm u16 OSGetWirelessID(s32 channel) { + nofralloc + mflr r0 + lis r4, Scb@ha + stw r0, 4(r1) + stwu r1, -0x20(r1) + stw r31, 0x1c(r1) + addi r31, r4, Scb@l + stw r30, 0x18(r1) + addi r30, r3, 0 + bl OSDisableInterrupts + lwz r0, 0x48(r31) + addi r4, r31, 0x48 + cmpwi r0, 0 + beq lbl_803842F4 + bl OSRestoreInterrupts + li r3, 0 + b lbl_80384304 +lbl_803842F4: + stw r3, 0x44(r31) + li r0, 1 + addi r3, r31, 0x14 + stw r0, 0(r4) +lbl_80384304: + slwi r0, r30, 1 + add r3, r3, r0 + lhz r31, 0x1c(r3) + li r3, 0 + li r4, 0x14 + bl UnlockSram + mr r3, r31 + lwz r0, 0x24(r1) + lwz r31, 0x1c(r1) + lwz r30, 0x18(r1) + addi r1, r1, 0x20 + mtlr r0 + blr +} +#pragma pop +/* clang-format on */ +#endif + + +void OSSetWirelessID(s32 channel, u16 id) { + OSSramEx* sram; + + sram = __OSLockSramEx(); + if (sram->wirelessPadID[channel] != id) { + sram->wirelessPadID[channel] = id; + __OSUnlockSramEx(TRUE); + return; + } + + __OSUnlockSramEx(FALSE); +} diff --git a/src/Dolphin/os/OSSync.c b/src/Dolphin/os/OSSync.c new file mode 100644 index 0000000..b5aeccf --- /dev/null +++ b/src/Dolphin/os/OSSync.c @@ -0,0 +1,29 @@ +#include "string.h" +#include "dolphin/PPCArch.h" +#include "dolphin/os.h" + +void __OSSystemCallVectorStart(); +void __OSSystemCallVectorEnd(); +static asm void SystemCallVector() { + nofralloc +entry __OSSystemCallVectorStart + mfspr r9, HID0 + ori r10, r9, 8 + mtspr HID0, r10 + isync + sync + mtspr HID0, r9 + + rfi + +entry __OSSystemCallVectorEnd + nop +} + +void __OSInitSystemCall() { + void* addr = OSPhysicalToCached(0x00C00); + memcpy(addr, __OSSystemCallVectorStart, (size_t)__OSSystemCallVectorEnd - (size_t)__OSSystemCallVectorStart); + DCFlushRangeNoSync(addr, 0x100); + __sync(); + ICInvalidateRange(addr, 0x100); +} diff --git a/src/Dolphin/os/OSThread.c b/src/Dolphin/os/OSThread.c new file mode 100644 index 0000000..3bd1e5d --- /dev/null +++ b/src/Dolphin/os/OSThread.c @@ -0,0 +1,852 @@ +#include "dolphin/os/OSPriv.h" + +static vu32 RunQueueBits; +static volatile BOOL RunQueueHint; +static vs32 Reschedule; + +static OSThreadQueue RunQueue[32]; +static OSThread IdleThread; +static OSThread DefaultThread; +static OSContext IdleContext; +static void DefaultSwitchThreadCallback(OSThread* from, OSThread* to); +static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback; + +OSThread* __OSCurrentThread : OS_BASE_CACHED + 0x00E4; +OSThreadQueue __OSActiveThreadQueue : OS_BASE_CACHED + 0x00DC; +volatile OSContext __OSCurrentContext : OS_BASE_CACHED + 0x00D4; +volatile OSContext* __OSFPUContext : OS_BASE_CACHED + 0x00D8; + +static void DefaultSwitchThreadCallback(OSThread* from, OSThread* to) {} + +extern u8 _stack_addr[]; +extern u8 _stack_end[]; + +#define AddTail(queue, thread, link) \ + do { \ + OSThread* prev; \ + \ + prev = (queue)->tail; \ + if (prev == NULL) \ + (queue)->head = (thread); \ + else \ + prev->link.next = (thread); \ + (thread)->link.prev = prev; \ + (thread)->link.next = NULL; \ + (queue)->tail = (thread); \ + } while (0) + +#define AddPrio(queue, thread, link) \ + do { \ + OSThread *prev, *next; \ + \ + for (next = (queue)->head; next && next->priority <= thread->priority; next = next->link.next) \ + ; \ + if (next == NULL) \ + AddTail(queue, thread, link); \ + else { \ + (thread)->link.next = next; \ + prev = next->link.prev; \ + next->link.prev = (thread); \ + (thread)->link.prev = prev; \ + if (prev == NULL) \ + (queue)->head = (thread); \ + else \ + prev->link.next = (thread); \ + } \ + } while (0) + +#define RemoveItem(queue, thread, link) \ + do { \ + OSThread *next, *prev; \ + next = (thread)->link.next; \ + prev = (thread)->link.prev; \ + if (next == NULL) \ + (queue)->tail = prev; \ + else \ + next->link.prev = prev; \ + if (prev == NULL) \ + (queue)->head = next; \ + else \ + prev->link.next = next; \ + } while (0) + +#define RemoveHead(queue, thread, link) \ + do { \ + OSThread* __next; \ + (thread) = (queue)->head; \ + __next = (thread)->link.next; \ + if (__next == NULL) \ + (queue)->tail = NULL; \ + else \ + __next->link.prev = NULL; \ + (queue)->head = __next; \ + } while (0) + +static inline void OSInitMutexQueue(OSMutexQueue* queue) { queue->head = queue->tail = NULL; } + +static inline void OSSetCurrentThread(OSThread* thread) { + SwitchThreadCallback(__OSCurrentThread, thread); + __OSCurrentThread = thread; +} + +void __OSThreadInit() { + OSThread* thread = &DefaultThread; + int prio; + + thread->state = OS_THREAD_STATE_RUNNING; + thread->attr = OS_THREAD_ATTR_DETACH; + thread->priority = thread->base = 16; + thread->suspend = 0; + thread->val = (void*)-1; + thread->mutex = NULL; + OSInitThreadQueue(&thread->queueJoin); + OSInitMutexQueue(&thread->queueMutex); + + __OSFPUContext = &thread->context; + + OSClearContext(&thread->context); + OSSetCurrentContext(&thread->context); + thread->stackBase = (void*)_stack_addr; + thread->stackEnd = (void*)_stack_end; + *(thread->stackEnd) = OS_THREAD_STACK_MAGIC; + + OSSetCurrentThread(thread); + OSClearStack(0); + + RunQueueBits = 0; + RunQueueHint = FALSE; + for (prio = OS_PRIORITY_MIN; prio <= OS_PRIORITY_MAX; ++prio) { + OSInitThreadQueue(&RunQueue[prio]); + } + + OSInitThreadQueue(&__OSActiveThreadQueue); + AddTail(&__OSActiveThreadQueue, thread, linkActive); + OSClearContext(&IdleContext); + Reschedule = 0; +} + +void OSInitThreadQueue(OSThreadQueue* queue) { queue->head = queue->tail = NULL; } + +OSThread* OSGetCurrentThread() { return __OSCurrentThread; } + +#ifdef FULL_FRANK +/* Code matches, stack epilogue bug*/ +s32 OSDisableScheduler() { + BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + count = Reschedule++; + OSRestoreInterrupts(enabled); + return count; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level +#pragma optimizewithasm off +asm s32 OSDisableScheduler() { + nofralloc + mflr r0 + stw r0, 4(r1) + stwu r1, -0x10(r1) + stw r31, 0xc(r1) + bl OSDisableInterrupts + lwz r4, Reschedule + addi r0, r4, 1 + stw r0, Reschedule + mr r31, r4 + bl OSRestoreInterrupts + mr r3, r31 + lwz r0, 0x14(r1) + lwz r31, 0xc(r1) + addi r1, r1, 0x10 + mtlr r0 + blr +} +/* clang-format on */ +#pragma pop +#endif + +#ifdef FULL_FRANK +/* Code matches, stack epilogue bug*/ +s32 OSEnableScheduler() { + BOOL enabled; + s32 count; + + enabled = OSDisableInterrupts(); + count = Reschedule--; + OSRestoreInterrupts(enabled); + return count; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level +#pragma optimizewithasm off +asm s32 OSEnableScheduler() { + nofralloc + mflr r0 + stw r0, 4(r1) + stwu r1, -0x10(r1) + stw r31, 0xc(r1) + bl OSDisableInterrupts + lwz r4, Reschedule + subi r0, r4, 1 + stw r0, Reschedule + mr r31, r4 + bl OSRestoreInterrupts + mr r3, r31 + lwz r0, 0x14(r1) + lwz r31, 0xc(r1) + addi r1, r1, 0x10 + mtlr r0 + blr +} +/* clang-format on */ +#pragma pop +#endif + +static void SetRun(OSThread* thread) { + thread->queue = &RunQueue[thread->priority]; + AddTail(thread->queue, thread, link); + RunQueueBits |= 1u << (OS_PRIORITY_MAX - thread->priority); + RunQueueHint = TRUE; +} +#pragma dont_inline on +static void UnsetRun(OSThread* thread) { + OSThreadQueue* queue; + queue = thread->queue; + RemoveItem(queue, thread, link); + if (queue->head == 0) + RunQueueBits &= ~(1u << (OS_PRIORITY_MAX - thread->priority)); + thread->queue = NULL; +} +#pragma dont_inline reset + +OSPriority __OSGetEffectivePriority(OSThread* thread) { + OSPriority priority; + OSMutex* mutex; + OSThread* blocked; + + priority = thread->base; + for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) { + blocked = mutex->queue.head; + if (blocked && blocked->priority < priority) { + priority = blocked->priority; + } + } + return priority; +} + +static OSThread* SetEffectivePriority(OSThread* thread, OSPriority priority) { + switch (thread->state) { + case OS_THREAD_STATE_READY: + UnsetRun(thread); + thread->priority = priority; + SetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + RemoveItem(thread->queue, thread, link); + thread->priority = priority; + AddPrio(thread->queue, thread, link); + if (thread->mutex) { + return thread->mutex->thread; + } + break; + case OS_THREAD_STATE_RUNNING: + RunQueueHint = TRUE; + thread->priority = priority; + break; + } + return NULL; +} + +static void UpdatePriority(OSThread* thread) { + OSPriority priority; + + do { + if (0 < thread->suspend) { + break; + } + priority = __OSGetEffectivePriority(thread); + if (thread->priority == priority) { + break; + } + thread = SetEffectivePriority(thread, priority); + } while (thread); +} + +static void __OSSwitchThread(OSThread* nextThread) { + OSSetCurrentThread(nextThread); + OSSetCurrentContext(&nextThread->context); + OSLoadContext(&nextThread->context); +} + +static OSThread* SelectThread(BOOL yield) { + OSContext* currentContext; + OSThread* currentThread; + OSThread* nextThread; + OSPriority priority; + OSThreadQueue* queue; + + if (0 < Reschedule) { + return 0; + } + + currentContext = OSGetCurrentContext(); + currentThread = OSGetCurrentThread(); + if (currentContext != ¤tThread->context) { + return 0; + } + + if (currentThread) { + if (currentThread->state == OS_THREAD_STATE_RUNNING) { + if (!yield) { + priority = __cntlzw(RunQueueBits); + if (currentThread->priority <= priority) { + return 0; + } + } + currentThread->state = OS_THREAD_STATE_READY; + SetRun(currentThread); + } + + if (!(currentThread->context.state & OS_CONTEXT_STATE_EXC) && + OSSaveContext(¤tThread->context)) { + return 0; + } + } + + OSSetCurrentThread(NULL); + if (RunQueueBits == 0) { + OSSetCurrentContext(&IdleContext); + do { + OSEnableInterrupts(); + while (RunQueueBits == 0) + ; + OSDisableInterrupts(); + } while (RunQueueBits == 0); + + OSClearContext(&IdleContext); + } + + RunQueueHint = FALSE; + + priority = __cntlzw(RunQueueBits); + queue = &RunQueue[priority]; + RemoveHead(queue, nextThread, link); + if (queue->head == 0) { + RunQueueBits &= ~(1u << (OS_PRIORITY_MAX - priority)); + } + nextThread->queue = NULL; + nextThread->state = OS_THREAD_STATE_RUNNING; + __OSSwitchThread(nextThread); + return nextThread; +} + +void __OSReschedule() { + if (!RunQueueHint) { + return; + } + + SelectThread(FALSE); +} + +void OSYieldThread(void) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + SelectThread(TRUE); + OSRestoreInterrupts(enabled); +} + +void OSCancelThread(OSThread* thread) { + BOOL enabled; + + enabled = OSDisableInterrupts(); + + switch (thread->state) { + case OS_THREAD_STATE_READY: + if (!(0 < thread->suspend)) { + UnsetRun(thread); + } + break; + case OS_THREAD_STATE_RUNNING: + RunQueueHint = TRUE; + break; + case OS_THREAD_STATE_WAITING: + RemoveItem(thread->queue, thread, link); + thread->queue = NULL; + if (!(0 < thread->suspend) && thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + break; + default: + OSRestoreInterrupts(enabled); + return; + } + + OSClearContext(&thread->context); + if (thread->attr & OS_THREAD_ATTR_DETACH) { + RemoveItem(&__OSActiveThreadQueue, thread, linkActive); + thread->state = 0; + } else { + thread->state = OS_THREAD_STATE_MORIBUND; + } + + __OSUnlockAllMutex(thread); + + OSWakeupThread(&thread->queueJoin); + + __OSReschedule(); + OSRestoreInterrupts(enabled); + + return; +} + +#ifdef FULL_FRANK +/* Code matches, stack epilogue bug*/ +s32 OSResumeThread(OSThread* thread) { + BOOL enabled; + s32 suspendCount; + + enabled = OSDisableInterrupts(); + suspendCount = thread->suspend--; + if (thread->suspend < 0) { + thread->suspend = 0; + } else if (thread->suspend == 0) { + switch (thread->state) { + case OS_THREAD_STATE_READY: + thread->priority = __OSGetEffectivePriority(thread); + SetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + RemoveItem(thread->queue, thread, link); + thread->priority = __OSGetEffectivePriority(thread); + AddPrio(thread->queue, thread, link); + if (thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + break; + } + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return suspendCount; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level 0 +#pragma optimizewithasm off +asm s32 OSResumeThread(OSThread* thread) { + nofralloc + mflr r0 + stw r0, 4(r1) + stwu r1, -0x28(r1) + stw r31, 0x24(r1) + stw r30, 0x20(r1) + stw r29, 0x1c(r1) + mr r29, r3 + bl OSDisableInterrupts + lwz r4, 0x2cc(r29) + addi r31, r3, 0 + addi r0, r4, -1 + stw r0, 0x2cc(r29) + mr r30, r4 + lwz r0, 0x2cc(r29) + cmpwi r0, 0 + bge lbl_80384D60 + li r0, 0 + stw r0, 0x2cc(r29) + b lbl_80384F74 +lbl_80384D60: + bne lbl_80384F74 + lhz r0, 0x2c8(r29) + cmpwi r0, 4 + beq lbl_80384E24 + bge lbl_80384F60 + cmpwi r0, 1 + beq lbl_80384D80 + b lbl_80384F60 +lbl_80384D80: + lwz r0, 0x2d4(r29) + lwz r3, 0x2f4(r29) + b lbl_80384DAC +lbl_80384D8C: + lwz r4, 0(r3) + cmplwi r4, 0 + beq lbl_80384DA8 + lwz r4, 0x2d0(r4) + cmpw r4, r0 + bge lbl_80384DA8 + mr r0, r4 +lbl_80384DA8: + lwz r3, 0x10(r3) +lbl_80384DAC: + cmplwi r3, 0 + bne lbl_80384D8C + stw r0, 0x2d0(r29) + lis r3, RunQueue@ha + addi r0, r3, RunQueue@l + lwz r3, 0x2d0(r29) + slwi r3, r3, 3 + add r0, r0, r3 + stw r0, 0x2dc(r29) + lwz r4, 0x2dc(r29) + lwz r3, 4(r4) + cmplwi r3, 0 + bne lbl_80384DE8 + stw r29, 0(r4) + b lbl_80384DEC +lbl_80384DE8: + stw r29, 0x2e0(r3) +lbl_80384DEC: + stw r3, 0x2e4(r29) + li r0, 0 + li r3, 1 + stw r0, 0x2e0(r29) + lwz r4, 0x2dc(r29) + stw r29, 4(r4) + lwz r0, 0x2d0(r29) + lwz r4, RunQueueBits + subfic r0, r0, 0x1f + slw r0, r3, r0 + or r0, r4, r0 + stw r0, RunQueueBits + stw r3, RunQueueHint + b lbl_80384F60 +lbl_80384E24: + lwz r4, 0x2e0(r29) + lwz r5, 0x2e4(r29) + cmplwi r4, 0 + bne lbl_80384E40 + lwz r3, 0x2dc(r29) + stw r5, 4(r3) + b lbl_80384E44 +lbl_80384E40: + stw r5, 0x2e4(r4) +lbl_80384E44: + cmplwi r5, 0 + bne lbl_80384E58 + lwz r3, 0x2dc(r29) + stw r4, 0(r3) + b lbl_80384E5C +lbl_80384E58: + stw r4, 0x2e0(r5) +lbl_80384E5C: + lwz r0, 0x2d4(r29) + lwz r3, 0x2f4(r29) + b lbl_80384E88 +lbl_80384E68: + lwz r4, 0(r3) + cmplwi r4, 0 + beq lbl_80384E84 + lwz r4, 0x2d0(r4) + cmpw r4, r0 + bge lbl_80384E84 + mr r0, r4 +lbl_80384E84: + lwz r3, 0x10(r3) +lbl_80384E88: + cmplwi r3, 0 + bne lbl_80384E68 + stw r0, 0x2d0(r29) + lwz r4, 0x2dc(r29) + lwz r5, 0(r4) + b lbl_80384EA4 +lbl_80384EA0: + lwz r5, 0x2e0(r5) +lbl_80384EA4: + cmplwi r5, 0 + beq lbl_80384EBC + lwz r3, 0x2d0(r5) + lwz r0, 0x2d0(r29) + cmpw r3, r0 + ble lbl_80384EA0 +lbl_80384EBC: + cmplwi r5, 0 + bne lbl_80384EF4 + lwz r3, 4(r4) + cmplwi r3, 0 + bne lbl_80384ED8 + stw r29, 0(r4) + b lbl_80384EDC +lbl_80384ED8: + stw r29, 0x2e0(r3) +lbl_80384EDC: + stw r3, 0x2e4(r29) + li r0, 0 + stw r0, 0x2e0(r29) + lwz r3, 0x2dc(r29) + stw r29, 4(r3) + b lbl_80384F1C +lbl_80384EF4: + stw r5, 0x2e0(r29) + lwz r3, 0x2e4(r5) + stw r29, 0x2e4(r5) + cmplwi r3, 0 + stw r3, 0x2e4(r29) + bne lbl_80384F18 + lwz r3, 0x2dc(r29) + stw r29, 0(r3) + b lbl_80384F1C +lbl_80384F18: + stw r29, 0x2e0(r3) +lbl_80384F1C: + lwz r3, 0x2f0(r29) + cmplwi r3, 0 + beq lbl_80384F60 + lwz r29, 8(r3) +lbl_80384F2C: + lwz r0, 0x2cc(r29) + cmpwi r0, 0 + bgt lbl_80384F60 + mr r3, r29 + bl __OSGetEffectivePriority + lwz r0, 0x2d0(r29) + addi r4, r3, 0 + cmpw r0, r4 + beq lbl_80384F60 + mr r3, r29 + bl SetEffectivePriority + or. r29, r3, r3 + bne lbl_80384F2C +lbl_80384F60: + lwz r0, RunQueueHint + cmpwi r0, 0 + beq lbl_80384F74 + li r3, 0 + bl SelectThread +lbl_80384F74: + mr r3, r31 + bl OSRestoreInterrupts + mr r3, r30 + lwz r0, 0x2c(r1) + lwz r31, 0x24(r1) + lwz r30, 0x20(r1) + lwz r29, 0x1c(r1) + addi r1, r1, 0x28 + mtlr r0 + blr +} +#pragma pop +/* clang-format on */ + +#endif + +#ifdef FULL_FRANK +/* Code matches, stack epilogue bug*/ +s32 OSSuspendThread(OSThread* thread) { + BOOL enabled; + s32 suspendCount; + + enabled = OSDisableInterrupts(); + suspendCount = thread->suspend++; + if (suspendCount == 0) { + switch (thread->state) { + case OS_THREAD_STATE_RUNNING: + RunQueueHint = TRUE; + thread->state = OS_THREAD_STATE_READY; + break; + case OS_THREAD_STATE_READY: + UnsetRun(thread); + break; + case OS_THREAD_STATE_WAITING: + RemoveItem(thread->queue, thread, link); + thread->priority = 32; + AddTail(thread->queue, thread, link); + if (thread->mutex) { + UpdatePriority(thread->mutex->thread); + } + break; + } + + __OSReschedule(); + } + OSRestoreInterrupts(enabled); + return suspendCount; +} +#else +/* clang-format off */ +#pragma push +#pragma optimization_level 0 +#pragma optimizewithasm off +asm s32 OSSuspendThread(OSThread* thread) { + nofralloc + mflr r0 + stw r0, 4(r1) + stwu r1, -0x20(r1) + stw r31, 0x1c(r1) + stw r30, 0x18(r1) + stw r29, 0x14(r1) + mr r29, r3 + bl OSDisableInterrupts + lwz r4, 0x2cc(r29) + addi r31, r3, 0 + addi r0, r4, 1 + or. r30, r4, r4 + stw r0, 0x2cc(r29) + bne lbl_803850E4 + lhz r0, 0x2c8(r29) + cmpwi r0, 3 + beq lbl_803850D0 + bge lbl_80384FF4 + cmpwi r0, 1 + beq lbl_80385010 + bge lbl_80385000 + b lbl_803850D0 +lbl_80384FF4: + cmpwi r0, 5 + bge lbl_803850D0 + b lbl_8038501C +lbl_80385000: + li r0, 1 + stw r0, RunQueueHint + sth r0, 0x2c8(r29) + b lbl_803850D0 +lbl_80385010: + mr r3, r29 + bl UnsetRun + b lbl_803850D0 +lbl_8038501C: + lwz r4, 0x2e0(r29) + lwz r5, 0x2e4(r29) + cmplwi r4, 0 + bne lbl_80385038 + lwz r3, 0x2dc(r29) + stw r5, 4(r3) + b lbl_8038503C +lbl_80385038: + stw r5, 0x2e4(r4) +lbl_8038503C: + cmplwi r5, 0 + bne lbl_80385050 + lwz r3, 0x2dc(r29) + stw r4, 0(r3) + b lbl_80385054 +lbl_80385050: + stw r4, 0x2e0(r5) +lbl_80385054: + li r0, 0x20 + stw r0, 0x2d0(r29) + lwz r4, 0x2dc(r29) + lwz r3, 4(r4) + cmplwi r3, 0 + bne lbl_80385074 + stw r29, 0(r4) + b lbl_80385078 +lbl_80385074: + stw r29, 0x2e0(r3) +lbl_80385078: + stw r3, 0x2e4(r29) + li r0, 0 + stw r0, 0x2e0(r29) + lwz r3, 0x2dc(r29) + stw r29, 4(r3) + lwz r3, 0x2f0(r29) + cmplwi r3, 0 + beq lbl_803850D0 + lwz r29, 8(r3) +lbl_8038509C: + lwz r0, 0x2cc(r29) + cmpwi r0, 0 + bgt lbl_803850D0 + mr r3, r29 + bl __OSGetEffectivePriority + lwz r0, 0x2d0(r29) + addi r4, r3, 0 + cmpw r0, r4 + beq lbl_803850D0 + mr r3, r29 + bl SetEffectivePriority + or. r29, r3, r3 + bne lbl_8038509C +lbl_803850D0: + lwz r0, RunQueueHint + cmpwi r0, 0 + beq lbl_803850E4 + li r3, 0 + bl SelectThread +lbl_803850E4: + mr r3, r31 + bl OSRestoreInterrupts + mr r3, r30 + lwz r0, 0x24(r1) + lwz r31, 0x1c(r1) + lwz r30, 0x18(r1) + lwz r29, 0x14(r1) + addi r1, r1, 0x20 + mtlr r0 + blr +} +#pragma pop +/* clang-format on */ +#endif + +void OSSleepThread(OSThreadQueue* queue) { + BOOL enabled; + OSThread* currentThread; + + enabled = OSDisableInterrupts(); + currentThread = OSGetCurrentThread(); + + currentThread->state = OS_THREAD_STATE_WAITING; + currentThread->queue = queue; + AddPrio(queue, currentThread, link); + RunQueueHint = TRUE; + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +void OSWakeupThread(OSThreadQueue* queue) { + BOOL enabled; + OSThread* thread; + + enabled = OSDisableInterrupts(); + while (queue->head) { + RemoveHead(queue, thread, link); + thread->state = OS_THREAD_STATE_READY; + if (!(0 < thread->suspend)) { + SetRun(thread); + } + } + __OSReschedule(); + OSRestoreInterrupts(enabled); +} + +BOOL OSSetThreadPriority(OSThread* thread, s32 prio) { + BOOL enabled; + + if (prio < OS_PRIORITY_MIN || prio > OS_PRIORITY_MAX) { + return FALSE; + } + + enabled = OSDisableInterrupts(); + + if (thread->base != prio) { + thread->base = prio; + UpdatePriority(thread); + __OSReschedule(); + } + + OSRestoreInterrupts(enabled); + return TRUE; +} + +OSPriority OSGetThreadPriority(OSThread *thread) { + return thread->base; +} + +void OSClearStack(u8 val) { + register u32 sp; + register u32* p; + register u32 pattern; + + pattern = ((u32)val << 24) | ((u32)val << 16) | ((u32)val << 8) | (u32)val; + sp = OSGetStackPointer(); + for (p = __OSCurrentThread->stackEnd + 1; p < (u32*)sp; ++p) { + *p = pattern; + } +} diff --git a/src/Dolphin/os/OSTime.c b/src/Dolphin/os/OSTime.c new file mode 100644 index 0000000..4250798 --- /dev/null +++ b/src/Dolphin/os/OSTime.c @@ -0,0 +1,137 @@ +#include <dolphin/os.h> + +#define OS_TIME_MONTH_MAX 12 +#define OS_TIME_WEEK_DAY_MAX 7 +#define OS_TIME_YEAR_DAY_MAX 365 + +// End of each month in standard year +static s32 YearDays[OS_TIME_MONTH_MAX] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; +// End of each month in leap year +static s32 LeapYearDays[OS_TIME_MONTH_MAX] = {0, 31, 60, 91, 121, 152, + 182, 213, 244, 274, 305, 335}; + +asm OSTime OSGetTime(void) { + // clang-format off + nofralloc + + mftbu r3 + mftb r4 + + // Check for possible carry from TBL to TBU + mftbu r5 + cmpw r3, r5 + bne OSGetTime + + blr + // clang-format on +} + +asm OSTick OSGetTick(void){ + // clang-format off + nofralloc + + mftb r3 + blr + // clang-format on +} + +#define OS_SYSTEMTIME_BASE 0x30D8 + +OSTime __OSGetSystemTime(void) { + BOOL enabled; + OSTime* timeAdjustAddr = (OSTime*)(OS_BASE_CACHED + OS_SYSTEMTIME_BASE); + OSTime result; + + enabled = OSDisableInterrupts(); + result = *timeAdjustAddr + OSGetTime(); + OSRestoreInterrupts(enabled); + + return result; +} + +OSTime __OSTimeToSystemTime(OSTime time) { + BOOL enabled; + OSTime* timeAdjustAddr = (OSTime*)(OS_BASE_CACHED + OS_SYSTEMTIME_BASE); + OSTime result; + + enabled = OSDisableInterrupts(); + result = *timeAdjustAddr + time; + OSRestoreInterrupts(enabled); + + return result; +} + +static BOOL IsLeapYear(s32 year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); } + +static s32 GetYearDays(s32 year, s32 mon) { + return (IsLeapYear(year) ? LeapYearDays : YearDays)[mon]; +} + +static s32 GetLeapDays(s32 year) { + if (year < 1) { + return 0; + } + return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400; +} + +static void GetDates(s32 days, OSCalendarTime* cal) { + s32 year; + s32 totalDays; + s32* p_days; + s32 month; + cal->wday = (days + 6) % OS_TIME_WEEK_DAY_MAX; + + for (year = days / OS_TIME_YEAR_DAY_MAX; + days < (totalDays = year * OS_TIME_YEAR_DAY_MAX + GetLeapDays(year));) { + year--; + } + + days -= totalDays; + cal->year = year; + cal->yday = days; + + p_days = IsLeapYear(year) ? LeapYearDays : YearDays; + month = OS_TIME_MONTH_MAX; + while (days < p_days[--month]) { + ; + } + cal->mon = month; + cal->mday = days - p_days[month] + 1; +} + +#define BIAS (2000 * 365 + (2000 + 3) / 4 - (2000 - 1) / 100 + (2000 - 1) / 400) + +#pragma push +#pragma dont_inline on +void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td) { + int days; + int secs; + OSTime d; + + d = ticks % OSSecondsToTicks(1); + if (d < 0) { + d += OSSecondsToTicks(1); + } + td->usec = (int)(OSTicksToMicroseconds(d) % 1000); + td->msec = (int)(OSTicksToMilliseconds(d) % 1000); + + ticks -= d; + days = (int)(OSTicksToSeconds(ticks) / 86400 + BIAS); + secs = (int)(OSTicksToSeconds(ticks) % 86400); + if (secs < 0) { + days -= 1; + secs += 24 * 60 * 60; + } + + GetDates(days, td); + + td->hour = secs / 60 / 60; + td->min = (secs / 60) % 60; + td->sec = secs % 60; +} +#pragma dont_inline reset + +OSTime OSCalendarTimeToTicks(OSCalendarTime* time) { + ; + ; +} diff --git a/src/Dolphin/os/__ppc_eabi_init.cpp b/src/Dolphin/os/__ppc_eabi_init.cpp index a0e7574..67c85be 100644 --- a/src/Dolphin/os/__ppc_eabi_init.cpp +++ b/src/Dolphin/os/__ppc_eabi_init.cpp @@ -1,5 +1,3 @@ -// This file was taken from the Metroid Prime decompilation project. -// https://github.com/PrimeDecomp/prime/blob/main/src/Dolphin/os/__ppc_eabi_init.cpp #include "dolphin/__ppc_eabi_init.h" #include "dolphin/PPCArch.h" @@ -10,37 +8,39 @@ void __OSPSInit(); void __OSCacheInit(); asm void __init_hardware(void) { - nofralloc - mfmsr r0 - ori r0, r0, 0x2000 - mtmsr r0 + // clang-format off + nofralloc + mfmsr r0 + ori r0, r0, 0x2000 + mtmsr r0 - mflr r31 - bl __OSPSInit - bl __OSCacheInit - mtlr r31 - blr + mflr r31 + bl __OSPSInit + bl __OSCacheInit + mtlr r31 + blr + // clang-format on } asm void __flush_cache(register void* address, register unsigned int size) { - // clang-format off - nofralloc - lis r5, ~0 - ori r5, r5, ~14 - and r5, r5, r3 - subf r3, r5, r3 - add r4, r4, r3 + // clang-format off + nofralloc + lis r5, ~0 + ori r5, r5, ~14 + and r5, r5, r3 + subf r3, r5, r3 + add r4, r4, r3 -loop: - dcbst r0, r5 - sync - icbi r0, r5 - addic r5, r5, 8 - subic. r4, r4, 8 - bge loop - isync - blr - // clang-format on +loop: + dcbst r0, r5 + sync + icbi r0, r5 + addic r5, r5, 8 + subic. r4, r4, 8 + bge loop + isync + blr + // clang-format on } void __init_user() { __init_cpp(); } @@ -50,14 +50,14 @@ __declspec(section ".init") extern voidfunctionptr _ctors[]; __declspec(section ".init") extern voidfunctionptr _dtors[]; void __init_cpp(void) { - voidfunctionptr* constructor; + voidfunctionptr* constructor; - /* - * call static initializers - */ - for (constructor = _ctors; *constructor; constructor++) { - (*constructor)(); - } + /* + * call static initializers + */ + for (constructor = _ctors; *constructor; constructor++) { + (*constructor)(); + } } void _ExitProcess(void) { PPCHalt(); } diff --git a/src/Dolphin/os/__start.c b/src/Dolphin/os/__start.c index 4cb44e2..f180de8 100644 --- a/src/Dolphin/os/__start.c +++ b/src/Dolphin/os/__start.c @@ -1,54 +1,47 @@ -// This file was taken from the Super Mario Sunshine decompilation project. -// https://github.com/doldecomp/sms/blob/master/src/os/__start.c #include "dolphin/__start.h" +#include "__ppc_eabi_linker.h" -#pragma section code_type ".init" - -void __check_pad3(void) -{ - if ((Pad3Button & 0x0eef) == 0x0eef) { - OSResetSystem(OS_RESET_RESTART, 0, FALSE); - } - return; +void __check_pad3(void) { + if ((Pad3Button & 0x0eef) == 0x0eef) { + OSResetSystem(OS_RESET_RESTART, 0, FALSE); + } + return; } -#ifndef LD_TEST -// clang-format off - -__declspec (weak) asm void __start(void) -{ - nofralloc +__declspec(weak) asm void __start(void) { + // clang-format off + nofralloc bl __init_registers - bl __init_hardware - li r0, -1 - stwu r1, -8(r1) - stw r0, 4(r1) - stw r0, 0(r1) - bl __init_data - li r0, 0 - lis r6, EXCEPTIONMASK_ADDR@ha - addi r6, r6, EXCEPTIONMASK_ADDR@l - stw r0, 0(r6) - lis r6, BOOTINFO2_ADDR@ha - addi r6, r6, BOOTINFO2_ADDR@l - lwz r6, 0(r6) + bl __init_hardware + li r0, -1 + stwu r1, -8(r1) + stw r0, 4(r1) + stw r0, 0(r1) + bl __init_data + li r0, 0 + lis r6, EXCEPTIONMASK_ADDR@ha + addi r6, r6, EXCEPTIONMASK_ADDR@l + stw r0, 0(r6) + lis r6, BOOTINFO2_ADDR@ha + addi r6, r6, BOOTINFO2_ADDR@l + lwz r6, 0(r6) _check_TRK: - cmplwi r6, 0 - beq _load_lomem_debug_flag - lwz r7, OS_BI2_DEBUGFLAG_OFFSET(r6) - b _check_debug_flag - + cmplwi r6, 0 + beq _load_lomem_debug_flag + lwz r7, OS_BI2_DEBUGFLAG_OFFSET(r6) + b _check_debug_flag + _load_lomem_debug_flag: lis r5, ARENAHI_ADDR@ha addi r5, r5, ARENAHI_ADDR@l - lwz r5, 0(r5) - cmplwi r5, 0 - beq _goto_main - lis r7, DEBUGFLAG_ADDR@ha - addi r7, r7, DEBUGFLAG_ADDR@l - lwz r7, 0(r7) - + lwz r5, 0(r5) + cmplwi r5, 0 + beq _goto_main + lis r7, DEBUGFLAG_ADDR@ha + addi r7, r7, DEBUGFLAG_ADDR@l + lwz r7, 0(r7) + _check_debug_flag: li r5, 0 cmplwi r7, 2 @@ -62,7 +55,7 @@ _goto_inittrk: addi r6, r6, InitMetroTRK@l mtlr r6 blrl - + _goto_main: lis r6, BOOTINFO2_ADDR@ha addi r6, r6, BOOTINFO2_ADDR@l @@ -105,31 +98,22 @@ _end_of_parseargs: beq _check_pad3 andi. r3, r3, 0x7fff cmplwi r3, 1 - bne _skip_crc + bne _goto_skip_init_bba _check_pad3: bl __check_pad3 -_skip_crc: +_goto_skip_init_bba: bl __init_user mr r3, r14 mr r4, r15 bl main b exit + // clang-format on } -#else -__declspec(weak) void __start() { - int ret; - int argc = 0; - char **argv = NULL; - __init_user(); - ret = main(argc, argv); - exit(ret); -} -#endif -asm static void __init_registers(void) -{ +asm static void __init_registers(void) { + // clang-format off nofralloc lis r1, _stack_addr@h ori r1, r1, _stack_addr@l @@ -138,51 +122,40 @@ asm static void __init_registers(void) lis r13, _SDA_BASE_@h ori r13, r13, _SDA_BASE_@l blr + // clang-format on } -__declspec(section ".init") extern __rom_copy_info _rom_copy_info[]; -__declspec(section ".init") extern __bss_init_info _bss_init_info[]; - -// clang-format on - -inline static void __copy_rom_section(void* dst, const void* src, - unsigned long size) -{ - if (size && (dst != src)) { - memcpy(dst, src, size); - __flush_cache(dst, size); - } +inline static void __copy_rom_section(void* dst, const void* src, unsigned long size) { + if (size && (dst != src)) { + memcpy(dst, src, size); + __flush_cache(dst, size); + } } -inline static void __init_bss_section(void* dst, unsigned long size) -{ - if (size) { - memset(dst, 0, size); - } +inline static void __init_bss_section(void* dst, unsigned long size) { + if (size) { + memset(dst, 0, size); + } } #pragma scheduling off -#pragma peephole off -// peephole might have been turned off due to the inline asm peephole bug -// which turns off peephole optimizations after an inline-asm function -void __init_data(void) -{ - __rom_copy_info* dci; - __bss_init_info* bii; - - dci = _rom_copy_info; - while (TRUE) { - if (dci->size == 0) - break; - __copy_rom_section(dci->addr, dci->rom, dci->size); - dci++; - } - - bii = _bss_init_info; - while (TRUE) { - if (bii->size == 0) - break; - __init_bss_section(bii->addr, bii->size); - bii++; - } +void __init_data(void) { + __rom_copy_info* dci; + __bss_init_info* bii; + + dci = _rom_copy_info; + while (TRUE) { + if (dci->size == 0) + break; + __copy_rom_section(dci->addr, dci->rom, dci->size); + dci++; + } + + bii = _bss_init_info; + while (TRUE) { + if (bii->size == 0) + break; + __init_bss_section(bii->addr, bii->size); + bii++; + } } |