Merge pull request #1 from JoshuaMKW/Updated-loader.c
Refactored some code, added comments
This commit is contained in:
commit
abddea6916
1 changed files with 147 additions and 104 deletions
251
loader.c
251
loader.c
|
@ -1,44 +1,59 @@
|
|||
/*Credits to riidefi for hook code, cache asm, and teaching me C*/
|
||||
|
||||
#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))
|
||||
#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))
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#define NULL 0
|
||||
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
typedef int BOOL;
|
||||
typedef int s32;
|
||||
typedef short s16;
|
||||
typedef char s8;
|
||||
typedef u32 BOOL;
|
||||
typedef u32 unk32;
|
||||
enum
|
||||
{
|
||||
FALSE,
|
||||
TRUE
|
||||
};
|
||||
enum
|
||||
{
|
||||
NULL
|
||||
|
||||
__attribute__((noreturn)) int main();
|
||||
__attribute__((noinline)) void memCopy();
|
||||
__attribute__((noinline)) u32* findVIHook();
|
||||
__attribute__((noinline)) u32* findArrayInstance();
|
||||
__attribute__((noinline)) u32* findU32Instance();
|
||||
|
||||
enum {
|
||||
MEM1_START = 0x80000000,
|
||||
MEM1_END = 0x81800000,
|
||||
MEM1_RANGE = MEM1_START - MEM1_END,
|
||||
CODEHANDLER_ENTRY = 0x800018A8,
|
||||
GAME_ENTRY = 0xDEADBEEF,
|
||||
GCT_MAGIC = 0x00D0C0DE
|
||||
};
|
||||
|
||||
struct Info
|
||||
{
|
||||
struct Info {
|
||||
u32 allocsize;
|
||||
u32 _loaderSize;
|
||||
u32 _loaderFullSize;
|
||||
struct CodeList *_codelistPointer;
|
||||
struct CodeList* _codelistPointer;
|
||||
u32 _wiiVIHook[4];
|
||||
u32 _gcnVIHook[8];
|
||||
};
|
||||
|
||||
struct CodeList
|
||||
{
|
||||
struct CodeList {
|
||||
u16 mBaseASM;
|
||||
u16 mUpperBase;
|
||||
u16 mOffsetASM;
|
||||
u16 mLowerOffset;
|
||||
};
|
||||
|
||||
struct DiscInfo
|
||||
{
|
||||
struct DiscInfo {
|
||||
u8 mDiscID;
|
||||
u16 mGameCode;
|
||||
u8 mRegionCode;
|
||||
|
@ -53,7 +68,7 @@ struct DiscInfo
|
|||
u32 mUnknown2[2];
|
||||
u32 mRAMSize;
|
||||
u32 mUnknown3[2];
|
||||
u32 *mHeapPointer;
|
||||
u32* mHeapPointer;
|
||||
u32 mHeapMirror;
|
||||
u32 mFstSize;
|
||||
u32 mData[(0x3110 - 0x40) / 4];
|
||||
|
@ -61,125 +76,153 @@ struct DiscInfo
|
|||
};
|
||||
|
||||
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},
|
||||
.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 },
|
||||
};
|
||||
|
||||
static inline void flushAddr(void *addr)
|
||||
static inline void flushAddr(void* addr)
|
||||
{
|
||||
dcbf(addr);
|
||||
icbi(addr);
|
||||
}
|
||||
|
||||
static inline void directWrite(u32 *addr, u32 ptr)
|
||||
static inline void directWrite(u32* addr, u32 value)
|
||||
{
|
||||
addr[0] = ptr;
|
||||
addr[0] = value;
|
||||
flushAddr(addr);
|
||||
}
|
||||
|
||||
static inline void directBranchEx(void *addr, void *ptr, BOOL link)
|
||||
/*This constructs a branch instruction. &TO = ((TO - FROM) & MAX_OFFSET) | BRANCH_TYPE | !!isLink*/
|
||||
static inline void directBranchEx(void* addr, void* ptr, BOOL lk)
|
||||
{
|
||||
directWrite((u32 *)(addr), ((((u32)(ptr) - (u32)(addr)) & 0x3ffffff) | 0x48000000 | !!link));
|
||||
directWrite((u32*)(addr), ((((u32)(ptr) - (u32)(addr)) & 0x3ffffff) | 0x48000000 | !!lk));
|
||||
}
|
||||
|
||||
void (*_init_registers)(void) = &gInfo;
|
||||
void (*_codeHandler)(void) = &gInfo;
|
||||
|
||||
static inline u32 *findFunction(u32 *hookData, u32 *start, u32 end, u32 arrayLength)
|
||||
u32* findArrayInstance(u32* start, u32 end, u32 arrayLength, u32* hookData)
|
||||
{
|
||||
u32 index = 0;
|
||||
for (u32 i = 0; (u32)&start[i] < end; ++i)
|
||||
{
|
||||
|
||||
/*Loop through the games RAM, make sure we don't find our own hook data by accident*/
|
||||
for (u32 i = 0; (u32)&start[i] < end; ++i) {
|
||||
/*If the data matches, increase the index counter and continue search,
|
||||
else set index to 0 and continue searching*/
|
||||
if (start[i] == hookData[index])
|
||||
index = index + 1;
|
||||
++index;
|
||||
else
|
||||
index = 0;
|
||||
if (index >= (arrayLength - 1))
|
||||
{
|
||||
if ((u32)&start[i] < &gInfo || (u32)&start[i] > (u32)&gInfo + 0x100)
|
||||
{
|
||||
return &start[i];
|
||||
}
|
||||
|
||||
/*If the data has matched the whole array, return the address of the match*/
|
||||
if (index >= (arrayLength - 1) && ((u32)&start[i] < (u32)&gInfo || (u32)&start[i] > (u32)&gInfo + sizeof(gInfo))) {
|
||||
return &start[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hookFunction(u32 *start, u32 hookInstruction, u32 hookTo)
|
||||
u32* findU32Instance(u32* start, u32 end, u32* hookData)
|
||||
{
|
||||
for (u32 i = 0; (u32)&start[i] < end; ++i) {
|
||||
if (start[i] == hookData) {
|
||||
return &start[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Find VI hook for Game*/
|
||||
u32* findVIHook(struct DiscInfo* discResources, struct Info* infoPointer, u32* start, u32 end)
|
||||
{
|
||||
u32* hookData;
|
||||
u32 arrayLength;
|
||||
|
||||
/*If the game is built for the Wii, set the hookdata to be the Wii variant*/
|
||||
if (discResources->mWiiMagic) {
|
||||
hookData = infoPointer->_wiiVIHook;
|
||||
arrayLength = sizeof(infoPointer->_wiiVIHook) / sizeof(u32);
|
||||
} else /*The game is built for the GCN, set the hookdata to be the GCN variant*/
|
||||
{
|
||||
hookData = infoPointer->_gcnVIHook;
|
||||
arrayLength = sizeof(infoPointer->_gcnVIHook) / sizeof(u32);
|
||||
}
|
||||
return findArrayInstance(start, end, arrayLength, hookData);
|
||||
}
|
||||
|
||||
/*Call this after findFunction, finds the address of the first instance
|
||||
of value hookInstruction, and hooks it to the pointer hookTo*/
|
||||
void hookFunction(u32* start, u32 hookInstruction, u32 hookTo, BOOL isLink)
|
||||
{
|
||||
int i = 0;
|
||||
while (start[i] != hookInstruction)
|
||||
{
|
||||
while (start[i] != hookInstruction) {
|
||||
++i;
|
||||
}
|
||||
directBranchEx((u32 *)(&start[i]), (void *)(hookTo), FALSE);
|
||||
directBranchEx((u32*)(&start[i]), (void*)(hookTo), isLink);
|
||||
}
|
||||
|
||||
static inline void overwriteValue(u32 *addr, u32 newValue)
|
||||
/*Reallocate the games internal memory heap based on the console
|
||||
the game is for, to make space for our codes*/
|
||||
static inline void setHeap(struct DiscInfo* discResources, u32 alloc)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (discResources->mWiiMagic) {
|
||||
discResources->mHeapPointer = (u32*)((u32)discResources->mWiiHeap - alloc);
|
||||
discResources->mWiiHeap = (u32)discResources->mHeapPointer;
|
||||
} else {
|
||||
discResources->mHeapPointer = (u32*)((u32)discResources->mHeapPointer - alloc);
|
||||
}
|
||||
}
|
||||
|
||||
void memCopy(u32* to, u32* from, s32 size)
|
||||
{
|
||||
for (s32 i = 0; i < size; ++i) {
|
||||
to[i] = from[i];
|
||||
}
|
||||
}
|
||||
|
||||
BOOL initMods(struct DiscInfo* discResources)
|
||||
{
|
||||
struct Info* infoPointer = &gInfo;
|
||||
const u32* geckoPointerInit = (u32*)(MEM1_START + 0x18F8);
|
||||
s32 sizeDiff = (infoPointer->_loaderFullSize - infoPointer->_loaderSize) / 4; /*Calculate size of codelist*/
|
||||
const u32* sourcePointer = (u32*)(infoPointer);
|
||||
|
||||
if (infoPointer->_codelistPointer == NULL)
|
||||
return FALSE; /*Pointer is null*/
|
||||
|
||||
setHeap(discResources, infoPointer->allocsize); /*Reallocate the internal heap*/
|
||||
if (infoPointer->_loaderFullSize == NULL || infoPointer->_loaderSize == NULL || sizeDiff <= 0)
|
||||
return FALSE; /*Invalid values*/
|
||||
|
||||
/*Copy codelist to the new allocation*/
|
||||
memCopy(discResources->mHeapPointer, findU32Instance((u32*)&gInfo, MEM1_END, (u32*)GCT_MAGIC), sizeDiff);
|
||||
|
||||
/*Change upper codelist pointer to the new address in the allocation*/
|
||||
infoPointer->_codelistPointer->mUpperBase = ((u32)discResources->mHeapPointer >> 16) & 0xFFFF;
|
||||
|
||||
/*Change lower codelist pointer to the new address in the allocation*/
|
||||
infoPointer->_codelistPointer->mLowerOffset = (u32)(discResources->mHeapPointer) & 0xFFFF;
|
||||
|
||||
/*Update the cache, so that the instructions fully update*/
|
||||
flushAddr(&infoPointer->_codelistPointer->mUpperBase);
|
||||
flushAddr(&infoPointer->_codelistPointer->mLowerOffset);
|
||||
|
||||
u32* functionAddr = findVIHook(discResources, infoPointer, (u32*)MEM1_START, MEM1_END);
|
||||
if (functionAddr == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
hookFunction(functionAddr, 0x4E800020, CODEHANDLER_ENTRY, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct DiscInfo *baseAddress = (struct DiscInfo *)0x80000000;
|
||||
if (baseAddress->mWiiMagic || baseAddress->mGCNMagic)
|
||||
{
|
||||
initMods(baseAddress);
|
||||
(*_codeHandler)();
|
||||
struct DiscInfo* discResources = (struct DiscInfo*)MEM1_START;
|
||||
if (discResources->mWiiMagic || discResources->mGCNMagic) {
|
||||
if (initMods(discResources) == TRUE) {
|
||||
((void (*)())CODEHANDLER_ENTRY)(); /*Call the codehandler if successful*/
|
||||
}
|
||||
}
|
||||
(*_init_registers)();
|
||||
((void (*)())GAME_ENTRY)(); /*Call the game start*/
|
||||
}
|
||||
|
|
Reference in a new issue