From 3f11879640c455185d1ed7a6078f77c158f5e1ed Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 23 Nov 2016 03:57:33 +0900 Subject: [PATCH 1/5] ES HLE / WAD boot: hardcode the entrypoint NAND titles are always started at address 0x3400 with translation off. The entrypoint in the DOL is ignored. --- Source/Core/Core/Boot/Boot_WiiWAD.cpp | 6 +++++- Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index 8fa0e63565..3a54ee03ed 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -109,7 +109,11 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename) return false; pDolLoader->Load(); - PC = pDolLoader->GetEntryPoint(); + // NAND titles start with address translation off at 0x3400 (via the PPC bootstub) + // The state of other CPU registers (like the BAT registers) doesn't matter much + // because the realmode code at 0x3400 initializes everything itself anyway. + MSR = 0; + PC = 0x3400; // Pass the "#002 check" // Apploader should write the IOS version and revision to 0x3140, and compare it diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp index fb8abf301c..376bebe327 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -968,12 +968,12 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) if (pDolLoader->IsValid()) { pDolLoader->Load(); // TODO: Check why sysmenu does not load the DOL correctly - // WADs start with address translation off at the given entry point. + // NAND titles start with address translation off at 0x3400 (via the PPC bootstub) // // The state of other CPU registers (like the BAT registers) doesn't matter much - // because the WAD initializes everything itself anyway. + // because the realmode code at 0x3400 initializes everything itself anyway. MSR = 0; - PC = pDolLoader->GetEntryPoint(); + PC = 0x3400; bSuccess = true; } else From a6742d9cf7154937d4cc551b40157c1f41818e67 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 23 Nov 2016 04:03:13 +0900 Subject: [PATCH 2/5] ELF boot: scan segments for Wii mode detection, not sections --- Source/Core/Core/Boot/Boot_ELF.cpp | 8 ++++---- Source/Core/Core/Boot/ElfReader.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/Boot/Boot_ELF.cpp b/Source/Core/Core/Boot/Boot_ELF.cpp index 42ba5e2052..48efad678e 100644 --- a/Source/Core/Core/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Boot/Boot_ELF.cpp @@ -35,12 +35,12 @@ bool CBoot::IsElfWii(const std::string& filename) u32 HID4_mask = Common::swap32(0xfc1fffff); ElfReader reader(elf.get()); - for (int i = 0; i < reader.GetNumSections(); ++i) + for (int i = 0; i < reader.GetNumSegments(); ++i) { - if (reader.IsCodeSection(i)) + if (reader.IsCodeSegment(i)) { - u32* code = (u32*)reader.GetSectionDataPtr(i); - for (u32 j = 0; j < reader.GetSectionSize(i) / sizeof(u32); ++j) + u32* code = (u32*)reader.GetSegmentPtr(i); + for (u32 j = 0; j < reader.GetSegmentSize(i) / sizeof(u32); ++j) { if ((code[j] & HID4_mask) == HID4_pattern) return true; diff --git a/Source/Core/Core/Boot/ElfReader.h b/Source/Core/Core/Boot/ElfReader.h index b1d57d6aed..92392e2bc0 100644 --- a/Source/Core/Core/Boot/ElfReader.h +++ b/Source/Core/Core/Boot/ElfReader.h @@ -55,8 +55,9 @@ public: else return nullptr; } - bool IsCodeSection(int section) const { return sections[section].sh_type == SHT_PROGBITS; } + bool IsCodeSegment(int segment) const { return segments[segment].p_flags & PF_X; } const u8* GetSegmentPtr(int segment) { return GetPtr(segments[segment].p_offset); } + int GetSegmentSize(int segment) const { return segments[segment].p_filesz; } u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } int GetSectionSize(SectionID section) const { return sections[section].sh_size; } SectionID GetSectionByName(const char* name, int firstSection = 0) const; //-1 for not found From 2b906e3fc45a908704863db847d995a4b9b63374 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 23 Nov 2016 04:17:31 +0900 Subject: [PATCH 3/5] DOL/ELF loaders: enable HID4.SBE in Wii mode When booting "cooked" executables, BATs should already be set up and enabled. They should only really be disabled when booting NAND contents in real mode. --- Source/Core/Core/Boot/Boot.cpp | 2 ++ Source/Core/Core/Boot/Boot_ELF.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 59b6eee70c..da104586c7 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -381,6 +381,8 @@ bool CBoot::BootUp() PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; + if (dolLoader.IsWii()) + HID4.SBE = 1; PowerPC::DBATUpdated(); PowerPC::IBATUpdated(); diff --git a/Source/Core/Core/Boot/Boot_ELF.cpp b/Source/Core/Core/Boot/Boot_ELF.cpp index 48efad678e..c626725698 100644 --- a/Source/Core/Core/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Boot/Boot_ELF.cpp @@ -85,6 +85,8 @@ bool CBoot::Boot_ELF(const std::string& filename) PowerPC::ppcState.spr[SPR_DBAT4L] = 0x10000002; PowerPC::ppcState.spr[SPR_DBAT5U] = 0xd0001fff; PowerPC::ppcState.spr[SPR_DBAT5L] = 0x1000002a; + if (IsElfWii(filename)) + HID4.SBE = 1; PowerPC::DBATUpdated(); PowerPC::IBATUpdated(); From 288e75f672ae6bc795210f2b3c67be5cf1c2e01c Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 1 Dec 2016 06:35:12 +0900 Subject: [PATCH 4/5] Wii IPC HLE: Fix IPC missing reply fail --- Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp | 10 ++++++++++ .../Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp index 83d8397331..b59bb7f552 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE.cpp @@ -533,6 +533,11 @@ void ExecuteCommand(u32 address) { result = device->IOCtl(address); } + else + { + Memory::Write_U32(FS_EINVAL, address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } break; } case IPC_CMD_IOCTLV: @@ -541,6 +546,11 @@ void ExecuteCommand(u32 address) { result = device->IOCtlV(address); } + else + { + Memory::Write_U32(FS_EINVAL, address + 4); + result = IWII_IPC_HLE_Device::GetDefaultReply(); + } break; } default: diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp index c1d7670847..87f9cecedd 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_ven.cpp @@ -50,7 +50,7 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_ven::IOCtlV(u32 command_address) IPCCommandResult CWII_IPC_HLE_Device_usb_ven::IOCtl(u32 command_address) { - IPCCommandResult reply = GetNoReply(); + IPCCommandResult reply = GetDefaultReply(); u32 command = Memory::Read_U32(command_address + 0x0c); u32 buffer_in = Memory::Read_U32(command_address + 0x10); u32 buffer_in_size = Memory::Read_U32(command_address + 0x14); From 90c2dec02d6104dd4c9c358c5665d06bf864383f Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 1 Dec 2016 06:50:19 +0900 Subject: [PATCH 5/5] Wii IPC HLE: do not clobber memory when launching a new title It's questionable whether ES_LAUNCH should write *anything* to the command structure at all, ever, given that it never actually returns it back through the mailbox. But it *definitely* shouldn't write anything to it if it has just launched a DOL, because otherwise it might clobber code/data from the just-loaded application. --- .../Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp index 376bebe327..2c514aecd8 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -937,6 +937,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) { _dbg_assert_(WII_IPC_ES, Buffer.NumberInBuffer == 2); bool bSuccess = false; + bool bReset = false; u16 IOSv = 0xffff; u64 TitleID = Memory::Read_U64(Buffer.InBuffer[0].m_Address); @@ -975,6 +976,7 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) MSR = 0; PC = 0x3400; bSuccess = true; + bReset = true; } else { @@ -1045,7 +1047,12 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) Memory::Write_U32(Memory::Read_U32(0x00003140), 0x00003188); // TODO: provide correct return code when bSuccess= false - Memory::Write_U32(0, _CommandAddress + 0x4); + // Note: If we just reset the PPC, don't write anything to the command buffer. This + // could clobber the DOL we just loaded. + if (!bReset) + { + Memory::Write_U32(0, _CommandAddress + 0x4); + } ERROR_LOG(WII_IPC_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x", @@ -1055,10 +1062,13 @@ IPCCommandResult CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) // This is necessary because Reset(true) above deleted this object. Ew. - // The original hardware overwrites the command type with the async reply type. - Memory::Write_U32(IPC_REP_ASYNC, _CommandAddress); - // IOS also seems to write back the command that was responded to in the FD field. - Memory::Write_U32(IPC_CMD_IOCTLV, _CommandAddress + 8); + if (!bReset) + { + // The original hardware overwrites the command type with the async reply type. + Memory::Write_U32(IPC_REP_ASYNC, _CommandAddress); + // IOS also seems to write back the command that was responded to in the FD field. + Memory::Write_U32(IPC_CMD_IOCTLV, _CommandAddress + 8); + } // Generate a "reply" to the IPC command. ES_LAUNCH is unique because it // involves restarting IOS; IOS generates two acknowledgements in a row.