More robust eeload hooking to monitor and interfere with bios and game loading.

Maybe some other cruft can go now this should be reliable.
This commit is contained in:
Pseudonym 2016-07-29 08:22:28 +01:00
parent 242ac26299
commit c782b6222c
4 changed files with 91 additions and 64 deletions

View File

@ -512,8 +512,8 @@ static void intExecute()
bool instruction_was_cancelled; bool instruction_was_cancelled;
enum ExecuteState { enum ExecuteState {
RESET, RESET,
REPLACE_OSDSYS_DONE, GAME_LOADING,
GAME_STARTING_DONE GAME_RUNNING
}; };
ExecuteState state = RESET; ExecuteState state = RESET;
do { do {
@ -523,24 +523,32 @@ static void intExecute()
// resume it after a cancelled instruction. // resume it after a cancelled instruction.
switch (state) { switch (state) {
case RESET: case RESET:
if (g_SkipBiosHack) { do
do execI();
execI(); while (cpuRegs.pc != (eeloadMain ? eeloadMain : EELOAD_START));
while (cpuRegs.pc != EELOAD_START); if (cpuRegs.pc == EELOAD_START)
eeloadReplaceOSDSYS(); {
} // The EELOAD _start function is the same across all BIOS versions afaik
state = REPLACE_OSDSYS_DONE; u32 mainjump = memRead32(EELOAD_START + 0x9c);
if (mainjump >> 26 == 3) // JAL
eeloadMain = ((EELOAD_START + 0xa0) & 0xf0000000U) | (mainjump << 2 & 0x0fffffffU);
} else if (cpuRegs.pc == eeloadMain)
eeloadHook();
if (g_GameLoading)
state = GAME_LOADING;
else
break;
case REPLACE_OSDSYS_DONE: case GAME_LOADING:
if (ElfEntry != 0xFFFFFFFF) { if (ElfEntry != 0xFFFFFFFF) {
do do
execI(); execI();
while (cpuRegs.pc != ElfEntry); while (cpuRegs.pc != ElfEntry);
eeGameStarting(); eeGameStarting();
} }
state = GAME_STARTING_DONE; state = GAME_RUNNING;
case GAME_STARTING_DONE: case GAME_RUNNING:
while (true) while (true)
execI(); execI();
} }

View File

@ -49,11 +49,14 @@ R5900cpu *Cpu = NULL;
bool g_SkipBiosHack; // set at boot if the skip bios hack is on, reset before the game has started bool g_SkipBiosHack; // set at boot if the skip bios hack is on, reset before the game has started
bool g_GameStarted; // set when we reach the game's entry point or earlier if the entry point cannot be determined bool g_GameStarted; // set when we reach the game's entry point or earlier if the entry point cannot be determined
bool g_GameLoading; // EELOAD has been called to load the game
static const uint eeWaitCycles = 3072; static const uint eeWaitCycles = 3072;
bool eeEventTestIsActive = false; bool eeEventTestIsActive = false;
u32 eeloadMain = 0;
extern SysMainMemory& GetVmMemory(); extern SysMainMemory& GetVmMemory();
void cpuReset() void cpuReset()
@ -87,6 +90,7 @@ void cpuReset()
Deci2Reset(); Deci2Reset();
g_GameStarted = false; g_GameStarted = false;
g_GameLoading = false;
g_SkipBiosHack = EmuConfig.UseBOOT2Injection; g_SkipBiosHack = EmuConfig.UseBOOT2Injection;
ElfCRC = 0; ElfCRC = 0;
@ -103,6 +107,8 @@ void cpuReset()
// run into this while testing minor binary hacked changes to ISO images, which // run into this while testing minor binary hacked changes to ISO images, which
// is why I found out about this) --air // is why I found out about this) --air
LastELF = L""; LastELF = L"";
eeloadMain = 0;
} }
void cpuShutdown() void cpuShutdown()
@ -517,6 +523,7 @@ void __fastcall eeGameStarting()
{ {
//Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry ); //Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry );
g_GameStarted = true; g_GameStarted = true;
g_GameLoading = false;
GetCoreThread().GameStartingInThread(); GetCoreThread().GameStartingInThread();
// GameStartingInThread may issue a reset of the cpu and/or recompilers. Check for and // GameStartingInThread may issue a reset of the cpu and/or recompilers. Check for and
@ -530,10 +537,8 @@ void __fastcall eeGameStarting()
} }
// Called from recompilers; __fastcall define is mandatory. // Called from recompilers; __fastcall define is mandatory.
void __fastcall eeloadReplaceOSDSYS() void __fastcall eeloadHook()
{ {
g_SkipBiosHack = false;
const wxString &elf_override = GetCoreThread().GetElfOverride(); const wxString &elf_override = GetCoreThread().GetElfOverride();
if (!elf_override.IsEmpty()) if (!elf_override.IsEmpty())
@ -541,55 +546,63 @@ void __fastcall eeloadReplaceOSDSYS()
else else
cdvdReloadElfInfo(); cdvdReloadElfInfo();
// didn't recognize an ELF wxString discelf;
if (ElfEntry == 0xFFFFFFFF) { int disctype = GetPS2ElfName(discelf);
eeGameStarting();
return;
}
static u32 osdsys = 0, osdsys_p = 0;
// Memory this high is safe before the game's running presumably
// Other options are kernel memory (first megabyte) or the scratchpad
// PS2LOGO is loaded at 16MB, let's use 17MB
const u32 safemem = 0x1100000;
// The strings are all 64-bit aligned. Why? I don't know, but they are
for (u32 i = EELOAD_START; i < EELOAD_START + EELOAD_SIZE; i += 8) {
if (!strcmp((char*)PSM(i), "rom0:OSDSYS")) {
osdsys = i;
break;
}
}
pxAssert(osdsys);
for (u32 i = osdsys - 4; i >= EELOAD_START; i -= 4) {
if (memRead32(i) == osdsys) {
osdsys_p = i;
break;
}
}
pxAssert(osdsys_p);
std::string elfname; std::string elfname;
if (cpuRegs.GPR.n.a0.SD[0] >= 2) // argc >= 2
elfname = (char*)PSM(memRead32(cpuRegs.GPR.n.a1.UD[0] + 4)); // argv[1]
if (!elf_override.IsEmpty()) if (g_SkipBiosHack && elfname.empty())
{ {
elfname += "host:"; std::string elftoload;
elfname += elf_override.ToUTF8(); if (!elf_override.IsEmpty())
} {
else elftoload = "host:";
{ elftoload += elf_override.ToUTF8();
wxString boot2; }
if (GetPS2ElfName(boot2) == 2) else
elfname = boot2.ToUTF8(); {
if (disctype == 2)
elftoload = discelf.ToUTF8();
}
if (!elftoload.empty())
{
#if 0
// FIXME: you'd think that changing argc and argv would work but no, need to work out why not
// This method would support adding command line arguments to homebrew (and is generally less hacky)
// It works if you hook on rom0:PS2LOGO loading, but not on the first call with no arguments
cpuRegs.GPR.n.a0.SD[0] = 2; // argc = 2
// argv[0] = "EELOAD"
strcpy((char*)PSM(cpuRegs.GPR.n.a1.UD[0] + 0x40), "EELOAD");
memWrite32(cpuRegs.GPR.n.a1.UD[0] + 0, cpuRegs.GPR.n.a1.UD[0] + 0x40);
// argv[1] = elftoload
strcpy((char*)PSM(cpuRegs.GPR.n.a1.UD[0] + 0x47), elftoload.c_str());
memWrite32(cpuRegs.GPR.n.a1.UD[0] + 4, cpuRegs.GPR.n.a1.UD[0] + 0x47);
memWrite32(cpuRegs.GPR.n.a1.UD[0] + 8, 0);
g_GameLoading = true;
return;
#else
// The strings are all 64-bit aligned. Why? I don't know, but they are
for (u32 osdsys_str = EELOAD_START; osdsys_str < EELOAD_START + EELOAD_SIZE; osdsys_str += 8) {
if (!strcmp((char*)PSM(osdsys_str), "rom0:OSDSYS")) {
for (u32 osdsys_ptr = osdsys_str - 4; osdsys_ptr >= EELOAD_START; osdsys_ptr -= 4) {
if (memRead32(osdsys_ptr) == osdsys_str) {
strcpy((char*)PSM(cpuRegs.GPR.n.a1.UD[0] + 0x40), elftoload.c_str());
memWrite32(osdsys_ptr, cpuRegs.GPR.n.a1.UD[0] + 0x40);
g_GameLoading = true;
return;
}
}
}
}
#endif
}
} }
if (!elfname.empty()) if (!g_GameStarted && disctype == 2 && elfname == discelf)
{ g_GameLoading = true;
strcpy((char*)PSM(safemem), elfname.c_str());
memWrite32(osdsys_p, safemem);
}
// else... uh...?
} }
inline bool isBranchOrJump(u32 addr) inline bool isBranchOrJump(u32 addr)

