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;
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();
}

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_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)

View File

@ -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

View File

@ -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