diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp index 6f8f67bf11..f35c24c594 100644 --- a/Source/Core/Core/Src/Boot/Boot.cpp +++ b/Source/Core/Core/Src/Boot/Boot.cpp @@ -184,14 +184,6 @@ bool CBoot::BootUp() NOTICE_LOG(BOOT, "Booting %s", _StartupPara.m_strFilename.c_str()); - // HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code handler - if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats) - { - HLE::Patch(0x80001800, "HBReload"); - const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' }; - Memory::WriteBigEData(stubstr, 0x80001804, 8); - } - g_symbolDB.Clear(); VideoInterface::Preset(_StartupPara.bNTSC); switch (_StartupPara.m_BootType) @@ -415,6 +407,19 @@ bool CBoot::BootUp() return false; } } + + // HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code handler + if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats) + { + HLE::Patch(0x80001800, "HBReload"); + const u8 stubstr[] = { 'S', 'T', 'U', 'B', 'H', 'A', 'X', 'X' }; + Memory::WriteBigEData(stubstr, 0x80001804, 8); + } + + // Not part of the binary itself, but either we or Gecko OS might insert + // this, and it doesn't clear the icache properly. + HLE::Patch(0x800018a8, "GeckoCodehandler"); + Host_UpdateLogDisplay(); return true; } diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp index 252e758746..f8359e1bc5 100644 --- a/Source/Core/Core/Src/GeckoCode.cpp +++ b/Source/Core/Core/Src/GeckoCode.cpp @@ -154,8 +154,9 @@ bool InstallCodeHandler() // Turn off Pause on start Memory::Write_U32(0, 0x80002774); - // Write the Game ID into the location expected by WiiRD - Memory::WriteBigEData(Memory::GetPointer(0x80000000), 0x80001800, 6); + // Write a magic value to 'gameid' (codehandleronly does not actually read this). + // For the purpose of this, see HLEGeckoCodehandler. + Memory::Write_U32(0xd01f1bad, 0x80001800); // Create GCT in memory Memory::Write_U32(0x00d0c0de, codelist_location); @@ -279,10 +280,7 @@ void RunCodeHandler() { if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats && active_codes.size() > 0) { - u8 *gameId = Memory::GetPointer(0x80000000); - u8 *wiirdId = Memory::GetPointer(0x80001800); - - if (!code_handler_installed || memcmp(gameId, wiirdId, 6)) + if (!code_handler_installed || Memory::Read_U32(0x80001800) - 0xd01f1bad > 5) code_handler_installed = InstallCodeHandler(); if (code_handler_installed) diff --git a/Source/Core/Core/Src/HLE/HLE.cpp b/Source/Core/Core/Src/HLE/HLE.cpp index 6469359a31..3d3d8d6052 100644 --- a/Source/Core/Core/Src/HLE/HLE.cpp +++ b/Source/Core/Core/Src/HLE/HLE.cpp @@ -63,6 +63,7 @@ static const SPatch OSPatches[] = { "___blank(char *,...)", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used for early init things (normally) { "___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, { "__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG }, // used by sysmenu (+more?) + { "GeckoCodehandler", HLE_Misc::HLEGeckoCodehandler, HLE_HOOK_START, HLE_TYPE_GENERIC }, }; static const SPatch OSBreakPoints[] = diff --git a/Source/Core/Core/Src/HLE/HLE_Misc.cpp b/Source/Core/Core/Src/HLE/HLE_Misc.cpp index 0b5db4f17f..fa5f8c7d61 100644 --- a/Source/Core/Core/Src/HLE/HLE_Misc.cpp +++ b/Source/Core/Core/Src/HLE/HLE_Misc.cpp @@ -17,6 +17,7 @@ #include "IPC_HLE/WII_IPC_HLE_Device_usb.h" #include "HLE.h" #include "PowerPC/PPCAnalyst.h" +#include "PowerPC/PPCCache.h" #include "PowerPC/SignatureDB.h" #include "PowerPC/PPCSymbolDB.h" #include "CommonPaths.h" @@ -242,4 +243,26 @@ void OSBootDol() NPC = PC; } +void HLEGeckoCodehandler() +{ + // Work around the codehandler not properly invalidating the icache, but + // only the first few frames. + // (Project M uses a conditional to only apply patches after something has + // been read into memory, or such, so we do the first 5 frames. More + // robust alternative would be to actually detect memory writes, but that + // would be even uglier.) + u32 magic = 0xd01f1bad; + u32 existing = Memory::Read_U32(0x80001800); + if (existing - magic == 5) + { + return; + } + else if(existing - magic > 5) + { + existing = magic; + } + Memory::Write_U32(existing + 1, 0x80001800); + PowerPC::ppcState.iCache.Reset(); +} + } diff --git a/Source/Core/Core/Src/HLE/HLE_Misc.h b/Source/Core/Core/Src/HLE/HLE_Misc.h index 43924a4dcf..bc3acd143f 100644 --- a/Source/Core/Core/Src/HLE/HLE_Misc.h +++ b/Source/Core/Core/Src/HLE/HLE_Misc.h @@ -12,6 +12,7 @@ namespace HLE_Misc void HBReload(); void OSBootDol(); void OSGetResetCode(); + void HLEGeckoCodehandler(); } #endif diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp index 9e52b70e5a..31baf28abb 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -150,6 +150,12 @@ void Reset(bool _bHard) g_FdMap[i] = NULL; } + u32 j; + for (j=0; jGetDeviceName().c_str(), Command, _Address); - } - else - { - INFO_LOG(WII_IPC_HLE, "<<-- Reply Failed to Unknown (%08x) IPC Request %i @ 0x%08x ", DeviceID, Command, _Address); - } - } } // Happens AS SOON AS IPC gets a new pointer! diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp index 754b930053..98e77c7695 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -594,13 +594,18 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) ViewCount = FileSize / DiscIO::INANDContentLoader::TICKET_SIZE; _dbg_assert_msg_(WII_IPC_ES, (ViewCount>0) && (ViewCount<=4), "IOCTL_ES_GETVIEWCNT ticket count seems to be wrong"); } + else if (TitleID >> 32 == 0x00000001) + { + // Fake a ticket view to make IOS reload work. + ViewCount = 1; + } else { + ViewCount = 0; if (TitleID == TITLEID_SYSMENU) { PanicAlertT("There must be a ticket for 00000001/00000002. Your NAND dump is probably incomplete."); } - ViewCount = 0; //retVal = ES_NO_TICKET_INSTALLED; } } @@ -651,6 +656,19 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) } } } + else if (TitleID >> 32 == 0x00000001) + { + // For IOS titles, the ticket view isn't normally parsed by either the + // SDK or libogc, just passed to LaunchTitle, so this + // shouldn't matter at all. Just fill out some fields just + // to be on the safe side. + u32 Address = Buffer.PayloadBuffer[0].m_Address; + memset(Memory::GetPointer(Address), 0, 0xD8); + Memory::Write_U64(TitleID, Address + 4 + (0x1dc - 0x1d0)); // title ID + Memory::Write_U16(0xffff, Address + 4 + (0x1e4 - 0x1d0)); // unnnown + Memory::Write_U32(0xff00, Address + 4 + (0x1ec - 0x1d0)); // access mask + memset(Memory::GetPointer(Address + 4 + (0x222 - 0x1d0)), 0xff, 0x20); // content permissions + } else { //retVal = ES_NO_TICKET_INSTALLED; @@ -916,10 +934,11 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) // Lie to mem about loading a different IOS // someone with an affected game should test IOSv = TitleID & 0xffff; + bSuccess = true; } - if (!bSuccess && IOSv >= 30 && IOSv != 0xffff) + if (!bSuccess) { - PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload an IOS or a title that is not available in your NAND dump\n" + PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload a title that is not available in your NAND dump\n" "TitleID %016llx.\n Dolphin will likely hang now.", TitleID); } else @@ -966,14 +985,13 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) ERROR_LOG(WII_IPC_ES, "IOCTL_ES_LAUNCH %016llx %08x %016llx %08x %016llx %04x", TitleID,view,ticketid,devicetype,titleid,access); // IOCTL_ES_LAUNCH 0001000248414341 00000001 0001c0fef3df2cfa 00000000 0001000248414341 ffff - //We have to handle the reply ourselves as this handle is not valid anymore - + // This is necessary because Reset(true) above deleted this object. Ew. // It seems that the original hardware overwrites the command after it has been // executed. We write 8 which is not any valid command, and what IOS does Memory::Write_U32(8, _CommandAddress); // IOS seems to write back the command that was responded to - Memory::Write_U32(6, _CommandAddress + 8); + Memory::Write_U32(7, _CommandAddress + 8); // Generate a reply to the IPC command WII_IPC_HLE_Interface::EnqReply(_CommandAddress, 0); diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp index ca98489fd3..a99eab7cea 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp @@ -106,10 +106,20 @@ int Interpreter::SingleStepInner(void) if (HLE::IsEnabled(flags)) { HLEFunction(function); + if (type == HLE::HLE_HOOK_START) + { + // Run the original. + function = 0; + } + } + else + { + function = 0; } } } - else + + if (function == 0) { #ifdef USE_GDBSTUB if (gdb_active() && gdb_bp_x(PC)) {