From 42d942d33c3a1ac356146096b3b22b8a966fbf29 Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Sun, 7 Jul 2024 18:41:48 -0400 Subject: [PATCH] __start OK, OSReboot almost --- configure.py | 4 +- include/dolphin/os/OSAlloc.h | 8 +- include/dolphin/os/OSExec.h | 4 +- include/dolphin/os/__start.h | 65 ++++++++++++ src/dolphin/os/OSAlloc.c | 200 ++++++++++++++++++++++++++++++----- src/dolphin/os/OSReboot.c | 127 ++++++++++++++++++---- src/dolphin/os/__start.c | 139 +++++++++++++++--------- 7 files changed, 447 insertions(+), 100 deletions(-) create mode 100644 include/dolphin/os/__start.h diff --git a/configure.py b/configure.py index 095a171b5..516c229c2 100644 --- a/configure.py +++ b/configure.py @@ -962,10 +962,10 @@ def JSystemLib(lib_name, objects): DolphinLib( "os", [ - Object(NonMatching, "dolphin/os/__start.c"), + Object(Matching, "dolphin/os/__start.c"), Object(Matching, "dolphin/os/OS.c"), Object(Matching, "dolphin/os/OSAlarm.c"), - Object(NonMatching, "dolphin/os/OSAlloc.c"), + Object(Matching, "dolphin/os/OSAlloc.c"), Object(Matching, "dolphin/os/OSArena.c"), Object(Matching, "dolphin/os/OSAudioSystem.c"), Object(Matching, "dolphin/os/OSCache.c"), diff --git a/include/dolphin/os/OSAlloc.h b/include/dolphin/os/OSAlloc.h index 31a69d317..a4e5d2561 100644 --- a/include/dolphin/os/OSAlloc.h +++ b/include/dolphin/os/OSAlloc.h @@ -9,16 +9,16 @@ extern "C" { typedef struct OSHeapDescriptor { /* 0x0 */ s32 size; - /* 0x4 */ struct OSHeapCell* freeList; - /* 0x8 */ struct OSHeapCell* usedList; + /* 0x4 */ struct OSHeapCell* free; + /* 0x8 */ struct OSHeapCell* allocated; } OSHeapDescriptor; typedef struct OSHeapCell { /* 0x00 */ struct OSHeapCell* prev; /* 0x04 */ struct OSHeapCell* next; - /* 0x08 */ s32 size; + /* 0x08 */ u32 size; /* 0x0C */ struct OSHeapDescriptor* hd; - /* 0x10 */ s32 usedSize; + /* 0x10 */ u32 usedSize; /* 0x14 */ char field_0x14[0x20 - 0x14]; } OSHeapCell; diff --git a/include/dolphin/os/OSExec.h b/include/dolphin/os/OSExec.h index d2878e800..a460b7eb3 100644 --- a/include/dolphin/os/OSExec.h +++ b/include/dolphin/os/OSExec.h @@ -18,9 +18,9 @@ typedef struct { } OSExecParams; static s32 PackArgs(void* param_0, u32 param_1, void* param_2); -static void Run(int param_0); +static void Run(u32 param_0); static void ReadDisc(void* param_0, s32 param_1, s32 param_2); -static void Callback(void); +static void Callback(s32 result, struct DVDCommandBlock* block); void __OSGetExecParams(OSExecParams* param_0); void __OSBootDolSimple(u32 param_0, u32 param_1, void* param_2, void* param_3, s32 param_4, u32 param_5, void* param_6); void __OSBootDol(s32 param_0, u32 param_1, char** param_2); diff --git a/include/dolphin/os/__start.h b/include/dolphin/os/__start.h new file mode 100644 index 000000000..3ce610ce1 --- /dev/null +++ b/include/dolphin/os/__start.h @@ -0,0 +1,65 @@ +#ifndef __START_H +#define __START_H + +#include "global.h" + +#ifdef __cplusplus +extern "C" { +#endif // ifdef __cplusplus + +#define PAD3_BUTTON_ADDR 0x800030E4 +#define OS_RESET_RESTART 0 +#define FALSE 0 +#define TRUE 1 +#define EXCEPTIONMASK_ADDR 0x80000044 +#define BOOTINFO2_ADDR 0x800000F4 +#define OS_BI2_DEBUGFLAG_OFFSET 0xC +#define ARENAHI_ADDR 0x80000034 +#define DEBUGFLAG_ADDR 0x800030E8 +#define DVD_DEVICECODE_ADDR 0x800030E6 +#define DOL_ADDR_LIMIT 0x80700000 + +extern void InitMetroTRK(); + +u16 Pad3Button : PAD3_BUTTON_ADDR; + +extern int main(int argc, char* argv[]); +extern void exit(int); +extern void __init_user(void); +extern void InitMetroTRK_BBA(void); +extern void OSInit(void); +extern void OSResetSystem(BOOL reset, u32 resetCode, BOOL forceMenu); + +SECTION_INIT extern void __check_pad3(void); +SECTION_INIT extern void __set_debug_bba(void); +SECTION_INIT extern u8 __get_debug_bba(void); +SECTION_INIT extern void __start(void); +SECTION_INIT extern void __init_registers(void); +SECTION_INIT extern void __init_data(void); +SECTION_INIT extern void __init_hardware(void); +SECTION_INIT extern void __flush_cache(void* addr, u32 size); + +SECTION_INIT extern u8 _stack_addr[]; +SECTION_INIT extern char _SDA_BASE_[]; +SECTION_INIT extern char _SDA2_BASE_[]; + +typedef struct __rom_copy_info { + char* rom; + char* addr; + uint size; +} __rom_copy_info; + +SECTION_INIT extern __rom_copy_info _rom_copy_info[]; + +typedef struct __bss_init_info { + char* addr; + uint size; +} __bss_init_info; + +SECTION_INIT extern __bss_init_info _bss_init_info[]; + +#ifdef __cplusplus +}; +#endif // ifdef __cplusplus + +#endif /* __START_H */ diff --git a/src/dolphin/os/OSAlloc.c b/src/dolphin/os/OSAlloc.c index af668fe81..53ccb5291 100644 --- a/src/dolphin/os/OSAlloc.c +++ b/src/dolphin/os/OSAlloc.c @@ -1,4 +1,13 @@ #include "dolphin/os/OSAlloc.h" +#include "dolphin/os/OS.h" + +#define ALIGNMENT 32 +#define MINOBJSIZE 64 + +#define HEADERSIZE 32 + +#define InRange(addr, start, end) ((u8*)(start) <= (u8*)(addr) && (u8*)(addr) < (u8*)(end)) +#define OFFSET(addr, align) (((u32)(addr) & ((align)-1))) static OSHeapCell* DLInsert(OSHeapCell* list, OSHeapCell* child) { OSHeapCell* prev = NULL; @@ -58,11 +67,62 @@ inline OSHeapCell* DLExtract(OSHeapCell* list, OSHeapCell* child) { static OSHeapDescriptor* HeapArray; +static inline void* DLAddFront(OSHeapCell* neighbor, OSHeapCell* cell) +{ + cell->next = neighbor; + cell->prev = NULL; + if (neighbor != NULL) + neighbor->prev = cell; + return cell; +} + +void* OSAllocFromHeap(OSHeapHandle heap, u32 size) +{ + OSHeapDescriptor* hd = &HeapArray[heap]; + s32 sizeAligned = OSRoundUp32B(ALIGNMENT + size); + OSHeapCell* cell; + OSHeapCell* oldTail; + u32 leftoverSpace; + + // find first cell with enough capacity + for (cell = hd->free; cell != NULL; cell = cell->next) { + if (sizeAligned <= (s32)cell->size) + break; + } + if (cell == NULL) + return NULL; + + leftoverSpace = cell->size - sizeAligned; + if (leftoverSpace < MINOBJSIZE) { + // remove this cell from the free list + hd->free = DLExtract(hd->free, cell); + } else { + // remove this cell from the free list and make a new cell out of the + // remaining space + OSHeapCell* newcell = (void*)((u8*)cell + sizeAligned); + cell->size = sizeAligned; + newcell->size = leftoverSpace; + newcell->prev = cell->prev; + newcell->next = cell->next; + if (newcell->next != NULL) + newcell->next->prev = newcell; + if (newcell->prev != NULL) + newcell->prev->next = newcell; + else + hd->free = newcell; + } + + // add the cell to the beginning of the allocated list + hd->allocated = DLAddFront(hd->allocated, cell); + + return (u8*)cell + ALIGNMENT; +} + void OSFreeToHeap(OSHeapHandle handle, void* ptr) { OSHeapDescriptor* hd = &HeapArray[handle]; OSHeapCell* cell = (OSHeapCell*)((char*)ptr - sizeof(OSHeapCell)); - hd->usedList = DLExtract(hd->usedList, cell); - hd->freeList = DLInsert(hd->freeList, cell); + hd->allocated = DLExtract(hd->allocated, cell); + hd->free = DLInsert(hd->free, cell); } volatile s32 __OSCurrHeap = -1; @@ -90,38 +150,130 @@ void* OSInitAlloc(void* lo, void* hi, s32 maxHeaps) { OSHeapDescriptor* hd = &HeapArray[i]; hd->size = -1; - hd->freeList = hd->usedList = NULL; + hd->free = hd->allocated = NULL; } __OSCurrHeap = -1; lo = (u8*)HeapArray + totalSize; - lo = OSRoundUpPtr(lo, 0x20); + lo = OSRoundUpPtr(lo, 0x20); - ArenaStart = lo; - ArenaEnd = OSRoundDownPtr(hi, 0x20); + ArenaStart = lo; + ArenaEnd = OSRoundDownPtr(hi, 0x20); return ArenaStart; } OSHeapHandle OSCreateHeap(void* start, void* end) { int i; - OSHeapCell* cell = OSRoundUpPtr(start, 0x20); - end = OSRoundDownPtr(end, 0x20); - - for (i = 0; i < NumHeaps; i++) { - OSHeapDescriptor* hd = &HeapArray[i]; - - if (hd->size < 0) { - hd->size = (u8*)end - (u8*)cell; - cell->prev = NULL; - cell->next = NULL; - cell->size = hd->size; - hd->freeList = cell; - hd->usedList = NULL; - return i; - } - } - - return -1; + OSHeapCell* cell = OSRoundUpPtr(start, 0x20); + end = OSRoundDownPtr(end, 0x20); + + for (i = 0; i < NumHeaps; i++) { + OSHeapDescriptor* hd = &HeapArray[i]; + + if (hd->size < 0) { + hd->size = (u8*)end - (u8*)cell; + cell->prev = NULL; + cell->next = NULL; + cell->size = hd->size; + hd->free = cell; + hd->allocated = NULL; + return i; + } + } + + return -1; +} + +void OSDestroyHeap(OSHeapHandle heap) { + OSHeapDescriptor* hd; + long size; + + hd = &HeapArray[heap]; + + hd->size = -1; +} + +// custom macro for OSCheckHeap +#define ASSERTREPORT(line, cond) \ + if (!(cond)) { OSReport("OSCheckHeap: Failed " #cond " in %d", line); return -1; } + +long OSCheckHeap(OSHeapHandle heap) { + OSHeapDescriptor* hd; + OSHeapCell* cell; + long total = 0; + long free = 0; + + ASSERTREPORT(0x37D, HeapArray); + ASSERTREPORT(0x37E, 0 <= heap && heap < NumHeaps); + hd = &HeapArray[heap]; + ASSERTREPORT(0x381, 0 <= hd->size); + + ASSERTREPORT(0x383, hd->allocated == NULL || hd->allocated->prev == NULL); + + for(cell = hd->allocated; cell; cell = cell->next) { + ASSERTREPORT(0x386, InRange(cell, ArenaStart, ArenaEnd)); + ASSERTREPORT(0x387, OFFSET(cell, ALIGNMENT) == 0); + ASSERTREPORT(0x388, cell->next == NULL || cell->next->prev == cell); + ASSERTREPORT(0x389, MINOBJSIZE <= cell->size); + ASSERTREPORT(0x38A, OFFSET(cell->size, ALIGNMENT) == 0); + total += cell->size; + ASSERTREPORT(0x38D, 0 < total && total <= hd->size); +#ifdef ENABLE_HEAPDESC + ASSERTREPORT(0x390, cell->hd == hd); + ASSERTREPORT(0x391, HEADERSIZE + cell->requested <= cell->size); +#endif + } + + + ASSERTREPORT(0x395, hd->free == NULL || hd->free->prev == NULL); + + for(cell = hd->free; cell; cell = cell->next) { + ASSERTREPORT(0x398, InRange(cell, ArenaStart, ArenaEnd)); + ASSERTREPORT(0x399, OFFSET(cell, ALIGNMENT) == 0); + ASSERTREPORT(0x39A, cell->next == NULL || cell->next->prev == cell); + ASSERTREPORT(0x39B, MINOBJSIZE <= cell->size); + ASSERTREPORT(0x39C, OFFSET(cell->size, ALIGNMENT) == 0); + ASSERTREPORT(0x39D, cell->next == NULL || (char*) cell + cell->size < (char*) cell->next); + total += cell->size; + free = (cell->size + free); + free -= HEADERSIZE; + ASSERTREPORT(0x3A1, 0 < total && total <= hd->size); +#ifdef ENABLE_HEAPDESC + ASSERTREPORT(0x3A4, cell->hd == NULL); +#endif + } + ASSERTREPORT(0x3A8, total == hd->size); + return free; +} + +s32 OSReferentSize(void* ptr) { + OSHeapCell* cell; + + cell = (void*)((u32)ptr - HEADERSIZE); + return (long)((u32)cell->size - HEADERSIZE); +} + +void OSDumpHeap(OSHeapHandle heap) { + OSHeapDescriptor* hd; + OSHeapCell* cell; + + OSReport("\nOSDumpHeap(%d):\n", heap); + hd = &HeapArray[heap]; + if (hd->size < 0) { + OSReport("--------Inactive\n"); + return; + } + + OSReport("addr size end prev next\n"); + OSReport("--------Allocated\n"); + + for(cell = hd->allocated; cell; cell = cell->next) { + OSReport("%x %d %x %x %x\n", cell, cell->size, (char*)cell + cell->size, cell->prev, cell->next); + } + OSReport("--------Free\n"); + for(cell = hd->free; cell; cell = cell->next) { + OSReport("%x %d %x %x %x\n", cell, cell->size, (char*)cell + cell->size, cell->prev, cell->next); + } } diff --git a/src/dolphin/os/OSReboot.c b/src/dolphin/os/OSReboot.c index 66b269b56..91f763f12 100644 --- a/src/dolphin/os/OSReboot.c +++ b/src/dolphin/os/OSReboot.c @@ -1,29 +1,118 @@ +#include "dolphin/os/Os.h" #include "dolphin/os/OSReboot.h" -#include "dolphin/os/OSContext.h" -#include "dolphin/os/OSExec.h" -void __OSReboot(u32 resetCode, u32 bootDol) { - struct OSContext context; - char* iVar1; - OSDisableInterrupts(); - OSSetArenaLo((void*)0x81280000); - OSSetArenaHi((void*)0x812f0000); - OSClearContext(&context); - OSSetCurrentContext(&context); - iVar1 = NULL; - __OSBootDol(bootDol, resetCode | 0x80000000, &iVar1); +static void* SaveStart = NULL; +static void* SaveEnd = NULL; +static volatile BOOL Prepared; + +extern u32 OS_RESET_CODE : 0x800030F0; +extern u8 OS_REBOOT_BOOL : 0x800030E2; // unknown function, set to true by __OSReboot +extern u32 UNK_817FFFF8 : 0x817FFFF8; +extern u32 UNK_817FFFFC : 0x817FFFFC; + +#define OS_BOOTROM_ADDR 0x81300000 + +typedef struct _ApploaderHeader { + /* 0x00 */ char date[16]; + /* 0x10 */ u32 entry; + /* 0x14 */ u32 size; + /* 0x18 */ u32 rebootSize; + /* 0x1C */ u32 reserved2; +} ApploaderHeader; // Size: 0x20 + +static ApploaderHeader Header ALIGN_DECL(32); + +asm static void Run(register u32 addr) { + nofralloc + + sync + isync + mtlr addr + blr +} + +void ReadApploader(DVDCommandBlock* dvdCmd, void* addr, u32 offset, u32 numBytes); + +void ReadApploader(DVDCommandBlock* dvdCmd, void* addr, u32 offset, u32 numBytes) { + /* Not sure if this inline is correct - might need to call other inlines */ + while (Prepared == FALSE) { + } + DVDReadAbsAsyncForBS(dvdCmd, addr, numBytes, offset + 0x2440, NULL); + + while (TRUE) { + switch (dvdCmd->state) { + case 0: + break; + case 1: + default: + continue; + case -1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + __OSDoHotReset(UNK_817FFFFC); + continue; + } + break; + } } -static void* SaveStart; +static void Callback(s32 result, struct DVDCommandBlock* block) { Prepared = TRUE; } + +void __OSReboot(u32 resetCode, u32 bootDol) { + /* Nonmatching */ + OSContext exceptionContext; + DVDCommandBlock dvdCmd; + DVDCommandBlock dvdCmd2; + u32 numBytes; + u32 offset; + + OSDisableInterrupts(); + + UNK_817FFFFC = 1; + UNK_817FFFF8 = 1; + OS_RESET_CODE = resetCode; + OS_REBOOT_BOOL = TRUE; + BOOT_REGION_START = (u32)SaveStart; + BOOT_REGION_END = (u32)SaveEnd; + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + DVDInit(); + DVDSetAutoInvalidation(TRUE); + + __DVDPrepareResetAsync(Callback); + + if (!DVDCheckDisk()) { + __OSDoHotReset(UNK_817FFFFC); + } + + __OSMaskInterrupts(0xffffffe0); + __OSUnmaskInterrupts(0x400); -static void* SaveEnd; + OSEnableInterrupts(); + + offset = 0; + numBytes = 32; + ReadApploader(&dvdCmd, (void*)&Header, offset, numBytes); + + offset = Header.size + 0x20; + numBytes = OSRoundUp32B(Header.rebootSize); + ReadApploader(&dvdCmd2, (void*)(OS_BOOTROM_ADDR), offset, numBytes); + + ICInvalidateRange((void*)(OS_BOOTROM_ADDR), numBytes); + OSDisableInterrupts(); + ICFlashInvalidate(); + Run(OS_BOOTROM_ADDR); +} void OSSetSaveRegion(void* start, void* end) { SaveStart = start; SaveEnd = end; } - -void OSGetSaveRegion(void** start, void** end) { - *start = SaveStart; - *end = SaveEnd; -} diff --git a/src/dolphin/os/__start.c b/src/dolphin/os/__start.c index 76b189c17..62698b6b1 100644 --- a/src/dolphin/os/__start.c +++ b/src/dolphin/os/__start.c @@ -1,35 +1,9 @@ #include "stdlib.h" #include "global.h" -// #include "init.h" +#include "dolphin/os/OS.h" +#include "dolphin/os/__start.h" -// -// Forward References: -// - -SECTION_INIT void __check_pad3(void); -SECTION_INIT void __set_debug_bba(void); -SECTION_INIT u8 __get_debug_bba(void); -SECTION_INIT void __start(void); - -// -// External References: -// - -void main(); -void OSInit(); -void OSResetSystem(s32, s32, s32); -void __init_user(); void DBInit(); -void InitMetroTRK(); -void InitMetroTRK_BBA(); -extern u8 data_804516D0; -void __init_data(); -void __init_hardware(); -void __init_registers(); - -// -// Declarations: -// SECTION_INIT void __check_pad3(void) { if ((*(u16*)0x800030E4 & 0xEEF) == 0xEEF) { @@ -37,14 +11,6 @@ SECTION_INIT void __check_pad3(void) { } } -void __set_debug_bba(void) { - data_804516D0 = 1; -} - -SECTION_INIT u8 __get_debug_bba(void) { - return data_804516D0; -} - SECTION_INIT asm void __start(void) { // clang-format off nofralloc @@ -83,13 +49,8 @@ SECTION_INIT asm void __start(void) { cmplwi r7, 2 beq lbl_800031E8 cmplwi r7, 3 - li r5, 1 - beq lbl_800031E8 - cmplwi r7, 4 bne lbl_800031F8 - li r5, 2 - bl __set_debug_bba - b lbl_800031F8 + li r5, 1 lbl_800031E8: lis r6, InitMetroTRK@ha @@ -139,17 +100,11 @@ SECTION_INIT asm void __start(void) { beq lbl_80003288 andi. r3, r3, 0x7fff cmplwi r3, 1 - bne lbl_8000328C + bne lbl_8000329C lbl_80003288: bl __check_pad3 -lbl_8000328C: - bl __get_debug_bba - cmplwi r3, 1 - bne lbl_8000329C - bl InitMetroTRK_BBA - lbl_8000329C: bl __init_user mr r3, r14 @@ -158,3 +113,89 @@ SECTION_INIT asm void __start(void) { b exit // clang-format on } + +asm static void __init_registers(void) +{ +#ifdef __MWERKS__ + nofralloc + lis r1, _stack_addr@h + ori r1, r1, _stack_addr@l + lis r2, _SDA2_BASE_@h + ori r2, r2, _SDA2_BASE_@l + lis r13, _SDA_BASE_@h + ori r13, r13, _SDA_BASE_@l + blr +#endif +} + +inline static void __copy_rom_section(void* dst, const void* src, u32 size) +{ + if (size && (dst != src)) { + memcpy(dst, src, size); + __flush_cache(dst, size); + } +} + +inline static void __init_bss_section(void* dst, u32 size) +{ + if (size) { + memset(dst, 0, size); + } +} + +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++; + } +} + +asm void __init_hardware() { +#ifdef __MWERKS__ // clang-format off + nofralloc + mfmsr r0 + ori r0,r0,0x2000 + mtmsr r0 + mflr r31 + bl __OSPSInit + bl __OSCacheInit + mtlr r31 + blr +#endif // clang-format on +} + +asm void __flush_cache(void* addr, u32 size) +{ +#ifdef __MWERKS__ + nofralloc + lis r5, 0xFFFFFFF1@h + ori r5, r5, 0xFFFFFFF1@l + and r5, r5, r3 + subf r3, r5, r3 + add r4, r4, r3 +loop: + dcbst 0, r5 + sync + icbi 0, r5 + addic r5, r5, 8 + addic. r4, r4, -8 + bge loop + isync + blr +#endif +}