From 39a524f47df5c40688ca05b4d800b5818a42c943 Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 5 Sep 2013 13:00:25 -0400 Subject: [PATCH 1/8] Returning false from an IPC_HLE method should not produce an INFO_LOG. It's commonly used to delay replying to a message and is in no way an error. --- Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp | 11 ----------- 1 file changed, 11 deletions(-) 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..8425f092d8 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -548,17 +548,6 @@ void ExecuteCommand(u32 _Address) // Generate a reply to the IPC command EnqReply(_Address, reply_delay); } - else - { - if (pDevice) - { - INFO_LOG(WII_IPC_HLE, "<<-- Reply Failed to %s IPC Request %i @ 0x%08x ", pDevice->GetDeviceName().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! From 868ab1918b25e6c817a849ae18540076443635b5 Mon Sep 17 00:00:00 2001 From: comex Date: Wed, 11 Sep 2013 22:17:58 -0400 Subject: [PATCH 2/8] Reset es_inuse upon Reset. --- Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp | 6 ++++++ 1 file changed, 6 insertions(+) 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 8425f092d8..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; j Date: Wed, 11 Sep 2013 22:43:00 -0400 Subject: [PATCH 3/8] Fake ticket views for missing IOS title. --- .../Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) 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..254fcecbd6 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; From 354b205decf33451061b5dff41e64f7535d58634 Mon Sep 17 00:00:00 2001 From: comex Date: Wed, 11 Sep 2013 22:43:12 -0400 Subject: [PATCH 4/8] Return correct value to fix libogc's IOS launch sequence. --- Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 254fcecbd6..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 @@ -934,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 @@ -984,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); From a316e2f1827d159e3fbf501f1a10c37bf478700c Mon Sep 17 00:00:00 2001 From: comex Date: Wed, 11 Sep 2013 23:55:17 -0400 Subject: [PATCH 5/8] Hook the Gecko codehandler to invalidate the icache. The codehandler is broken and does not do this itself. This is a hack, but a lot simpler than the alternatives. --- Source/Core/Core/Src/Boot/Boot.cpp | 4 ++++ Source/Core/Core/Src/HLE/HLE.cpp | 1 + Source/Core/Core/Src/HLE/HLE_Misc.cpp | 23 +++++++++++++++++++++++ Source/Core/Core/Src/HLE/HLE_Misc.h | 1 + 4 files changed, 29 insertions(+) diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp index 6f8f67bf11..9f48b87a32 100644 --- a/Source/Core/Core/Src/Boot/Boot.cpp +++ b/Source/Core/Core/Src/Boot/Boot.cpp @@ -192,6 +192,10 @@ bool CBoot::BootUp() 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"); + g_symbolDB.Clear(); VideoInterface::Preset(_StartupPara.bNTSC); switch (_StartupPara.m_BootType) 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 From e6cd3b328376bb3ec71e4f4571991e5d4dec1397 Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 12 Sep 2013 00:03:37 -0400 Subject: [PATCH 6/8] Fix placement of HLE::Patch to not get overwritten by HLE::PatchFunctions. (This applies to the existing HBReload hook, which would be erased in various circumstances depending on the type of file loaded.) --- Source/Core/Core/Src/Boot/Boot.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp index 9f48b87a32..f35c24c594 100644 --- a/Source/Core/Core/Src/Boot/Boot.cpp +++ b/Source/Core/Core/Src/Boot/Boot.cpp @@ -184,18 +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); - } - - // 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"); - g_symbolDB.Clear(); VideoInterface::Preset(_StartupPara.bNTSC); switch (_StartupPara.m_BootType) @@ -419,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; } From e62bc44f15edfc21819994cd8908698f678d6b30 Mon Sep 17 00:00:00 2001 From: comex Date: Fri, 13 Sep 2013 16:26:39 -0400 Subject: [PATCH 7/8] Use d01f1bad for the gameid check in RunCodeHandler rather than the actual ID. This avoids conflict with the icache hack. codehandleronly.s does not actually use the gameid, so it shouldn't matter. --- Source/Core/Core/Src/GeckoCode.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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) From e15e30602c5c30c4f667278ca114e37747473f6c Mon Sep 17 00:00:00 2001 From: comex Date: Fri, 13 Sep 2013 18:11:53 -0400 Subject: [PATCH 8/8] Fix HLE_HOOK_START in the interpreter. --- .../Core/Src/PowerPC/Interpreter/Interpreter.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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)) {