diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index be4ef2636c..3b004eca78 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -5,7 +5,10 @@ #include "Core/Boot/Boot.h" #include +#include +#include #include +#include #include #include #include @@ -25,6 +28,7 @@ #include "Core/Boot/DolReader.h" #include "Core/Boot/ElfReader.h" +#include "Core/CommonTitles.h" #include "Core/ConfigManager.h" #include "Core/FifoPlayer/FifoPlayer.h" #include "Core/HLE/HLE.h" @@ -418,3 +422,38 @@ BootExecutableReader::BootExecutableReader(const std::vector& bytes) : m_byt } BootExecutableReader::~BootExecutableReader() = default; + +void StateFlags::UpdateChecksum() +{ + constexpr size_t length_in_bytes = sizeof(StateFlags) - 4; + constexpr size_t num_elements = length_in_bytes / sizeof(u32); + std::array flag_data; + std::memcpy(flag_data.data(), &flags, length_in_bytes); + checksum = std::accumulate(flag_data.cbegin(), flag_data.cend(), 0U); +} + +void UpdateStateFlags(std::function update_function) +{ + const std::string file_path = + Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + WII_STATE; + + File::IOFile file; + StateFlags state; + if (File::Exists(file_path)) + { + file.Open(file_path, "r+b"); + file.ReadBytes(&state, sizeof(state)); + } + else + { + File::CreateFullPath(file_path); + file.Open(file_path, "a+b"); + memset(&state, 0, sizeof(state)); + } + + update_function(&state); + state.UpdateChecksum(); + + file.Seek(0, SEEK_SET); + file.WriteBytes(&state, sizeof(state)); +} diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index f5428616af..96dd2002e4 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include @@ -128,3 +129,18 @@ public: protected: std::vector m_bytes; }; + +struct StateFlags +{ + void UpdateChecksum(); + u32 checksum; + u8 flags; + u8 type; + u8 discstate; + u8 returnto; + u32 unknown[6]; +}; + +// Reads the state file from the NAND, then calls the passed update function to update the struct, +// and finally writes the updated state file to the NAND. +void UpdateStateFlags(std::function update_function); diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 910fe5db81..794e979aa1 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -286,7 +286,6 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id) Memory::Write_U32(0x00000000, 0x00000030); // Init Memory::Write_U32(0x817FEC60, 0x00000034); // Init // 38, 3C should get start, size of FST through apploader - Memory::Write_U32(0x38a00040, 0x00000060); // Exception init Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?) Memory::Write_U32(0x8179b500, 0x000000f4); // __start @@ -296,10 +295,19 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id) Memory::Write_U32(0x00000000, 0x000030c0); // EXI Memory::Write_U32(0x00000000, 0x000030c4); // EXI Memory::Write_U32(0x00000000, 0x000030dc); // Time - Memory::Write_U32(0x00000000, 0x000030d8); // Time + Memory::Write_U32(0xffffffff, 0x000030d8); // Unknown, set by any official NAND title Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable Memory::Write_U32(0x00000000, 0x000030f0); // Apploader + // During the boot process, 0x315c is first set to 0xdeadbeef by IOS + // in the boot_ppc syscall. The value is then partly overwritten by SDK titles. + // Two bytes at 0x315e are used to indicate the "devkit boot program version". + // It is only written to by the system menu, so we must do so here as well. + // + // 0x0113 appears to mean v1.13, which is the latest version. + // It is fine to always use the latest value as apploaders work with all versions. + Memory::Write_U16(0x0113, 0x0000315e); + if (!IOS::HLE::GetIOS()->BootIOS(ios_title_id)) return false; @@ -319,6 +327,15 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id) return true; } +static void WriteEmptyPlayRecord() +{ + const std::string file_path = + Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + "play_rec.dat"; + File::IOFile playrec_file(file_path, "r+b"); + std::vector empty_record(0x80); + playrec_file.WriteBytes(empty_record.data(), empty_record.size()); +} + // __________________________________________________________________________________________________ // Wii Bootstrap 2 HLE: // copy the apploader to 0x81200000 @@ -335,6 +352,21 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::Volume& volume) if (!tmd.IsValid()) return false; + WriteEmptyPlayRecord(); + UpdateStateFlags([](StateFlags* state) { + state->flags = 0xc1; + state->type = 0xff; + state->discstate = 0x01; + }); + + // While reading a disc, the system menu reads the first partition table + // (0x20 bytes from 0x00040020) and stores a pointer to the data partition entry. + // When launching the disc game, it copies the partition type and offset to 0x3194 + // and 0x3198 respectively. + const DiscIO::Partition data_partition = volume.GetGamePartition(); + Memory::Write_U32(0, 0x3194); + Memory::Write_U32(static_cast(data_partition.offset >> 2), 0x3198); + if (!SetupWiiMemory(tmd.GetIOSId())) return false; diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index 145ae48a1f..44d2b64262 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -2,15 +2,12 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include #include #include -#include #include #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/File.h" #include "Common/FileUtil.h" #include "Common/MsgHandler.h" #include "Common/NandPaths.h" @@ -24,55 +21,11 @@ #include "DiscIO/NANDContentLoader.h" -struct StateFlags -{ - u32 checksum; - u8 flags; - u8 type; - u8 discstate; - u8 returnto; - u32 unknown[6]; -}; - -static u32 StateChecksum(const StateFlags& flags) -{ - constexpr size_t length_in_bytes = sizeof(StateFlags) - 4; - constexpr size_t num_elements = length_in_bytes / sizeof(u32); - std::array flag_data; - - std::memcpy(flag_data.data(), &flags.flags, length_in_bytes); - - return std::accumulate(flag_data.cbegin(), flag_data.cend(), 0U); -} - bool CBoot::Boot_WiiWAD(const std::string& _pFilename) { - std::string state_filename( - Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + WII_STATE); - - if (File::Exists(state_filename)) - { - File::IOFile state_file(state_filename, "r+b"); - StateFlags state; - state_file.ReadBytes(&state, sizeof(StateFlags)); - - state.type = 0x03; // TYPE_RETURN - state.checksum = StateChecksum(state); - - state_file.Seek(0, SEEK_SET); - state_file.WriteBytes(&state, sizeof(StateFlags)); - } - else - { - File::CreateFullPath(state_filename); - File::IOFile state_file(state_filename, "a+b"); - StateFlags state; - memset(&state, 0, sizeof(StateFlags)); - state.type = 0x03; // TYPE_RETURN - state.discstate = 0x01; // DISCSTATE_WII - state.checksum = StateChecksum(state); - state_file.WriteBytes(&state, sizeof(StateFlags)); - } + UpdateStateFlags([](StateFlags* state) { + state->type = 0x03; // TYPE_RETURN + }); const DiscIO::NANDContentLoader& ContentLoader = DiscIO::NANDContentManager::Access().GetNANDLoader(_pFilename);