diff --git a/loader.c b/loader.c new file mode 100644 index 0000000..e9a82bd --- /dev/null +++ b/loader.c @@ -0,0 +1,159 @@ +#include "cache.h" + +#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; +typedef int BOOL; +typedef u32 unk32; +enum { FALSE, TRUE }; +enum { NULL }; + +struct Info { + u32 allocsize; + u32 _loaderSize; + u32 _loaderFullSize; + struct CodeList* _codelistPointer; + u32 _wiiVIHook[4]; + u32 _gcnVIHook[8]; +}; + +struct CodeList { + u16 mBaseASM; + u16 mUpperBase; + u16 mOffsetASM; + u16 mLowerOffset; +}; + +struct DiscInfo { + 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]; + u32* mHeapPointer; + u32 mHeapMirror; + u32 mFstSize; + u32 mData[(0x3110 - 0x40) / 4]; + u32 mWiiHeap; +}; + +struct Info gInfo = { + .allocsize = 0, + ._loaderSize = 0, + ._loaderFullSize = 0, + ._codelistPointer = (struct CodeList*)0x800018F8, + ._wiiVIHook = {0x7CE33B78, 0x38870034, + 0x38A70038, 0x38C7004C}, + ._gcnVIHook = {0x7C030034, 0x38830020, + 0x5485083C, 0x7C7F2A14, + 0xA0030000, 0x7C7D2A14, + 0x20A4003F, 0xB0030000}, +}; + +static inline void flushAddr(void* addr) +{ + dcbf(addr); + icbi(addr); +} + +static inline void directWrite(u32* addr, u32 ptr) { + addr[0] = ptr; + flushAddr(addr); +} + +static inline void directBranchEx(void* addr, void* ptr, BOOL link) { + directWrite((u32*)(addr), + ((((u32)(ptr) - (u32)(addr)) & 0x3ffffff) | 0x48000000 | !!link)); +} + +void (*_init_registers)(void) = &gInfo; +void (*_codeHandler)(void) = &gInfo; + +static inline u32* findFunction(u32* hookData, u32* start, u32 end, u32 arrayLength) { + u32 index = 0; + for (u32 i = 0; (u32)&start[i] < end; ++i) { + if (start[i] == hookData[index]) index = index + 1; + else index = 0; + if (index >= (arrayLength - 1)) { + if ((u32)&start[i] < &gInfo || (u32)&start[i] > (u32)&gInfo + 0x100){ + return &start[i]; + } + } + } + return NULL; +} + +void hookFunction(u32* start, u32 hookInstruction, u32 hookTo) { + int i = 0; + while (start[i] != hookInstruction) { + ++i; + } + directBranchEx((u32*)(&start[i]), (void*)(hookTo), FALSE); +} + +static inline void overwriteValue(u32* addr, u32 newValue) { + addr[0] = newValue; + flushAddr(&addr[0]); +} + +void initMods(struct DiscInfo* baseAddress) { + + struct Info* infoPointer = &gInfo; + const u32* geckoPointerInit = (u32*)(u32)baseAddress + 0x18F8; + u32 sizeDiff = infoPointer->_loaderFullSize - infoPointer->_loaderSize; + const u32* sourcePointer = (u32*)(infoPointer); + + if (infoPointer->_codelistPointer) { + if (baseAddress->mWiiMagic) { + baseAddress->mHeapPointer = (u32)baseAddress->mWiiHeap - infoPointer->allocsize; + baseAddress->mWiiHeap = (u32)baseAddress->mHeapPointer; + } + else if(baseAddress->mGCNMagic) { + baseAddress->mHeapPointer = (u32)baseAddress->mHeapPointer - infoPointer->allocsize; + } + + if (infoPointer->_loaderFullSize > 0 && infoPointer->_loaderSize > 0) { + while (sizeDiff > 0) { + sizeDiff = sizeDiff - 4; + baseAddress->mHeapPointer[sizeDiff / 4] = sourcePointer[sizeDiff / 4]; + } + infoPointer->_codelistPointer->mUpperBase = ((u32)baseAddress->mHeapPointer >> 16) & 0xFFFF; + infoPointer->_codelistPointer->mLowerOffset = (u32)(baseAddress->mHeapPointer) & 0xFFFF; + flushAddr(&infoPointer->_codelistPointer->mUpperBase); + flushAddr(&infoPointer->_codelistPointer->mLowerOffset); + + u32* functionAddr; + if (baseAddress->mWiiMagic) { + functionAddr = findFunction((u32*)infoPointer->_wiiVIHook, (u32*)baseAddress, 0x817FFF00, 0x4); + } + else { + functionAddr = findFunction((u32*)infoPointer->_gcnVIHook, (u32*)baseAddress, 0x817FFF00, 0x8); + } + if (functionAddr) { + hookFunction(functionAddr, 0x4E800020, 0x800018A8); + } + } + } +} + +int main() { + struct DiscInfo* baseAddress = (struct DiscInfo*)0x80000000; + if (baseAddress->mWiiMagic || baseAddress->mGCNMagic) { + initMods(baseAddress); + (*_codeHandler)(); + } + (*_init_registers)(); +} \ No newline at end of file