mirror of https://github.com/zeldaret/tp
403 lines
9.9 KiB
C
403 lines
9.9 KiB
C
#include <dolphin.h>
|
|
#include <dolphin/os.h>
|
|
|
|
#include "__os.h"
|
|
#include "__dvd.h"
|
|
|
|
extern volatile u32 BOOT_REGION_START AT_ADDRESS(0x812FDFF0);
|
|
extern volatile u32 BOOT_REGION_END AT_ADDRESS(0x812FDFEC);
|
|
extern volatile u8 g_unk_800030E2 AT_ADDRESS(0x800030E2);
|
|
|
|
static int Prepared;
|
|
|
|
static int PackArgs(void* addr, s32 argc, char** argv) {
|
|
s32 numArgs;
|
|
char* bootInfo2;
|
|
char* ptr;
|
|
char** list;
|
|
u32 i;
|
|
|
|
bootInfo2 = (char*)addr;
|
|
memset(bootInfo2, 0, 0x2000);
|
|
|
|
if (argc == 0) {
|
|
*(u32*)(bootInfo2 + 8) = 0;
|
|
} else {
|
|
numArgs = argc;
|
|
ptr = bootInfo2 + 0x2000;
|
|
while (--argc >= 0) {
|
|
ptr -= strlen(argv[argc]) + 1;
|
|
strcpy(ptr, argv[argc]);
|
|
argv[argc] = (char*)(ptr - bootInfo2);
|
|
}
|
|
|
|
ptr = bootInfo2 + ((ptr - bootInfo2) & ~0x3);
|
|
ptr -= ((numArgs + 1) * 4);
|
|
list = (char**)ptr;
|
|
|
|
for (i = 0; i < numArgs + 1; i++) {
|
|
list[i] = argv[i];
|
|
}
|
|
|
|
ptr -= 4;
|
|
*(u32*)ptr = numArgs;
|
|
|
|
ASSERTMSGLINE(LINE(129, 138, 140), ptr - bootInfo2 >= 0x1000U, "OSExec: Argument list is too long");
|
|
|
|
*(u32*)(bootInfo2 + 8) = (ptr - bootInfo2);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
#ifdef __GEKKO__
|
|
static asm void Run(__REGISTER void* entryPoint) {
|
|
nofralloc
|
|
|
|
mflr r0
|
|
stw r0, 4(r1)
|
|
stwu r1, -0x18(r1)
|
|
stw r31, 0x14(r1)
|
|
mr r31, entryPoint
|
|
bl ICFlashInvalidate
|
|
sync
|
|
isync
|
|
mtlr r31
|
|
blr
|
|
|
|
lwz r0, 0x1c(r1)
|
|
lwz r31, 0x14(r1)
|
|
addi r1, r1, 0x18
|
|
mtlr r0
|
|
blr
|
|
}
|
|
#endif
|
|
|
|
static void StartDol(const OSExecParams* params, void* entry) {
|
|
OSExecParams* paramsWork = OSAllocFromArenaLo(sizeof(OSExecParams), 1);
|
|
|
|
__OSSetExecParams(params, paramsWork);
|
|
__PIRegs[9] = 7;
|
|
|
|
OSDisableInterrupts();
|
|
Run(entry);
|
|
}
|
|
|
|
static void ReadDisc(void* addr, s32 length, s32 offset) {
|
|
DVDCommandBlock block;
|
|
#if SDK_REVISION < 1
|
|
OSTime start;
|
|
#endif
|
|
|
|
DVDReadAbsAsyncPrio(&block, addr, length, offset, NULL, 0);
|
|
|
|
#if SDK_REVISION < 1
|
|
start = OSGetTime();
|
|
#endif
|
|
|
|
while (DVDGetCommandBlockStatus(&block)) {
|
|
#if SDK_REVISION < 1
|
|
if (!DVDCheckDisk() || OS_TIMER_CLOCK < (OSGetTime() - start))
|
|
#else
|
|
if (!DVDCheckDisk())
|
|
#endif
|
|
{
|
|
__OSDoHotReset(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Callback(s32, DVDCommandBlock*) {
|
|
Prepared = TRUE;
|
|
}
|
|
|
|
static int IsStreamEnabled() {
|
|
if (DVDGetCurrentDiskID()->streaming) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void __OSGetExecParams(OSExecParams* params) {
|
|
if (0x80000000 <= (u32)__OSExecParams) {
|
|
memcpy(params, __OSExecParams, sizeof(OSExecParams));
|
|
} else {
|
|
params->valid = FALSE;
|
|
}
|
|
}
|
|
|
|
void __OSSetExecParams(const OSExecParams* params, OSExecParams* addr) {
|
|
memcpy(addr, params, sizeof(OSExecParams));
|
|
__OSExecParams = addr;
|
|
}
|
|
|
|
static void StopStreaming() {
|
|
DVDCommandBlock block;
|
|
#if SDK_REVISION < 1
|
|
OSTime start;
|
|
#endif
|
|
|
|
if (!__OSIsGcam && IsStreamEnabled()) {
|
|
AISetStreamVolLeft(0);
|
|
AISetStreamVolRight(0);
|
|
DVDCancelStreamAsync(&block, NULL);
|
|
|
|
#if SDK_REVISION < 1
|
|
start = OSGetTime();
|
|
#endif
|
|
|
|
while (DVDGetCommandBlockStatus(&block)) {
|
|
#if SDK_REVISION < 1
|
|
if (!DVDCheckDisk() || OS_TIMER_CLOCK < (OSGetTime() - start))
|
|
#else
|
|
if (!DVDCheckDisk())
|
|
#endif
|
|
{
|
|
__OSDoHotReset(0);
|
|
}
|
|
}
|
|
|
|
AISetStreamPlayState(0);
|
|
}
|
|
}
|
|
|
|
static int GetApploaderPosition(void) {
|
|
static s32 apploaderPosition;
|
|
|
|
u32* tgcHeader;
|
|
s32 apploaderOffsetInTGC;
|
|
|
|
if (apploaderPosition != 0) {
|
|
return apploaderPosition;
|
|
}
|
|
|
|
if (__OSAppLoaderOffset != 0) {
|
|
tgcHeader = OSAllocFromArenaLo(0x40, DOLPHIN_ALIGNMENT);
|
|
ReadDisc(tgcHeader, 0x40, __OSAppLoaderOffset);
|
|
apploaderOffsetInTGC = tgcHeader[14];
|
|
ASSERTMSGLINE(LINE(370, 376, 378), apploaderOffsetInTGC != 0, "OSExec() or OSResetSystem(): Wrong apploader offset. Maybe converted by an\nolder version of gcm2tgc. Use gcm2tgc v.1.20 or later.");
|
|
|
|
apploaderPosition = __OSAppLoaderOffset + apploaderOffsetInTGC;
|
|
} else {
|
|
apploaderPosition = 0x2440;
|
|
}
|
|
return apploaderPosition;
|
|
}
|
|
|
|
typedef struct {
|
|
char date[16];
|
|
u32 entry;
|
|
u32 size;
|
|
u32 rebootSize;
|
|
u32 reserved2;
|
|
} AppLoaderStruct;
|
|
|
|
static AppLoaderStruct* LoadApploader() {
|
|
AppLoaderStruct* header;
|
|
|
|
header = (AppLoaderStruct*)OSAllocFromArenaLo(sizeof(AppLoaderStruct), DOLPHIN_ALIGNMENT);
|
|
ReadDisc(header, sizeof(AppLoaderStruct), GetApploaderPosition());
|
|
ASSERTMSGLINE(LINE(401, 407, 409), header->rebootSize != 0, "OSResetSystem(): old apploader");
|
|
|
|
ReadDisc((void*)0x81200000, OSRoundUp32B(header->size), GetApploaderPosition() + 0x20);
|
|
ICInvalidateRange((void*)0x81200000, OSRoundUp32B(header->size));
|
|
return header;
|
|
}
|
|
|
|
static void* LoadDol(const OSExecParams* params, AppLoaderCallback getInterface) {
|
|
appInitCallback appInit;
|
|
appGetNextCallback appGetNext;
|
|
appGetEntryCallback appGetEntry;
|
|
void* addr;
|
|
u32 length;
|
|
u32 offset;
|
|
OSExecParams* paramsWork;
|
|
|
|
getInterface(&appInit, &appGetNext, &appGetEntry);
|
|
paramsWork = (OSExecParams*)OSAllocFromArenaLo(sizeof(OSExecParams), 1);
|
|
__OSSetExecParams(params, paramsWork);
|
|
appInit((void(*)(char*))OSReport);
|
|
OSSetArenaLo(paramsWork);
|
|
|
|
while (appGetNext(&addr, &length, &offset) != 0) {
|
|
ReadDisc(addr, length, offset);
|
|
}
|
|
|
|
return appGetEntry();
|
|
}
|
|
|
|
static BOOL IsNewApploader(AppLoaderStruct* header) {
|
|
return strncmp(header->date, "2004/02/01", 10) > 0 ? TRUE : FALSE;
|
|
}
|
|
|
|
void __OSBootDolSimple(u32 doloffset, u32 restartCode, void* regionStart, void* regionEnd, BOOL argsUseDefault, s32 argc, char** argv) {
|
|
OSExecParams* params;
|
|
void* dolEntry;
|
|
AppLoaderStruct* header;
|
|
|
|
#if SDK_REVISION < 1
|
|
OSTime start;
|
|
#endif
|
|
|
|
OSDisableInterrupts();
|
|
params = (OSExecParams*)OSAllocFromArenaLo(sizeof(OSExecParams), 1);
|
|
params->valid = TRUE;
|
|
params->restartCode = restartCode;
|
|
params->regionStart = regionStart;
|
|
params->regionEnd = regionEnd;
|
|
params->argsUseDefault = argsUseDefault;
|
|
|
|
if (!argsUseDefault) {
|
|
params->argsAddr = OSAllocFromArenaLo(0x2000, 1);
|
|
PackArgs(params->argsAddr, argc, argv);
|
|
}
|
|
|
|
DVDInit();
|
|
DVDSetAutoInvalidation(TRUE);
|
|
DVDResume();
|
|
|
|
Prepared = FALSE;
|
|
|
|
__DVDPrepareResetAsync(Callback);
|
|
__OSMaskInterrupts(0xFFFFFFE0);
|
|
__OSUnmaskInterrupts(0x400);
|
|
OSEnableInterrupts();
|
|
|
|
#if SDK_REVISION < 1
|
|
start = OSGetTime();
|
|
#endif
|
|
|
|
while (Prepared != TRUE) {
|
|
#if SDK_REVISION < 1
|
|
if (!DVDCheckDisk() || OS_TIMER_CLOCK < (OSGetTime() - start))
|
|
#else
|
|
if (!DVDCheckDisk())
|
|
#endif
|
|
{
|
|
__OSDoHotReset(0);
|
|
}
|
|
}
|
|
|
|
StopStreaming();
|
|
|
|
header = LoadApploader();
|
|
if (IsNewApploader(header)) {
|
|
if (doloffset == 0xFFFFFFFF) {
|
|
doloffset = (GetApploaderPosition() + 0x20) + header->size;
|
|
}
|
|
|
|
params->bootDol = doloffset;
|
|
dolEntry = LoadDol(params, (AppLoaderCallback)header->entry);
|
|
StartDol(params, dolEntry);
|
|
} else {
|
|
BOOT_REGION_START = (u32)regionStart;
|
|
BOOT_REGION_END = (u32)regionEnd;
|
|
g_unk_800030E2 = 1;
|
|
|
|
ReadDisc((void*)0x81300000, OSRoundUp32B(header->rebootSize), (GetApploaderPosition() + 0x20) + header->size);
|
|
ICInvalidateRange((void*)0x81300000, OSRoundUp32B(header->rebootSize));
|
|
OSDisableInterrupts();
|
|
ICFlashInvalidate();
|
|
Run((void*)0x81300000);
|
|
}
|
|
}
|
|
|
|
void __OSBootDol(u32 doloffset, u32 restartCode, const char** argv) {
|
|
char doloffInString[20];
|
|
s32 argvlen;
|
|
char** argvToPass;
|
|
s32 i;
|
|
void* saveStart;
|
|
void* saveEnd;
|
|
|
|
OSGetSaveRegion(&saveStart, &saveEnd);
|
|
sprintf(doloffInString, "%d", doloffset);
|
|
argvlen = 0;
|
|
|
|
if (argv != 0) {
|
|
while (argv[argvlen] != 0) {
|
|
argvlen++;
|
|
}
|
|
}
|
|
|
|
argvlen++;
|
|
argvToPass = OSAllocFromArenaLo((argvlen + 1) * 4, 1);
|
|
*argvToPass = doloffInString;
|
|
|
|
for (i = 1; i < argvlen; i++) {
|
|
argvToPass[i] = (char*)argv[i - 1];
|
|
}
|
|
|
|
__OSBootDolSimple(-1, restartCode, saveStart, saveEnd, FALSE, argvlen, argvToPass);
|
|
}
|
|
|
|
static void ExecCommon(const char* dolfile, const char** argv) {
|
|
DVDFileInfo fileInfo;
|
|
u32 doloff;
|
|
|
|
if ((s8)*dolfile == '\0') {
|
|
doloff = 0;
|
|
} else if (DVDOpen((char*)dolfile, &fileInfo)) {
|
|
doloff = fileInfo.startAddr;
|
|
} else {
|
|
ASSERTMSGLINE(LINE(689, 695, 697), 0, "OSExec(): The specified file doesn't exist");
|
|
return;
|
|
}
|
|
|
|
__OSBootDol(doloff, 0xC0000000, argv);
|
|
}
|
|
|
|
void OSExecv(const char* dolfile, const char** argv) {
|
|
ASSERTMSGLINE(LINE(718, 724, 726), dolfile != 0, "OSExecv(): null pointer was specified for the dol file name.");
|
|
ASSERTMSGLINE(LINE(719, 725, 727), argv != 0, "OSExecv(): null pointer was specified for argv.");
|
|
|
|
OSDisableScheduler();
|
|
__OSShutdownDevices(FALSE);
|
|
OSEnableScheduler();
|
|
OSSetArenaLo((void*)0x81280000);
|
|
OSSetArenaHi((void*)0x812F0000);
|
|
ExecCommon(dolfile, argv);
|
|
}
|
|
|
|
void OSExecl(const char* dolfile, const char* arg0, ...) {
|
|
va_list vl;
|
|
char* ptr;
|
|
s32 i;
|
|
char** argv;
|
|
|
|
ASSERTMSGLINE(LINE(759, 765, 767), dolfile != 0, "OSExecl(): null pointer was specified for the dol file name.");
|
|
|
|
OSDisableScheduler();
|
|
__OSShutdownDevices(FALSE);
|
|
OSEnableScheduler();
|
|
OSSetArenaLo((void*)0x81280000);
|
|
OSSetArenaHi((void*)0x812F0000);
|
|
|
|
argv = OSAllocFromArenaLo(4, 0x1000);
|
|
va_start(vl, arg0);
|
|
#if SDK_REVISION < 2
|
|
*argv = (char*)arg0;
|
|
|
|
i = 1;
|
|
do {
|
|
ptr = va_arg(vl, char*);
|
|
argv[i++] = ptr;
|
|
} while (ptr != 0);
|
|
#else
|
|
i = 0;
|
|
ptr = (char*)arg0;
|
|
goto setarg;
|
|
|
|
do {
|
|
ptr = va_arg(vl, char*);
|
|
setarg:
|
|
argv[i++] = ptr;
|
|
} while (ptr != 0);
|
|
#endif
|
|
va_end(vl);
|
|
ASSERTMSGLINE(LINE(787, 793, 794), i < 0x400U, "OSExecl(): Arguments too long");
|
|
|
|
ExecCommon(dolfile, argv);
|
|
}
|