1
0
Fork 0
This repository has been archived on 2024-02-06. You can view files and clone it, but cannot push or open issues or pull requests.
GeckoLoader/loader.c

192 lines
6.8 KiB
C
Raw Normal View History

2020-04-14 16:00:48 -05:00
/*Credits to riidefi for hook code, cache asm, and teaching me C*/
2020-04-15 02:11:38 -05:00
#define dcbst(_val) asm volatile("dcbst 0, %0" \
: \
: "r"(_val))
#define dcbf(_val) asm volatile("dcbf 0, %0" \
: \
: "r"(_val))
#define icbi(_val) asm volatile("icbi 0, %0" \
: \
: "r"(_val))
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
2020-04-15 02:11:38 -05:00
typedef int s32;
typedef short s16;
typedef char s8;
typedef u32 BOOL;
typedef u32 unk32;
2020-04-15 02:11:38 -05:00
enum {
2020-04-14 18:10:46 -05:00
FALSE,
TRUE
};
2020-04-15 02:11:38 -05:00
enum {
2020-04-14 18:10:46 -05:00
NULL
};
2020-04-15 02:11:38 -05:00
struct Info {
2020-04-14 16:02:48 -05:00
u32 allocsize;
u32 _loaderSize;
u32 _loaderFullSize;
2020-04-15 02:11:38 -05:00
struct CodeList* _codelistPointer;
u32 _wiiVIHook[4];
u32 _gcnVIHook[8];
};
2020-04-15 02:11:38 -05:00
struct CodeList {
u16 mBaseASM;
u16 mUpperBase;
u16 mOffsetASM;
u16 mLowerOffset;
};
2020-04-15 02:11:38 -05:00
struct DiscInfo {
2020-04-14 16:00:48 -05:00
u8 mDiscID;
u16 mGameCode;
u8 mRegionCode;
u16 mMakerCode;
u8 mDiscNumber;
u8 mDiscVersion;
u8 mAudioStreaming;
u8 mStreamBufferSize;
u8 mUnknown[12];
u32 mWiiMagic;
u32 mGCNMagic;
u32 mUnknown2[2];
u32 mRAMSize;
u32 mUnknown3[2];
2020-04-15 02:11:38 -05:00
u32* mHeapPointer;
2020-04-14 16:00:48 -05:00
u32 mHeapMirror;
u32 mFstSize;
u32 mData[(0x3110 - 0x40) / 4];
u32 mWiiHeap;
};
struct Info gInfo = {
2020-04-15 02:11:38 -05:00
.allocsize = 0, /*This is the code allocation*/
._loaderSize = 0, /*This is the size of the GeckoLoader*/
._loaderFullSize = 0, /*This is the size of the GeckoLoader + the codelist*/
._codelistPointer = (struct CodeList*)0x800018F8, /*This points to where the codelist address is set in the codehandler*/
._wiiVIHook = { 0x7CE33B78, 0x38870034, 0x38A70038, 0x38C7004C },
._gcnVIHook = { 0x7C030034, 0x38830020, 0x5485083C, 0x7C7F2A14, 0xA0030000, 0x7C7D2A14, 0x20A4003F, 0xB0030000 },
};
2020-04-15 02:11:38 -05:00
const u32* MEM1_START = 0x80000000;
const u32* MEM1_END = 0x817FFF00;
const u32 CODEHANDLER_START = 0x800018A8;
static inline void flushAddr(void* addr)
{
2020-04-14 18:10:46 -05:00
dcbf(addr);
icbi(addr);
}
2020-04-15 02:11:38 -05:00
static inline void directWrite(u32* addr, u32 value)
2020-04-14 18:10:46 -05:00
{
2020-04-15 02:11:38 -05:00
addr[0] = value;
2020-04-14 18:10:46 -05:00
flushAddr(addr);
}
2020-04-15 02:11:38 -05:00
static inline void directBranchEx(void* addr, void* ptr, BOOL lk)
2020-04-14 18:10:46 -05:00
{
2020-04-15 02:11:38 -05:00
directWrite((u32*)(addr), ((((u32)(ptr) - (u32)(addr)) & 0x3ffffff) | 0x48000000 | !!lk)); /*This constructs a branch instruction. &TO = ((TO - FROM) & MAX_OFFSET) | BRANCH_TYPE | !!isLink*/
}
2020-04-15 02:11:38 -05:00
void (*_init_registers)(void) = &gInfo; /*Dummy, replace this with the address of the game entry after compile*/
void (*_codeHandler)(void) = &gInfo; /*Dummy, replace this with the address of the codehandler after compile*/
2020-04-14 18:10:46 -05:00
2020-04-15 02:11:38 -05:00
static inline u32* findFunction(u32* gcnHook, u32* wiiHook, u32 range, BOOL isWii)
2020-04-14 18:10:46 -05:00
{
2020-04-15 02:11:38 -05:00
u32* hookData;
u32 arrayLength;
if (isWii) /*If the game is built for the Wii, set the hookdata to be the Wii variant*/
{
hookData = wiiHook;
arrayLength = sizeof(wiiHook) / sizeof(u32);
} else /*The game is built for the GCN, set the hookdata to be the GCN variant*/
{
hookData = gcnHook;
arrayLength = sizeof(gcnHook) / sizeof(u32);
}
2020-04-14 18:10:46 -05:00
u32 index = 0;
2020-04-15 02:11:38 -05:00
for (u32 i = 0; (u32)&MEM1_START[i] < (u32)MEM1_START + range; ++i) /*Loop through the games RAM, make sure we don't find our own hook data by accident*/
2020-04-14 18:10:46 -05:00
{
2020-04-15 02:11:38 -05:00
if (MEM1_START[i] == hookData[index]) /*If the data matches, increase the index counter and continue search, else set index to 0 and continue searching*/
++index;
2020-04-14 18:10:46 -05:00
else
index = 0;
2020-04-15 02:11:38 -05:00
if (index >= (arrayLength - 1) && ((u32)&MEM1_START[i] < (u32)&gInfo || (u32)&MEM1_START[i] > (u32)&gInfo + 0x1000)) /*If the data has matched the whole array, return the address of the match*/
2020-04-14 18:10:46 -05:00
{
2020-04-15 02:11:38 -05:00
return &MEM1_START[i];
2020-04-14 18:10:46 -05:00
}
}
return NULL;
}
2020-04-15 02:11:38 -05:00
void hookFunction(u32* start, u32 hookInstruction, u32 hookTo, BOOL isLink)
/*Call this after findFunction, finds the address of the first instance of value hookInstruction, and hooks it to the pointer hookTo*/
2020-04-14 18:10:46 -05:00
{
int i = 0;
2020-04-15 02:11:38 -05:00
while (start[i] != hookInstruction) {
2020-04-14 18:10:46 -05:00
++i;
}
2020-04-15 02:11:38 -05:00
directBranchEx((u32*)(&start[i]), (void*)(hookTo), isLink);
}
2020-04-15 02:11:38 -05:00
static inline void setHeap(struct DiscInfo* discResources, struct Info* infoPointer, BOOL isWii)
/*Reallocate the games internal memory heap based on the console the game is for, to make space for our codes*/
2020-04-14 18:10:46 -05:00
{
2020-04-15 02:11:38 -05:00
if (isWii) {
discResources->mHeapPointer = (u32*)(u32)discResources->mWiiHeap - infoPointer->allocsize;
discResources->mWiiHeap = (u32)discResources->mHeapPointer;
} else {
discResources->mHeapPointer = (u32*)(u32)discResources->mHeapPointer - infoPointer->allocsize;
}
}
2020-04-15 02:11:38 -05:00
BOOL initMods(struct DiscInfo* discResources)
2020-04-14 18:10:46 -05:00
{
2020-04-15 02:11:38 -05:00
struct Info* infoPointer = &gInfo;
const u32* geckoPointerInit = (u32*)(MEM1_START + 0x18F8);
s32 sizeDiff = infoPointer->_loaderFullSize - infoPointer->_loaderSize; /*Calculate size of codelist*/
const u32* sourcePointer = (u32*)(infoPointer);
if (!infoPointer->_codelistPointer)
return FALSE; /*Pointer is null*/
else {
setHeap(discResources, infoPointer, (discResources->mWiiMagic != 0)); /*Reallocate the internal heap*/
if (infoPointer->_loaderFullSize == 0 || infoPointer->_loaderSize == 0 || sizeDiff <= 0)
return FALSE; /*Invalid values*/
else {
while (sizeDiff > 0) /*Copy codelist to the new allocation*/
2020-04-14 18:10:46 -05:00
{
sizeDiff = sizeDiff - 4;
2020-04-15 02:11:38 -05:00
discResources->mHeapPointer[sizeDiff / 4] = sourcePointer[sizeDiff / 4];
2020-04-14 18:10:46 -05:00
}
2020-04-15 02:11:38 -05:00
infoPointer->_codelistPointer->mUpperBase = ((u32)discResources->mHeapPointer >> 16) & 0xFFFF; /*Change upper codelist pointer to the new address in the allocation*/
infoPointer->_codelistPointer->mLowerOffset = (u32)(discResources->mHeapPointer) & 0xFFFF; /*Change lower codelist pointer to the new address in the allocation*/
2020-04-14 18:10:46 -05:00
flushAddr(&infoPointer->_codelistPointer->mUpperBase);
flushAddr(&infoPointer->_codelistPointer->mLowerOffset);
2020-04-15 02:11:38 -05:00
u32* functionAddr = findFunction(infoPointer->_gcnVIHook, infoPointer->_wiiVIHook, (MEM1_END - MEM1_START), (discResources->mWiiMagic != 0));
if (functionAddr) {
hookFunction(functionAddr, 0x4E800020, CODEHANDLER_START, FALSE);
return TRUE;
2020-04-14 18:10:46 -05:00
}
}
}
}
2020-04-14 18:10:46 -05:00
int main()
{
2020-04-15 02:11:38 -05:00
struct DiscInfo* discResources = (struct DiscInfo*)MEM1_START;
if (discResources->mWiiMagic || discResources->mGCNMagic) {
if (initMods(discResources) == TRUE)
(*_codeHandler)(); /*Call the codehandler if successful*/
2020-04-14 16:02:48 -05:00
}
2020-04-15 02:11:38 -05:00
(*_init_registers)(); /*Call the game start*/
2020-04-14 16:00:48 -05:00
}