diff --git a/pcsx2/Interpreter.cpp b/pcsx2/Interpreter.cpp index 8a5bb75279..3b74ea5445 100644 --- a/pcsx2/Interpreter.cpp +++ b/pcsx2/Interpreter.cpp @@ -512,8 +512,8 @@ static void intExecute() bool instruction_was_cancelled; enum ExecuteState { RESET, - REPLACE_OSDSYS_DONE, - GAME_STARTING_DONE + GAME_LOADING, + GAME_RUNNING }; ExecuteState state = RESET; do { @@ -523,24 +523,32 @@ static void intExecute() // resume it after a cancelled instruction. switch (state) { case RESET: - if (g_SkipBiosHack) { - do - execI(); - while (cpuRegs.pc != EELOAD_START); - eeloadReplaceOSDSYS(); - } - state = REPLACE_OSDSYS_DONE; + do + execI(); + while (cpuRegs.pc != (eeloadMain ? eeloadMain : EELOAD_START)); + if (cpuRegs.pc == EELOAD_START) + { + // The EELOAD _start function is the same across all BIOS versions afaik + 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) { do execI(); while (cpuRegs.pc != ElfEntry); eeGameStarting(); } - state = GAME_STARTING_DONE; + state = GAME_RUNNING; - case GAME_STARTING_DONE: + case GAME_RUNNING: while (true) execI(); } diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index e514cd6aa7..e88c7cbaa0 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -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_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; bool eeEventTestIsActive = false; +u32 eeloadMain = 0; + extern SysMainMemory& GetVmMemory(); void cpuReset() @@ -87,6 +90,7 @@ void cpuReset() Deci2Reset(); g_GameStarted = false; + g_GameLoading = false; g_SkipBiosHack = EmuConfig.UseBOOT2Injection; ElfCRC = 0; @@ -103,6 +107,8 @@ void cpuReset() // run into this while testing minor binary hacked changes to ISO images, which // is why I found out about this) --air LastELF = L""; + + eeloadMain = 0; } void cpuShutdown() @@ -517,6 +523,7 @@ void __fastcall eeGameStarting() { //Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry ); g_GameStarted = true; + g_GameLoading = false; GetCoreThread().GameStartingInThread(); // 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. -void __fastcall eeloadReplaceOSDSYS() +void __fastcall eeloadHook() { - g_SkipBiosHack = false; - const wxString &elf_override = GetCoreThread().GetElfOverride(); if (!elf_override.IsEmpty()) @@ -541,55 +546,63 @@ void __fastcall eeloadReplaceOSDSYS() else cdvdReloadElfInfo(); - // didn't recognize an ELF - if (ElfEntry == 0xFFFFFFFF) { - 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); + wxString discelf; + int disctype = GetPS2ElfName(discelf); 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:"; - elfname += elf_override.ToUTF8(); - } - else - { - wxString boot2; - if (GetPS2ElfName(boot2) == 2) - elfname = boot2.ToUTF8(); + std::string elftoload; + if (!elf_override.IsEmpty()) + { + elftoload = "host:"; + elftoload += elf_override.ToUTF8(); + } + else + { + 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()) - { - strcpy((char*)PSM(safemem), elfname.c_str()); - memWrite32(osdsys_p, safemem); - } - // else... uh...? + if (!g_GameStarted && disctype == 2 && elfname == discelf) + g_GameLoading = true; } inline bool isBranchOrJump(u32 addr) diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index 9cf9ba1f48..ffe6aa3fa6 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -26,6 +26,7 @@ class BaseR5900Exception; extern bool g_SkipBiosHack; extern bool g_GameStarted; +extern bool g_GameLoading; namespace Exception { @@ -272,9 +273,10 @@ const u32 EEKERNEL_START = 0; const u32 EENULL_START = 0x81FC0; const u32 EELOAD_START = 0x82000; const u32 EELOAD_SIZE = 0x20000; // overestimate for searching +extern u32 eeloadMain; extern void __fastcall eeGameStarting(); -extern void __fastcall eeloadReplaceOSDSYS(); +extern void __fastcall eeloadHook(); // -------------------------------------------------------------------------------------- // R5900cpu diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index f064c40d51..c9673360b4 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -1607,14 +1607,18 @@ static void __fastcall recRecompile( const u32 startpc ) pxAssert(s_pCurBlockEx); - if (g_SkipBiosHack && HWADDR(startpc) == EELOAD_START) { - xFastCall(eeloadReplaceOSDSYS); - xCMP(ptr32[&cpuRegs.pc], startpc); - xJNE(DispatcherReg); + if (HWADDR(startpc) == EELOAD_START) { + // The EELOAD _start function is the same across all BIOS versions afaik + u32 mainjump = memRead32(EELOAD_START + 0x9c); + 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 - 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); xFastCall(eeGameStarting); // Apply patch as soon as possible. Normally it is done in