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.cpp

233 lines
7.5 KiB
C++
Raw Normal View History

/*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 call(addr) ((void (*)(...))addr)
#define MEM1_START 0x80000000
#define MEM1_END 0x81800000
#define CODEHANDLER 0x800018A8
#define GCT_MAGIC 0x00D0C0DE
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef int s32;
typedef short s16;
typedef char s8;
__attribute__((noreturn)) int main();
struct CodeList {
u16 mBaseASM;
u16 mUpperBase;
u16 mOffsetASM;
u16 mLowerOffset;
};
struct Info {
const u32 allocsize;
const u32 loaderSize;
const u32 handlerSize;
const u32 codeSize;
const u32* codehandlerHook;
const u32 wiiVIHook[4];
const u32 gcnVIHook[8];
};
struct DiscInfo {
2020-06-04 11:45:15 +09:00
const u8 mDiscID; //0x0000
const u16 mGameCode; //0x0001
const u8 mRegionCode; //0x0003
const u16 mMakerCode; //0x0004
const u8 mDiscNumber; //0x0006
const u8 mDiscVersion; //0x0007
const u8 mAudioStreaming; //0x0008
const u8 mStreamBufferSize; //0x0009
const u8 _00[12]; //0x000A
const u32 mWiiMagic; //0x0018
const u32 mGCNMagic; //0x001C
const u32 _01[2]; //0x0020
u32 mRAMSize; //0x0028
const u32 _02[2]; //0x002C
u32* mOSArenaHi; //0x0034
u32* mFstPointer; //0x0038
u32 mFstSize; //0x003C
u32 _03[0xB4 / 4]; //0x0040
u32* mTranslation; //0x00F4
u32 _04[0x3018 / 4];
u32 mWiiHeap;
};
Info gpModInfo = {
0, /*This is the code allocation*/
0, /*This is the size of the GeckoLoader*/
0, /*This is the size of the codehandler*/
0, /*This is the size of the GeckoLoader + the codelist*/
0, /*This is the codehandler hook address*/
{ 0x7CE33B78, 0x38870034, 0x38A70038, 0x38C7004C },
{ 0x7C030034, 0x38830020, 0x5485083C, 0x7C7F2A14, 0xA0030000, 0x7C7D2A14, 0x20A4003F, 0xB0030000 },
};
DiscInfo* gpDiscResources = (DiscInfo*)MEM1_START;
static inline void flushAddr(void* addr)
{
dcbf(addr);
icbi(addr);
}
static inline void directWrite(u32* addr, u32 value)
{
*addr = value;
flushAddr(addr);
}
/*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 | !!lk));
}
static inline u32* findArrayInstance(u32* start, const u32 end, u32 arrayLength, const u32* hookData)
{
u32 index = 0;
/*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;
else
index = 0;
/*If the data has matched the whole array, return the address of the match*/
if (index >= (arrayLength) && ((u32)&start[i] < (u32)&gpModInfo || (u32)&start[i] > (u32)&gpModInfo + sizeof(Info)))
return (u32*)&start[i];
}
return nullptr;
}
static inline u32* findU32Instance(u32* start, u32 end, u32 hookData)
{
for (u32 i = 0; (u32)&start[i] < end; ++i) {
if (start[i] == hookData) {
return (u32*)&start[i];
}
}
return nullptr;
}
/*Find VI hook for Game*/
static inline u32* findVIHook(u32* start, const u32 end)
{
const u32* hookData;
u32 arrayLength;
/*If the game is built for the Wii, set the hookdata to be the Wii variant*/
if (gpDiscResources->mWiiMagic) {
hookData = (const u32*)gpModInfo.wiiVIHook;
arrayLength = sizeof(gpModInfo.wiiVIHook) / sizeof(u32);
} else /*The game is built for the GCN, set the hookdata to be the GCN variant*/
{
hookData = (const u32*)gpModInfo.gcnVIHook;
arrayLength = sizeof(gpModInfo.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*/
static inline void hookFunction(u32* start, u32 hookInstruction, u32 hookTo, bool isLink)
{
int i = 0;
while (start[i] != hookInstruction) {
++i;
}
directBranchEx((u32*)(&start[i]), (void*)(hookTo), isLink);
}
/*Reallocate the games internal memory heap based on the console
the game is for, to make space for our codes*/
static inline void setHeap(u32 alloc)
{
2020-06-04 11:45:15 +09:00
if (gpDiscResources->mTranslation < gpDiscResources->mOSArenaHi) {
if (gpDiscResources->mWiiMagic) {
gpDiscResources->mTranslation = (u32*)((u32)gpDiscResources->mTranslation - alloc);
gpDiscResources->mWiiHeap = (u32)gpDiscResources->mTranslation;
} else {
gpDiscResources->mTranslation = (u32*)((u32)gpDiscResources->mTranslation - alloc);
}
} else {
2020-06-04 11:45:15 +09:00
if (gpDiscResources->mWiiMagic) {
gpDiscResources->mOSArenaHi = (u32*)((u32)gpDiscResources->mWiiHeap - alloc);
gpDiscResources->mWiiHeap = (u32)gpDiscResources->mOSArenaHi;
} else {
gpDiscResources->mOSArenaHi = (u32*)((u32)gpDiscResources->mOSArenaHi - alloc);
}
}
2020-06-04 11:45:15 +09:00
}
static inline void memCopy(u32* to, u32* from, s32 size)
{
for (s32 i = 0; i < size; ++i) {
*to++ = *from++;
}
}
static inline void flushCacheRange(u8* addr, s32 size)
{
if ((u32)addr & 31) size += 32;
else size += 31;
for (u32 i = 0; i < (size >> 5); ++i) {
flushAddr((void*)addr);
addr += 32;
}
}
static inline bool initMods(DiscInfo* gpDiscResources)
{
setHeap(gpModInfo.allocsize); /*Reallocate the internal heap*/
/*Change codelist pointer to the new address in the allocation*/
CodeList* codelistPointer = (CodeList*)((u32)&gpModInfo + sizeof(gpModInfo) + 0xFC);
2020-06-04 11:45:15 +09:00
codelistPointer->mUpperBase = (((u32)gpDiscResources->mOSArenaHi + gpModInfo.handlerSize) >> 16) & 0xFFFF;
codelistPointer->mLowerOffset = ((u32)gpDiscResources->mOSArenaHi + gpModInfo.handlerSize) & 0xFFFF;
/*Copy codelist to the new allocation*/
2020-06-04 11:45:15 +09:00
memCopy(gpDiscResources->mOSArenaHi, (u32*)((u32)&gpModInfo + sizeof(gpModInfo) + 4), (gpModInfo.handlerSize + gpModInfo.codeSize) >> 2);
/*Update the cache, so that the instructions fully update*/
flushAddr(&codelistPointer->mBaseASM);
if (!gpModInfo.codehandlerHook || *gpModInfo.codehandlerHook != 0x4E800020) {
u32* functionAddr = findVIHook((u32*)MEM1_START, MEM1_END);
if (functionAddr == nullptr)
return false;
2020-06-04 11:45:15 +09:00
hookFunction(functionAddr, 0x4E800020, (u32)gpDiscResources->mOSArenaHi + 0xA8, false);
} else {
2020-06-04 11:45:15 +09:00
directBranchEx((void*)gpModInfo.codehandlerHook, (void*)((u32)gpDiscResources->mOSArenaHi + 0xA8), false);
}
2020-06-04 11:45:15 +09:00
flushCacheRange((u8*)gpDiscResources->mOSArenaHi, gpModInfo.handlerSize + gpModInfo.codeSize);
return true;
}
int main()
{
if ((gpDiscResources->mWiiMagic || gpDiscResources->mGCNMagic) && initMods(gpDiscResources) == true)
2020-06-04 11:45:15 +09:00
call((void*)((u32)(gpDiscResources->mOSArenaHi) + 0xA8))(); /*Call the codehandler if successful*/
call(0xDEADBEEF)(); /*Call the game start*/
}