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 42ba5e2052..c626725698 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; @@ -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(); 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/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 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_es.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_es.cpp index fb8abf301c..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); @@ -968,13 +969,14 @@ 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; + 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. 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);