diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 7b546e474b..79f08118bf 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -37,25 +37,35 @@ #include "DiscIO/Enums.h" #include "DiscIO/NANDContentLoader.h" #include "DiscIO/Volume.h" +#include "DiscIO/VolumeCreator.h" -bool CBoot::DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt) +// Inserts a disc into the emulated disc drive and returns a pointer to it. +// The returned pointer must only be used while we are still booting, +// because DVDThread can do whatever it wants to the disc after that. +static const DiscIO::IVolume* SetDisc(std::unique_ptr volume) +{ + const DiscIO::IVolume* pointer = volume.get(); + DVDInterface::SetDisc(std::move(volume)); + return pointer; +} + +bool CBoot::DVDRead(const DiscIO::IVolume& volume, u64 dvd_offset, u32 output_address, u32 length, + bool decrypt) { std::vector buffer(length); - if (!DVDInterface::GetVolume().Read(dvd_offset, length, buffer.data(), decrypt)) + if (!volume.Read(dvd_offset, length, buffer.data(), decrypt)) return false; Memory::CopyToEmu(output_address, buffer.data(), length); return true; } -void CBoot::Load_FST(bool is_wii) +void CBoot::Load_FST(bool is_wii, const DiscIO::IVolume* volume) { - if (!DVDInterface::IsDiscInside()) + if (!volume) return; - const DiscIO::IVolume& volume = DVDInterface::GetVolume(); - // copy first 32 bytes of disc to start of Mem 1 - DVDRead(/*offset*/ 0, /*address*/ 0, /*length*/ 0x20, false); + DVDRead(*volume, /*offset*/ 0, /*address*/ 0, /*length*/ 0x20, false); // copy of game id Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180); @@ -68,15 +78,15 @@ void CBoot::Load_FST(bool is_wii) u32 fst_size = 0; u32 max_fst_size = 0; - volume.ReadSwapped(0x0424, &fst_offset, is_wii); - volume.ReadSwapped(0x0428, &fst_size, is_wii); - volume.ReadSwapped(0x042c, &max_fst_size, is_wii); + volume->ReadSwapped(0x0424, &fst_offset, is_wii); + volume->ReadSwapped(0x0428, &fst_size, is_wii); + volume->ReadSwapped(0x042c, &max_fst_size, is_wii); u32 arena_high = Common::AlignDown(0x817FFFFF - (max_fst_size << shift), 0x20); Memory::Write_U32(arena_high, 0x00000034); // load FST - DVDRead(fst_offset << shift, arena_high, fst_size << shift, is_wii); + DVDRead(*volume, fst_offset << shift, arena_high, fst_size << shift, is_wii); Memory::Write_U32(arena_high, 0x00000038); Memory::Write_U32(max_fst_size << shift, 0x0000003c); @@ -277,22 +287,22 @@ bool CBoot::BootUp() { case SConfig::BOOT_ISO: { - DVDInterface::SetVolumeName(_StartupPara.m_strFilename); - if (!DVDInterface::IsDiscInside()) + const DiscIO::IVolume* volume = + SetDisc(DiscIO::CreateVolumeFromFilename(_StartupPara.m_strFilename)); + + if (!volume) return false; - const DiscIO::IVolume& pVolume = DVDInterface::GetVolume(); - - if ((pVolume.GetVolumeType() == DiscIO::Platform::WII_DISC) != _StartupPara.bWii) + if ((volume->GetVolumeType() == DiscIO::Platform::WII_DISC) != _StartupPara.bWii) { PanicAlertT("Warning - starting ISO in wrong console mode!"); } - _StartupPara.bWii = pVolume.GetVolumeType() == DiscIO::Platform::WII_DISC; + _StartupPara.bWii = volume->GetVolumeType() == DiscIO::Platform::WII_DISC; // We HLE the bootrom if requested or if LLEing it fails if (_StartupPara.bHLE_BS2 || !Load_BS2(_StartupPara.m_strBootROM)) - EmulatedBS2(_StartupPara.bWii); + EmulatedBS2(_StartupPara.bWii, volume); PatchEngine::LoadPatches(); @@ -330,28 +340,28 @@ bool CBoot::BootUp() PanicAlertT("Warning - starting DOL in wrong console mode!"); } + const DiscIO::IVolume* volume = nullptr; if (!_StartupPara.m_strDVDRoot.empty()) { NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str()); - DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, dolWii, - _StartupPara.m_strApploader, _StartupPara.m_strFilename); + volume = SetDisc(DiscIO::CreateVolumeFromDirectory(_StartupPara.m_strDVDRoot, dolWii, + _StartupPara.m_strApploader, + _StartupPara.m_strFilename)); } else if (!_StartupPara.m_strDefaultISO.empty()) { NOTICE_LOG(BOOT, "Loading default ISO %s", _StartupPara.m_strDefaultISO.c_str()); - DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); + volume = SetDisc(DiscIO::CreateVolumeFromFilename(_StartupPara.m_strDefaultISO)); } - if (!EmulatedBS2(dolWii)) + if (!EmulatedBS2(dolWii, volume)) { if (dolWii) HID4.SBE = 1; SetupBAT(dolWii); - // Because there is no TMD to get the requested system (IOS) version from, - // we default to IOS58, which is the version used by the Homebrew Channel. if (dolWii) - SetupWiiMemory(0x000000010000003a); + SetupWiiMemory(volume, 0x000000010000003a); dolLoader.Load(); PC = dolLoader.GetEntryPoint(); @@ -365,16 +375,19 @@ bool CBoot::BootUp() case SConfig::BOOT_ELF: { + const DiscIO::IVolume* volume = nullptr; + // load image or create virtual drive from directory if (!_StartupPara.m_strDVDRoot.empty()) { NOTICE_LOG(BOOT, "Setting DVDRoot %s", _StartupPara.m_strDVDRoot.c_str()); - DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, _StartupPara.bWii); + volume = + SetDisc(DiscIO::CreateVolumeFromDirectory(_StartupPara.m_strDVDRoot, _StartupPara.bWii)); } else if (!_StartupPara.m_strDefaultISO.empty()) { NOTICE_LOG(BOOT, "Loading default ISO %s", _StartupPara.m_strDefaultISO.c_str()); - DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); + volume = SetDisc(DiscIO::CreateVolumeFromFilename(_StartupPara.m_strDefaultISO)); } // Poor man's bootup @@ -382,14 +395,14 @@ bool CBoot::BootUp() { // Because there is no TMD to get the requested system (IOS) version from, // we default to IOS58, which is the version used by the Homebrew Channel. - SetupWiiMemory(0x000000010000003a); + SetupWiiMemory(volume, 0x000000010000003a); } else { - EmulatedBS2_GC(true); + EmulatedBS2_GC(volume, true); } - Load_FST(_StartupPara.bWii); + Load_FST(_StartupPara.bWii, volume); if (!Boot_ELF(_StartupPara.m_strFilename)) return false; @@ -411,9 +424,9 @@ bool CBoot::BootUp() // load default image or create virtual drive from directory if (!_StartupPara.m_strDVDRoot.empty()) - DVDInterface::SetVolumeDirectory(_StartupPara.m_strDVDRoot, true); + SetDisc(DiscIO::CreateVolumeFromDirectory(_StartupPara.m_strDVDRoot, true)); else if (!_StartupPara.m_strDefaultISO.empty()) - DVDInterface::SetVolumeName(_StartupPara.m_strDefaultISO); + SetDisc(DiscIO::CreateVolumeFromFilename(_StartupPara.m_strDefaultISO)); break; diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 6a88335c25..22af0f5773 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -9,6 +9,11 @@ #include "Common/CommonTypes.h" +namespace DiscIO +{ +class IVolume; +} + struct RegionSetting { const std::string area; @@ -40,7 +45,8 @@ public: static bool LoadMapFromFilename(); private: - static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt); + static bool DVDRead(const DiscIO::IVolume& volume, u64 dvd_offset, u32 output_address, u32 length, + bool decrypt); static void RunFunction(u32 address); static void UpdateDebugger_MapLoaded(); @@ -49,12 +55,12 @@ private: static bool Boot_WiiWAD(const std::string& filename); static void SetupBAT(bool is_wii); - static bool RunApploader(bool is_wii); - static bool EmulatedBS2_GC(bool skip_app_loader = false); - static bool EmulatedBS2_Wii(); - static bool EmulatedBS2(bool is_wii); + static bool RunApploader(bool is_wii, const DiscIO::IVolume& volume); + static bool EmulatedBS2_GC(const DiscIO::IVolume* volume, bool skip_app_loader = false); + static bool EmulatedBS2_Wii(const DiscIO::IVolume* volume); + static bool EmulatedBS2(bool is_wii, const DiscIO::IVolume* volume); static bool Load_BS2(const std::string& boot_rom_filename); - static void Load_FST(bool is_wii); + static void Load_FST(bool is_wii, const DiscIO::IVolume* volume); - static bool SetupWiiMemory(u64 ios_title_id); + static bool SetupWiiMemory(const DiscIO::IVolume* volume, u64 ios_title_id); }; diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index a956e7290b..ad662cf7f3 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -18,7 +18,6 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HLE/HLE.h" -#include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/EXI/EXI_DeviceIPL.h" #include "Core/HW/Memmap.h" #include "Core/IOS/ES/ES.h" @@ -78,11 +77,10 @@ void CBoot::SetupBAT(bool is_wii) PowerPC::IBATUpdated(); } -bool CBoot::RunApploader(bool is_wii) +bool CBoot::RunApploader(bool is_wii, const DiscIO::IVolume& volume) { // Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc, // but the size can differ between discs. Compare with YAGCD chap 13. - const DiscIO::IVolume& volume = DVDInterface::GetVolume(); const u32 apploader_offset = 0x2440; u32 apploader_entry = 0; u32 apploader_size = 0; @@ -95,7 +93,7 @@ bool CBoot::RunApploader(bool is_wii) INFO_LOG(BOOT, "Invalid apploader. Your disc image is probably corrupted."); return false; } - DVDRead(apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer, is_wii); + DVDRead(volume, apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer, is_wii); // TODO - Make Apploader(or just RunFunction()) debuggable!!! @@ -134,7 +132,7 @@ bool CBoot::RunApploader(bool is_wii) INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength); - DVDRead(iDVDOffset, iRamAddress, iLength, is_wii); + DVDRead(volume, iDVDOffset, iRamAddress, iLength, is_wii); } while (PowerPC::ppcState.gpr[3] != 0x00); @@ -153,7 +151,7 @@ bool CBoot::RunApploader(bool is_wii) // GameCube Bootstrap 2 HLE: // copy the apploader to 0x81200000 // execute the apploader, function by function, using the above utility. -bool CBoot::EmulatedBS2_GC(bool skip_app_loader) +bool CBoot::EmulatedBS2_GC(const DiscIO::IVolume* volume, bool skip_app_loader) { INFO_LOG(BOOT, "Faking GC BS2..."); @@ -164,8 +162,8 @@ bool CBoot::EmulatedBS2_GC(bool skip_app_loader) // to 0x80000000 according to YAGCD 4.2. // It's possible to boot DOL and ELF files without a disc inserted - if (DVDInterface::IsDiscInside()) - DVDRead(/*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, false); // write disc info + if (volume) + DVDRead(*volume, /*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, false); // Booted from bootrom. 0xE5207C22 = booted from jtag PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020); @@ -196,7 +194,7 @@ bool CBoot::EmulatedBS2_GC(bool skip_app_loader) // HIO checks this // PowerPC::HostWrite_U16(0x8200, 0x000030e6); // Console type - if (!DVDInterface::IsDiscInside()) + if (!volume) return false; // Setup pointers like real BS2 does @@ -211,10 +209,10 @@ bool CBoot::EmulatedBS2_GC(bool skip_app_loader) if (skip_app_loader) return false; - return RunApploader(/*is_wii*/ false); + return RunApploader(/*is_wii*/ false, *volume); } -bool CBoot::SetupWiiMemory(u64 ios_title_id) +bool CBoot::SetupWiiMemory(const DiscIO::IVolume* volume, u64 ios_title_id) { static const std::map region_settings = { {DiscIO::Region::NTSC_J, {"JPN", "NTSC", "JP", "LJ"}}, @@ -281,8 +279,8 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id) */ // When booting a WAD or the system menu, there will probably not be a disc inserted - if (DVDInterface::IsDiscInside()) - DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code + if (volume) + DVDRead(*volume, 0x00000000, 0x00000000, 0x20, false); // Game Code Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word Memory::Write_U32(0x00000001, 0x00000024); // Unknown @@ -328,25 +326,25 @@ bool CBoot::SetupWiiMemory(u64 ios_title_id) // Wii Bootstrap 2 HLE: // copy the apploader to 0x81200000 // execute the apploader -bool CBoot::EmulatedBS2_Wii() +bool CBoot::EmulatedBS2_Wii(const DiscIO::IVolume* volume) { INFO_LOG(BOOT, "Faking Wii BS2..."); - if (!DVDInterface::IsDiscInside()) + if (!volume) return false; - if (DVDInterface::GetVolume().GetVolumeType() != DiscIO::Platform::WII_DISC) + if (volume->GetVolumeType() != DiscIO::Platform::WII_DISC) return false; - const IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD(); + const IOS::ES::TMDReader tmd = volume->GetTMD(); - if (!SetupWiiMemory(tmd.GetIOSId())) + if (!SetupWiiMemory(volume, tmd.GetIOSId())) return false; // This is some kind of consistency check that is compared to the 0x00 // values as the game boots. This location keeps the 4 byte ID for as long // as the game is running. The 6 byte ID at 0x00 is overwritten sometime // after this check during booting. - DVDRead(0, 0x3180, 4, true); + DVDRead(*volume, 0, 0x3180, 4, true); SetupBAT(/*is_wii*/ true); @@ -356,16 +354,20 @@ bool CBoot::EmulatedBS2_Wii() PowerPC::ppcState.gpr[1] = 0x816ffff0; // StackPointer - if (!RunApploader(/*is_wii*/ true)) + if (!RunApploader(/*is_wii*/ true, *volume)) return false; - IOS::HLE::Device::ES::DIVerify(tmd, DVDInterface::GetVolume().GetTicket()); + // Warning: This call will set incorrect running game metadata if our volume parameter + // doesn't point to the same disc as the one that's inserted in the emulated disc drive! + IOS::HLE::Device::ES::DIVerify(tmd, volume->GetTicket()); return true; } -// Returns true if apploader has run successfully -bool CBoot::EmulatedBS2(bool is_wii) +// Returns true if apploader has run successfully. +// If is_wii is true and volume is not nullptr, the disc that volume +// point to must currently be inserted into the emulated disc drive. +bool CBoot::EmulatedBS2(bool is_wii, const DiscIO::IVolume* volume) { - return is_wii ? EmulatedBS2_Wii() : EmulatedBS2_GC(); + return is_wii ? EmulatedBS2_Wii(volume) : EmulatedBS2_GC(volume); } diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp index f9e7354f55..b05e848fa2 100644 --- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp @@ -85,7 +85,7 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename) IOS::HLE::CreateVirtualFATFilesystem(); // setup Wii memory - if (!SetupWiiMemory(ContentLoader.GetTMD().GetIOSId())) + if (!SetupWiiMemory(nullptr, ContentLoader.GetTMD().GetIOSId())) return false; IOS::HLE::Device::ES::LoadWAD(_pFilename); diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index b85550c57a..b4fd424d5a 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -761,20 +761,11 @@ void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd) // the disc header instead of the TMD. They can differ. // (IOS HLE ES calls us with a TMDReader rather than a volume when launching // a disc game, because ES has no reason to be accessing the disc directly.) - if (DVDInterface::IsDiscInside()) + if (!DVDThread::UpdateRunningGameMetadata(tmd_title_id)) { - DVDThread::WaitUntilIdle(); - const DiscIO::IVolume& volume = DVDInterface::GetVolume(); - u64 volume_title_id; - if (volume.GetTitleID(&volume_title_id) && volume_title_id == tmd_title_id) - { - SetRunningGameMetadata(volume.GetGameID(), volume_title_id, volume.GetRevision()); - return; - } + // If not launching a disc game, just read everything from the TMD. + SetRunningGameMetadata(tmd.GetGameID(), tmd_title_id, tmd.GetTitleVersion()); } - - // If not launching a disc game, just read everything from the TMD. - SetRunningGameMetadata(tmd.GetGameID(), tmd_title_id, tmd.GetTitleVersion()); } void SConfig::SetRunningGameMetadata(const std::string& game_id, u64 title_id, u16 revision) diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index 404b855f16..11812f6f54 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -21,7 +21,6 @@ #include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/DVD/DVDMath.h" #include "Core/HW/DVD/DVDThread.h" -#include "Core/HW/DVD/FileMonitor.h" #include "Core/HW/MMIO.h" #include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" @@ -195,8 +194,6 @@ union UDICFG UDICFG(u32 _hex) { Hex = _hex; } }; -static std::unique_ptr s_inserted_volume; - // STATE_TO_SAVE // Hardware registers @@ -255,8 +252,6 @@ void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, Rep void DoState(PointerWrap& p) { - bool disc_inside = IsDiscInside(); - p.DoPOD(s_DISR); p.DoPOD(s_DICVR); p.DoArray(s_DICMDBUF); @@ -276,7 +271,6 @@ void DoState(PointerWrap& p) p.Do(s_pending_samples); p.Do(s_error_code); - p.Do(disc_inside); p.Do(s_read_buffer_start_time); p.Do(s_read_buffer_end_time); @@ -286,24 +280,6 @@ void DoState(PointerWrap& p) p.Do(s_disc_path_to_insert); DVDThread::DoState(p); - - // s_inserted_volume isn't savestated (because it points to - // files on the local system). Instead, we check that the - // savestated disc_inside matches our IsDiscInside(). This - // won't catch cases of having the wrong disc inserted, though. - // TODO: Check the game ID, disc number, revision? - if (disc_inside != IsDiscInside()) - { - if (disc_inside) - { - PanicAlertT("An inserted disc was expected but not found."); - } - else - { - s_inserted_volume.reset(); - FileMonitor::SetFileSystem(nullptr); - } - } } static size_t ProcessDTKSamples(std::vector* temp_pcm, const std::vector& audio_data) @@ -452,39 +428,17 @@ void Reset() void Shutdown() { DVDThread::Stop(); - s_inserted_volume.reset(); - FileMonitor::SetFileSystem(nullptr); } -const DiscIO::IVolume& GetVolume() +void SetDisc(std::unique_ptr disc) { - _assert_(IsDiscInside()); - return *s_inserted_volume; -} - -bool SetVolumeName(const std::string& disc_path) -{ - DVDThread::WaitUntilIdle(); - s_inserted_volume = DiscIO::CreateVolumeFromFilename(disc_path); - FileMonitor::SetFileSystem(s_inserted_volume.get()); + DVDThread::SetDisc(std::move(disc)); SetLidOpen(); - return IsDiscInside(); -} - -bool SetVolumeDirectory(const std::string& full_path, bool is_wii, - const std::string& apploader_path, const std::string& DOL_path) -{ - DVDThread::WaitUntilIdle(); - s_inserted_volume = - DiscIO::CreateVolumeFromDirectory(full_path, is_wii, apploader_path, DOL_path); - FileMonitor::SetFileSystem(s_inserted_volume.get()); - SetLidOpen(); - return IsDiscInside(); } bool IsDiscInside() { - return s_inserted_volume != nullptr; + return DVDThread::HasDisc(); } // Take care of all logic of "swapping discs" @@ -493,24 +447,18 @@ bool IsDiscInside() // that the userdata string exists when called static void EjectDiscCallback(u64 userdata, s64 cyclesLate) { - DVDThread::WaitUntilIdle(); - s_inserted_volume.reset(); - FileMonitor::SetFileSystem(s_inserted_volume.get()); - SetLidOpen(); + SetDisc(nullptr); } static void InsertDiscCallback(u64 userdata, s64 cyclesLate) { - const std::string& old_path = SConfig::GetInstance().m_strFilename; + std::unique_ptr new_volume = + DiscIO::CreateVolumeFromFilename(s_disc_path_to_insert); - if (!SetVolumeName(s_disc_path_to_insert)) - { - // Put back the old one - SetVolumeName(old_path); + if (new_volume) + SetDisc(std::move(new_volume)); + else PanicAlertT("The disc that was about to be inserted couldn't be found."); - } - - s_disc_path_to_insert.clear(); } // Can only be called by the host thread @@ -550,10 +498,7 @@ void SetLidOpen() bool ChangePartition(u64 offset) { - DVDThread::WaitUntilIdle(); - const bool success = s_inserted_volume->ChangePartition(offset); - FileMonitor::SetFileSystem(s_inserted_volume.get()); - return success; + return DVDThread::ChangePartition(offset); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) @@ -1165,7 +1110,7 @@ void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, Rep const u64 current_time = CoreTiming::GetTicks(); const u32 ticks_per_second = SystemTimers::GetTicksPerSecond(); - const bool wii_disc = s_inserted_volume->GetVolumeType() == DiscIO::Platform::WII_DISC; + const bool wii_disc = DVDThread::GetDiscType() == DiscIO::Platform::WII_DISC; // Where the DVD read head is (usually parked at the end of the buffer, // unless we've interrupted it mid-buffer-read). @@ -1181,7 +1126,7 @@ void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, Rep // It's rounded to a whole ECC block and never uses Wii partition addressing. u64 dvd_offset = offset; if (decrypt) - dvd_offset = s_inserted_volume->PartitionOffsetToRawOffset(offset); + dvd_offset = DVDThread::PartitionOffsetToRawOffset(offset); dvd_offset = Common::AlignDown(dvd_offset, DVD_ECC_BLOCK_SIZE); if (SConfig::GetInstance().bFastDiscSpeed) diff --git a/Source/Core/Core/HW/DVD/DVDInterface.h b/Source/Core/Core/HW/DVD/DVDInterface.h index 64c4bc1efb..977e92c9fd 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.h +++ b/Source/Core/Core/HW/DVD/DVDInterface.h @@ -108,11 +108,7 @@ void DoState(PointerWrap& p); void RegisterMMIO(MMIO::Mapping* mmio, u32 base); -// Disc access (don't call GetVolume unless you know that IsDiscInside() == true) -const DiscIO::IVolume& GetVolume(); -bool SetVolumeName(const std::string& disc_path); -bool SetVolumeDirectory(const std::string& disc_path, bool is_wii, - const std::string& apploader_path = "", const std::string& DOL_path = ""); +void SetDisc(std::unique_ptr disc); bool IsDiscInside(); void ChangeDiscAsHost(const std::string& new_path); // Can only be called by the host thread void ChangeDiscAsCPU(const std::string& new_path); // Can only be called by the CPU thread diff --git a/Source/Core/Core/HW/DVD/DVDThread.cpp b/Source/Core/Core/HW/DVD/DVDThread.cpp index 8bd0ccf5cd..3040c56a8c 100644 --- a/Source/Core/Core/HW/DVD/DVDThread.cpp +++ b/Source/Core/Core/HW/DVD/DVDThread.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include "Common/Thread.h" #include "Common/Timer.h" +#include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/HW/DVD/DVDInterface.h" @@ -26,7 +28,9 @@ #include "Core/HW/DVD/FileMonitor.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/IOS/ES/Formats.h" +#include "DiscIO/Enums.h" #include "DiscIO/Volume.h" namespace DVDThread @@ -61,6 +65,7 @@ static void StartDVDThread(); static void StopDVDThread(); static void DVDThread(); +static void WaitUntilIdle(); static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length, bool decrypt, DVDInterface::ReplyType reply_type, @@ -80,6 +85,8 @@ static Common::FifoQueue s_request_queue; static Common::FifoQueue s_result_queue; static std::map s_result_map; +static std::unique_ptr s_disc; + void Start() { s_finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead); @@ -106,6 +113,8 @@ static void StartDVDThread() void Stop() { StopDVDThread(); + s_disc.reset(); + FileMonitor::SetFileSystem(nullptr); } static void StopDVDThread() @@ -123,24 +132,42 @@ static void StopDVDThread() void DoState(PointerWrap& p) { - // By waiting for the DVD thread to be done working, we ensure that - // there are no pending requests. The DVD thread won't be touching - // s_result_queue, and everything we need to save will be in either - // s_result_queue or s_result_map (other than s_next_id). + // By waiting for the DVD thread to be done working, we ensure + // that s_request_queue will be empty and that the DVD thread + // won't be touching anything while this function runs. WaitUntilIdle(); - // Move everything from s_result_queue to s_result_map because + // Move all results from s_result_queue to s_result_map because // PointerWrap::Do supports std::map but not Common::FifoQueue. // This won't affect the behavior of FinishRead. ReadResult result; while (s_result_queue.Pop(result)) s_result_map.emplace(result.first.id, std::move(result)); - // Everything is now in s_result_map, so we simply savestate that. - // We also savestate s_next_id to avoid ID collisions. + // Both queues are now empty, so we don't need to savestate them. p.Do(s_result_map); p.Do(s_next_id); + // s_disc isn't savestated (because it points to files on the + // local system). Instead, we check that the status of the disc + // is the same as when the savestate was made. This won't catch + // cases of having the wrong disc inserted, though. + // TODO: Check the game ID, disc number, revision? + bool had_disc = HasDisc(); + p.Do(had_disc); + if (had_disc != HasDisc()) + { + if (had_disc) + { + PanicAlertT("An inserted disc was expected but not found."); + } + else + { + s_disc.reset(); + FileMonitor::SetFileSystem(nullptr); + } + } + // TODO: Savestates can be smaller if the buffers of results aren't saved, // but instead get re-read from the disc when loading the savestate. @@ -152,6 +179,82 @@ void DoState(PointerWrap& p) // was made. Handling that properly may be more effort than it's worth. } +void SetDisc(std::unique_ptr disc) +{ + WaitUntilIdle(); + s_disc = std::move(disc); + FileMonitor::SetFileSystem(s_disc.get()); +} + +bool HasDisc() +{ + return s_disc != nullptr; +} + +u64 PartitionOffsetToRawOffset(u64 offset) +{ + // This is thread-safe as long as the partition currently isn't being changed, + // and that isn't supposed to be happening while running this function, because both + // this function and ChangePartition are only supposed to be called on the CPU thread. + _assert_(Core::IsCPUThread()); + return s_disc->PartitionOffsetToRawOffset(offset); +} + +DiscIO::Platform GetDiscType() +{ + // GetVolumeType is thread-safe, so calling WaitUntilIdle isn't necessary. + return s_disc->GetVolumeType(); +} + +IOS::ES::TMDReader GetTMD() +{ + WaitUntilIdle(); + return s_disc->GetTMD(); +} + +IOS::ES::TicketReader GetTicket() +{ + WaitUntilIdle(); + return s_disc->GetTicket(); +} + +bool ChangePartition(u64 offset) +{ + WaitUntilIdle(); + const bool success = s_disc->ChangePartition(offset); + FileMonitor::SetFileSystem(s_disc.get()); + return success; +} + +bool UpdateRunningGameMetadata(u64 title_id) +{ + if (!s_disc) + return false; + + WaitUntilIdle(); + + u64 volume_title_id; + if (!s_disc->GetTitleID(&volume_title_id)) + return false; + + if (volume_title_id != title_id) + return false; + + SConfig::GetInstance().SetRunningGameMetadata(*s_disc); + return true; +} + +bool UpdateRunningGameMetadata() +{ + if (!s_disc) + return false; + + DVDThread::WaitUntilIdle(); + + SConfig::GetInstance().SetRunningGameMetadata(*s_disc); + return true; +} + void WaitUntilIdle() { _assert_(Core::IsCPUThread()); @@ -281,8 +384,7 @@ static void DVDThread() FileMonitor::Log(request.dvd_offset, request.decrypt); std::vector buffer(request.length); - const DiscIO::IVolume& volume = DVDInterface::GetVolume(); - if (!volume.Read(request.dvd_offset, request.length, buffer.data(), request.decrypt)) + if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.decrypt)) buffer.resize(0); request.realtime_done_us = Common::Timer::GetTimeUs(); diff --git a/Source/Core/Core/HW/DVD/DVDThread.h b/Source/Core/Core/HW/DVD/DVDThread.h index c67a236d69..d7867d54bb 100644 --- a/Source/Core/Core/HW/DVD/DVDThread.h +++ b/Source/Core/Core/HW/DVD/DVDThread.h @@ -4,6 +4,9 @@ #pragma once +#include +#include + #include "Common/CommonTypes.h" class PointerWrap; @@ -11,6 +14,19 @@ namespace DVDInterface { enum class ReplyType : u32; } +namespace DiscIO +{ +enum class Platform; +class IVolume; +} +namespace IOS +{ +namespace ES +{ +class TMDReader; +class TicketReader; +} +} namespace DVDThread { @@ -18,7 +34,21 @@ void Start(); void Stop(); void DoState(PointerWrap& p); -void WaitUntilIdle(); +void SetDisc(std::unique_ptr disc); +bool HasDisc(); + +u64 PartitionOffsetToRawOffset(u64 offset); +DiscIO::Platform GetDiscType(); +IOS::ES::TMDReader GetTMD(); +IOS::ES::TicketReader GetTicket(); +bool ChangePartition(u64 offset); +// If a disc is inserted and its title ID is equal to the title_id argument, returns true and +// calls SConfig::SetRunningGameMetadata(IVolume&). Otherwise, returns false. +bool UpdateRunningGameMetadata(u64 title_id); +// If a disc is inserted, returns true and calls +// SConfig::SetRunningGameMetadata(IVolume&). Otherwise, returns false. +bool UpdateRunningGameMetadata(); + void StartRead(u64 dvd_offset, u32 length, bool decrypt, DVDInterface::ReplyType reply_type, s64 ticks_until_completion); void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length, bool decrypt, diff --git a/Source/Core/Core/IOS/DI/DI.cpp b/Source/Core/Core/IOS/DI/DI.cpp index 593914bcc2..7e1878a1fc 100644 --- a/Source/Core/Core/IOS/DI/DI.cpp +++ b/Source/Core/Core/IOS/DI/DI.cpp @@ -12,6 +12,7 @@ #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Core/HW/DVD/DVDInterface.h" +#include "Core/HW/DVD/DVDThread.h" #include "Core/HW/Memmap.h" #include "Core/IOS/DI/DI.h" #include "Core/IOS/ES/ES.h" @@ -106,10 +107,10 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request) INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset); // Read TMD to the buffer - const IOS::ES::TMDReader tmd = DVDInterface::GetVolume().GetTMD(); + const IOS::ES::TMDReader tmd = DVDThread::GetTMD(); const std::vector raw_tmd = tmd.GetRawTMD(); Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size()); - ES::DIVerify(tmd, DVDInterface::GetVolume().GetTicket()); + ES::DIVerify(tmd, DVDThread::GetTicket()); return_value = 1; break; diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp index aad859a0ef..7242dceb78 100644 --- a/Source/Core/Core/IOS/MIOS.cpp +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -120,13 +120,6 @@ static void ReinitHardware() SystemTimers::ChangePPCClock(SystemTimers::Mode::GC); } -static void UpdateRunningGame() -{ - DVDThread::WaitUntilIdle(); - SConfig::GetInstance().m_BootType = SConfig::BOOT_MIOS; - SConfig::GetInstance().SetRunningGameMetadata(DVDInterface::GetVolume()); -} - constexpr u32 ADDRESS_INIT_SEMAPHORE = 0x30f8; bool Load() @@ -176,7 +169,8 @@ bool Load() Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); NOTICE_LOG(IOS, "IPL ready."); - UpdateRunningGame(); + SConfig::GetInstance().m_BootType = SConfig::BOOT_MIOS; + DVDThread::UpdateRunningGameMetadata(); return true; } } // namespace MIOS diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 064f959223..fd24cd8092 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 84; // Last changed in PR 5354 +static const u32 STATE_VERSION = 85; // Last changed in PR 4241 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list,