diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 77fb61170e..a85a939e79 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -22,6 +22,7 @@ #include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/EXI/EXI_DeviceIPL.h" #include "Core/HW/Memmap.h" +#include "Core/IOS/DI/DI.h" #include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/Formats.h" #include "Core/IOS/FS/FileSystem.h" @@ -421,6 +422,12 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume) if (!SetupWiiMemory(console_type) || !IOS::HLE::GetIOS()->BootIOS(tmd.GetIOSId())) return false; + auto di = std::static_pointer_cast( + IOS::HLE::GetIOS()->GetDeviceByName("/dev/di")); + + di->InitializeIfFirstTime(); + di->ChangePartition(data_partition); + DVDReadDiscID(volume, 0x00000000); // This is some kind of consistency check that is compared to the 0x00 diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index ad45814fee..0e4fdc5b5f 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -161,7 +161,6 @@ static u8 s_dtk_buffer_length = 0; // TODO: figure out how this affects the reg // Disc drive state static u32 s_error_code = 0; -static DiscIO::Partition s_current_partition; // Disc drive timing static u64 s_read_buffer_start_time; @@ -223,7 +222,6 @@ void DoState(PointerWrap& p) p.Do(s_dtk_buffer_length); p.Do(s_error_code); - p.Do(s_current_partition); p.Do(s_read_buffer_start_time); p.Do(s_read_buffer_end_time); @@ -426,8 +424,6 @@ void SetDisc(std::unique_ptr disc, { bool had_disc = IsDiscInside(); bool has_disc = static_cast(disc); - if (has_disc) - s_current_partition = disc->GetGamePartition(); if (auto_disc_change_paths) { @@ -548,12 +544,8 @@ bool UpdateRunningGameMetadata(std::optional title_id) if (!DVDThread::HasDisc()) return false; - return DVDThread::UpdateRunningGameMetadata(s_current_partition, title_id); -} - -void ChangePartition(const DiscIO::Partition& partition) -{ - s_current_partition = partition; + return DVDThread::UpdateRunningGameMetadata(IOS::HLE::Device::DI::GetCurrentPartition(), + title_id); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) @@ -1125,14 +1117,15 @@ void ExecuteCommand(ReplyType reply_type) } } -void PerformDecryptingRead(u32 position, u32 length, u32 output_address, ReplyType reply_type) +void PerformDecryptingRead(u32 position, u32 length, u32 output_address, + const DiscIO::Partition& partition, ReplyType reply_type) { DIInterruptType interrupt_type = DIInterruptType::TCINT; s_can_configure_dtk = false; const bool command_handled_by_thread = - ExecuteReadCommand(static_cast(position) << 2, output_address, length, length, - s_current_partition, reply_type, &interrupt_type); + ExecuteReadCommand(static_cast(position) << 2, output_address, length, length, partition, + reply_type, &interrupt_type); if (!command_handled_by_thread) { diff --git a/Source/Core/Core/HW/DVD/DVDInterface.h b/Source/Core/Core/HW/DVD/DVDInterface.h index 0242c29b29..c0bd1bd4d0 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.h +++ b/Source/Core/Core/HW/DVD/DVDInterface.h @@ -124,9 +124,9 @@ bool UpdateRunningGameMetadata(std::optional title_id = {}); // Direct access to DI for IOS HLE (simpler to implement than how real IOS accesses DI, // and lets us skip encrypting/decrypting in some cases) -void ChangePartition(const DiscIO::Partition& partition); void ExecuteCommand(ReplyType reply_type); -void PerformDecryptingRead(u32 position, u32 length, u32 output_address, ReplyType reply_type); +void PerformDecryptingRead(u32 position, u32 length, u32 output_address, + const DiscIO::Partition& partition, ReplyType reply_type); // Exposed for use by emulated BS2; does not perform any checks on drive state void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length); diff --git a/Source/Core/Core/IOS/DI/DI.cpp b/Source/Core/Core/IOS/DI/DI.cpp index 70a6038a47..7dc2f714e4 100644 --- a/Source/Core/Core/IOS/DI/DI.cpp +++ b/Source/Core/Core/IOS/DI/DI.cpp @@ -52,6 +52,7 @@ void DI::DoState(PointerWrap& p) DoStateShared(p); p.Do(m_commands_to_execute); p.Do(m_executing_command); + p.Do(m_current_partition); p.Do(m_has_initialized); p.Do(m_last_length); } @@ -162,11 +163,15 @@ std::optional DI::StartIOCtl(const IOCtlRequest& request) // } case DIIoctl::DVDLowRead: { - // TODO. Needs to include decryption. const u32 length = Memory::Read_U32(request.buffer_in + 4); const u32 position = Memory::Read_U32(request.buffer_in + 8); INFO_LOG(IOS_DI, "DVDLowRead: offset 0x%08x (byte 0x%09" PRIx64 "), length 0x%x", position, static_cast(position) << 2, length); + if (m_current_partition == DiscIO::PARTITION_NONE) + { + ERROR_LOG(IOS_DI, "Attempted to perform a decrypting read when no partition is open!"); + return DIResult::SecurityError; + } if (request.buffer_out_size < length) { WARN_LOG(IOS_DI, @@ -176,7 +181,7 @@ std::optional DI::StartIOCtl(const IOCtlRequest& request) return DIResult::SecurityError; } m_last_length = position; // An actual mistake in IOS - DVDInterface::PerformDecryptingRead(position, length, request.buffer_out, + DVDInterface::PerformDecryptingRead(position, length, request.buffer_out, m_current_partition, DVDInterface::ReplyType::IOS); return {}; } @@ -194,7 +199,6 @@ std::optional DI::StartIOCtl(const IOCtlRequest& request) case DIIoctl::DVDLowNotifyReset: INFO_LOG(IOS_DI, "DVDLowNotifyReset"); ResetDIRegisters(); - // Should also reset current partition and such return DIResult::Success; case DIIoctl::DVDLowSetSpinupFlag: ERROR_LOG(IOS_DI, "DVDLowSetSpinupFlag - not a valid command, rejecting"); @@ -258,7 +262,6 @@ std::optional DI::StartIOCtl(const IOCtlRequest& request) INFO_LOG(IOS_DI, "DVDLowReset %s spinup", spinup ? "with" : "without"); DVDInterface::Reset(spinup); ResetDIRegisters(); - // Should also reset current partition and such return DIResult::Success; } case DIIoctl::DVDLowOpenPartition: @@ -266,7 +269,7 @@ std::optional DI::StartIOCtl(const IOCtlRequest& request) return DIResult::SecurityError; case DIIoctl::DVDLowClosePartition: INFO_LOG(IOS_DI, "DVDLowClosePartition"); - DVDInterface::ChangePartition(DiscIO::PARTITION_NONE); + ChangePartition(DiscIO::PARTITION_NONE); return DIResult::Success; case DIIoctl::DVDLowUnencryptedRead: { @@ -614,23 +617,29 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request) request.in_vectors.size(), request.io_vectors.size()); break; } - DEBUG_ASSERT_MSG(IOS_DI, request.in_vectors[1].address == 0, "DVDLowOpenPartition with ticket"); - DEBUG_ASSERT_MSG(IOS_DI, request.in_vectors[2].address == 0, - "DVDLowOpenPartition with cert chain"); + if (request.in_vectors[1].address != 0) + { + ERROR_LOG(IOS_DI, + "DVDLowOpenPartition with ticket - not implemented, ignoring ticket parameter"); + } + if (request.in_vectors[2].address != 0) + { + ERROR_LOG(IOS_DI, + "DVDLowOpenPartition with cert chain - not implemented, ignoring certs parameter"); + } const u64 partition_offset = static_cast(Memory::Read_U32(request.in_vectors[0].address + 4)) << 2; - const DiscIO::Partition partition(partition_offset); - DVDInterface::ChangePartition(partition); + ChangePartition(DiscIO::Partition(partition_offset)); INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%09" PRIx64, partition_offset); // Read TMD to the buffer - const IOS::ES::TMDReader tmd = DVDThread::GetTMD(partition); + const IOS::ES::TMDReader tmd = DVDThread::GetTMD(m_current_partition); const std::vector& raw_tmd = tmd.GetBytes(); Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size()); - ReturnCode es_result = m_ios.GetES()->DIVerify(tmd, DVDThread::GetTicket(partition)); + ReturnCode es_result = m_ios.GetES()->DIVerify(tmd, DVDThread::GetTicket(m_current_partition)); Memory::Write_U32(es_result, request.io_vectors[1].address); return_value = DIResult::Success; @@ -661,6 +670,21 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request) return GetDefaultReply(static_cast(return_value)); } +void DI::ChangePartition(const DiscIO::Partition partition) +{ + m_current_partition = partition; +} + +DiscIO::Partition DI::GetCurrentPartition() +{ + auto di = IOS::HLE::GetIOS()->GetDeviceByName("/dev/di"); + // Note that this function is called in Gamecube mode for UpdateRunningGameMetadata, + // so both cases are hit in normal circumstances. + if (!di) + return DiscIO::PARTITION_NONE; + return std::static_pointer_cast(di)->m_current_partition; +} + void DI::InitializeIfFirstTime() { // Match the behavior of Nintendo's initDvdDriverStage2, which is called the first time @@ -687,5 +711,7 @@ void DI::ResetDIRegisters() DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::TCINT, true); DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::DEINT, true); DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false); + // Close the current partition, if there is one + ChangePartition(DiscIO::PARTITION_NONE); } } // namespace IOS::HLE::Device diff --git a/Source/Core/Core/IOS/DI/DI.h b/Source/Core/Core/IOS/DI/DI.h index f52980f3ad..975b0adc51 100644 --- a/Source/Core/Core/IOS/DI/DI.h +++ b/Source/Core/Core/IOS/DI/DI.h @@ -11,7 +11,9 @@ #include "Common/CommonTypes.h" #include "Core/IOS/Device.h" #include "Core/IOS/IOS.h" +#include "DiscIO/Volume.h" +class CBoot; class PointerWrap; namespace DVDInterface @@ -36,6 +38,7 @@ public: DI(Kernel& ios, const std::string& device_name); static void InterruptFromDVDInterface(DVDInterface::DIInterruptType interrupt_type); + static DiscIO::Partition GetCurrentPartition(); void DoState(PointerWrap& p) override; @@ -116,6 +119,7 @@ private: bool m_copy_diimmbuf; }; + friend class ::CBoot; friend void ::IOS::HLE::Init(); void ProcessQueuedIOCtl(); @@ -125,6 +129,7 @@ private: std::optional StartImmediateTransfer(const IOCtlRequest& request, bool write_to_buf = true); + void ChangePartition(const DiscIO::Partition partition); void InitializeIfFirstTime(); void ResetDIRegisters(); static void FinishDICommandCallback(u64 userdata, s64 ticksbehind); @@ -135,6 +140,8 @@ private: std::optional m_executing_command; std::deque m_commands_to_execute; + DiscIO::Partition m_current_partition = DiscIO::PARTITION_NONE; + bool m_has_initialized = false; u32 m_last_length = 0; };