View File

@ -26,6 +26,7 @@ class BaseR5900Exception;
extern bool g_SkipBiosHack; extern bool g_SkipBiosHack;
extern bool g_GameStarted; extern bool g_GameStarted;
extern bool g_GameLoading;
namespace Exception namespace Exception
{ {
@ -272,9 +273,10 @@ const u32 EEKERNEL_START = 0;
const u32 EENULL_START = 0x81FC0; const u32 EENULL_START = 0x81FC0;
const u32 EELOAD_START = 0x82000; const u32 EELOAD_START = 0x82000;
const u32 EELOAD_SIZE = 0x20000; // overestimate for searching const u32 EELOAD_SIZE = 0x20000; // overestimate for searching
extern u32 eeloadMain;
extern void __fastcall eeGameStarting(); extern void __fastcall eeGameStarting();
extern void __fastcall eeloadReplaceOSDSYS(); extern void __fastcall eeloadHook();
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// R5900cpu // R5900cpu

View File

@ -1607,14 +1607,18 @@ static void __fastcall recRecompile( const u32 startpc )
pxAssert(s_pCurBlockEx); pxAssert(s_pCurBlockEx);
if (g_SkipBiosHack && HWADDR(startpc) == EELOAD_START) { if (HWADDR(startpc) == EELOAD_START) {
xFastCall(eeloadReplaceOSDSYS); // The EELOAD _start function is the same across all BIOS versions afaik
xCMP(ptr32[&cpuRegs.pc], startpc); u32 mainjump = memRead32(EELOAD_START + 0x9c);
xJNE(DispatcherReg); if (mainjump >> 26 == 3) // JAL
eeloadMain = ((EELOAD_START + 0xa0) & 0xf0000000U) | (mainjump << 2 & 0x0fffffffU);
} }
if (eeloadMain && HWADDR(startpc) == HWADDR(eeloadMain))
xFastCall(eeloadHook);
// this is the only way patches get applied, doesn't depend on a hack // this is the only way patches get applied, doesn't depend on a hack
if (HWADDR(startpc) == ElfEntry) { if (g_GameLoading && HWADDR(startpc) == ElfEntry) {
Console.WriteLn(L"Elf entry point @ 0x%08x about to get recompiled. Load patches first.", startpc); Console.WriteLn(L"Elf entry point @ 0x%08x about to get recompiled. Load patches first.", startpc);
xFastCall(eeGameStarting); xFastCall(eeGameStarting);
// Apply patch as soon as possible. Normally it is done in // Apply patch as soon as possible. Normally it is done in