Handle partitions in /dev/di, not DVDInterface

Partitions are Wii-exclusive, and don't happen at the DVDInterface level in
IOS.  This isn't quite the cleanest fix, but it gets rid of the assumption that
a partition is open on starting the game at least.
This commit is contained in:
Pokechu22 2019-09-17 13:57:57 -07:00
parent 71e8fb278f
commit 6c0399103f
5 changed files with 60 additions and 27 deletions

View File

@ -22,6 +22,7 @@
#include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/DVD/DVDInterface.h"
#include "Core/HW/EXI/EXI_DeviceIPL.h" #include "Core/HW/EXI/EXI_DeviceIPL.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/IOS/DI/DI.h"
#include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/ES.h"
#include "Core/IOS/ES/Formats.h" #include "Core/IOS/ES/Formats.h"
#include "Core/IOS/FS/FileSystem.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())) if (!SetupWiiMemory(console_type) || !IOS::HLE::GetIOS()->BootIOS(tmd.GetIOSId()))
return false; return false;
auto di = std::static_pointer_cast<IOS::HLE::Device::DI>(
IOS::HLE::GetIOS()->GetDeviceByName("/dev/di"));
di->InitializeIfFirstTime();
di->ChangePartition(data_partition);
DVDReadDiscID(volume, 0x00000000); DVDReadDiscID(volume, 0x00000000);
// This is some kind of consistency check that is compared to the 0x00 // This is some kind of consistency check that is compared to the 0x00

View File

@ -161,7 +161,6 @@ static u8 s_dtk_buffer_length = 0; // TODO: figure out how this affects the reg
// Disc drive state // Disc drive state
static u32 s_error_code = 0; static u32 s_error_code = 0;
static DiscIO::Partition s_current_partition;
// Disc drive timing // Disc drive timing
static u64 s_read_buffer_start_time; static u64 s_read_buffer_start_time;
@ -223,7 +222,6 @@ void DoState(PointerWrap& p)
p.Do(s_dtk_buffer_length); p.Do(s_dtk_buffer_length);
p.Do(s_error_code); p.Do(s_error_code);
p.Do(s_current_partition);
p.Do(s_read_buffer_start_time); p.Do(s_read_buffer_start_time);
p.Do(s_read_buffer_end_time); p.Do(s_read_buffer_end_time);
@ -426,8 +424,6 @@ void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
{ {
bool had_disc = IsDiscInside(); bool had_disc = IsDiscInside();
bool has_disc = static_cast<bool>(disc); bool has_disc = static_cast<bool>(disc);
if (has_disc)
s_current_partition = disc->GetGamePartition();
if (auto_disc_change_paths) if (auto_disc_change_paths)
{ {
@ -548,12 +544,8 @@ bool UpdateRunningGameMetadata(std::optional<u64> title_id)
if (!DVDThread::HasDisc()) if (!DVDThread::HasDisc())
return false; return false;
return DVDThread::UpdateRunningGameMetadata(s_current_partition, title_id); return DVDThread::UpdateRunningGameMetadata(IOS::HLE::Device::DI::GetCurrentPartition(),
} title_id);
void ChangePartition(const DiscIO::Partition& partition)
{
s_current_partition = partition;
} }
void RegisterMMIO(MMIO::Mapping* mmio, u32 base) 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; DIInterruptType interrupt_type = DIInterruptType::TCINT;
s_can_configure_dtk = false; s_can_configure_dtk = false;
const bool command_handled_by_thread = const bool command_handled_by_thread =
ExecuteReadCommand(static_cast<u64>(position) << 2, output_address, length, length, ExecuteReadCommand(static_cast<u64>(position) << 2, output_address, length, length, partition,
s_current_partition, reply_type, &interrupt_type); reply_type, &interrupt_type);
if (!command_handled_by_thread) if (!command_handled_by_thread)
{ {

View File

@ -124,9 +124,9 @@ bool UpdateRunningGameMetadata(std::optional<u64> title_id = {});
// Direct access to DI for IOS HLE (simpler to implement than how real IOS accesses DI, // 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) // and lets us skip encrypting/decrypting in some cases)
void ChangePartition(const DiscIO::Partition& partition);
void ExecuteCommand(ReplyType reply_type); 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 // Exposed for use by emulated BS2; does not perform any checks on drive state
void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length); void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length);

View File

@ -52,6 +52,7 @@ void DI::DoState(PointerWrap& p)
DoStateShared(p); DoStateShared(p);
p.Do(m_commands_to_execute); p.Do(m_commands_to_execute);
p.Do(m_executing_command); p.Do(m_executing_command);
p.Do(m_current_partition);
p.Do(m_has_initialized); p.Do(m_has_initialized);
p.Do(m_last_length); p.Do(m_last_length);
} }
@ -162,11 +163,15 @@ std::optional<DI::DIResult> DI::StartIOCtl(const IOCtlRequest& request)
// } // }
case DIIoctl::DVDLowRead: case DIIoctl::DVDLowRead:
{ {
// TODO. Needs to include decryption.
const u32 length = Memory::Read_U32(request.buffer_in + 4); const u32 length = Memory::Read_U32(request.buffer_in + 4);
const u32 position = Memory::Read_U32(request.buffer_in + 8); 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, INFO_LOG(IOS_DI, "DVDLowRead: offset 0x%08x (byte 0x%09" PRIx64 "), length 0x%x", position,
static_cast<u64>(position) << 2, length); static_cast<u64>(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) if (request.buffer_out_size < length)
{ {
WARN_LOG(IOS_DI, WARN_LOG(IOS_DI,
@ -176,7 +181,7 @@ std::optional<DI::DIResult> DI::StartIOCtl(const IOCtlRequest& request)
return DIResult::SecurityError; return DIResult::SecurityError;
} }
m_last_length = position; // An actual mistake in IOS 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); DVDInterface::ReplyType::IOS);
return {}; return {};
} }
@ -194,7 +199,6 @@ std::optional<DI::DIResult> DI::StartIOCtl(const IOCtlRequest& request)
case DIIoctl::DVDLowNotifyReset: case DIIoctl::DVDLowNotifyReset:
INFO_LOG(IOS_DI, "DVDLowNotifyReset"); INFO_LOG(IOS_DI, "DVDLowNotifyReset");
ResetDIRegisters(); ResetDIRegisters();
// Should also reset current partition and such
return DIResult::Success; return DIResult::Success;
case DIIoctl::DVDLowSetSpinupFlag: case DIIoctl::DVDLowSetSpinupFlag:
ERROR_LOG(IOS_DI, "DVDLowSetSpinupFlag - not a valid command, rejecting"); ERROR_LOG(IOS_DI, "DVDLowSetSpinupFlag - not a valid command, rejecting");
@ -258,7 +262,6 @@ std::optional<DI::DIResult> DI::StartIOCtl(const IOCtlRequest& request)
INFO_LOG(IOS_DI, "DVDLowReset %s spinup", spinup ? "with" : "without"); INFO_LOG(IOS_DI, "DVDLowReset %s spinup", spinup ? "with" : "without");
DVDInterface::Reset(spinup); DVDInterface::Reset(spinup);
ResetDIRegisters(); ResetDIRegisters();
// Should also reset current partition and such
return DIResult::Success; return DIResult::Success;
} }
case DIIoctl::DVDLowOpenPartition: case DIIoctl::DVDLowOpenPartition:
@ -266,7 +269,7 @@ std::optional<DI::DIResult> DI::StartIOCtl(const IOCtlRequest& request)
return DIResult::SecurityError; return DIResult::SecurityError;
case DIIoctl::DVDLowClosePartition: case DIIoctl::DVDLowClosePartition:
INFO_LOG(IOS_DI, "DVDLowClosePartition"); INFO_LOG(IOS_DI, "DVDLowClosePartition");
DVDInterface::ChangePartition(DiscIO::PARTITION_NONE); ChangePartition(DiscIO::PARTITION_NONE);
return DIResult::Success; return DIResult::Success;
case DIIoctl::DVDLowUnencryptedRead: case DIIoctl::DVDLowUnencryptedRead:
{ {
@ -614,23 +617,29 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request)
request.in_vectors.size(), request.io_vectors.size()); request.in_vectors.size(), request.io_vectors.size());
break; break;
} }
DEBUG_ASSERT_MSG(IOS_DI, request.in_vectors[1].address == 0, "DVDLowOpenPartition with ticket"); if (request.in_vectors[1].address != 0)
DEBUG_ASSERT_MSG(IOS_DI, request.in_vectors[2].address == 0, {
"DVDLowOpenPartition with cert chain"); 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 = const u64 partition_offset =
static_cast<u64>(Memory::Read_U32(request.in_vectors[0].address + 4)) << 2; static_cast<u64>(Memory::Read_U32(request.in_vectors[0].address + 4)) << 2;
const DiscIO::Partition partition(partition_offset); ChangePartition(DiscIO::Partition(partition_offset));
DVDInterface::ChangePartition(partition);
INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%09" PRIx64, partition_offset); INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%09" PRIx64, partition_offset);
// Read TMD to the buffer // 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<u8>& raw_tmd = tmd.GetBytes(); const std::vector<u8>& raw_tmd = tmd.GetBytes();
Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size()); 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); Memory::Write_U32(es_result, request.io_vectors[1].address);
return_value = DIResult::Success; return_value = DIResult::Success;
@ -661,6 +670,21 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request)
return GetDefaultReply(static_cast<s32>(return_value)); return GetDefaultReply(static_cast<s32>(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>(di)->m_current_partition;
}
void DI::InitializeIfFirstTime() void DI::InitializeIfFirstTime()
{ {
// Match the behavior of Nintendo's initDvdDriverStage2, which is called the first time // 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::TCINT, true);
DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::DEINT, true); DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::DEINT, true);
DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false); DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false);
// Close the current partition, if there is one
ChangePartition(DiscIO::PARTITION_NONE);
} }
} // namespace IOS::HLE::Device } // namespace IOS::HLE::Device

View File

@ -11,7 +11,9 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Core/IOS/Device.h" #include "Core/IOS/Device.h"
#include "Core/IOS/IOS.h" #include "Core/IOS/IOS.h"
#include "DiscIO/Volume.h"
class CBoot;
class PointerWrap; class PointerWrap;
namespace DVDInterface namespace DVDInterface
@ -36,6 +38,7 @@ public:
DI(Kernel& ios, const std::string& device_name); DI(Kernel& ios, const std::string& device_name);
static void InterruptFromDVDInterface(DVDInterface::DIInterruptType interrupt_type); static void InterruptFromDVDInterface(DVDInterface::DIInterruptType interrupt_type);
static DiscIO::Partition GetCurrentPartition();
void DoState(PointerWrap& p) override; void DoState(PointerWrap& p) override;
@ -116,6 +119,7 @@ private:
bool m_copy_diimmbuf; bool m_copy_diimmbuf;
}; };
friend class ::CBoot;
friend void ::IOS::HLE::Init(); friend void ::IOS::HLE::Init();
void ProcessQueuedIOCtl(); void ProcessQueuedIOCtl();
@ -125,6 +129,7 @@ private:
std::optional<DIResult> StartImmediateTransfer(const IOCtlRequest& request, std::optional<DIResult> StartImmediateTransfer(const IOCtlRequest& request,
bool write_to_buf = true); bool write_to_buf = true);
void ChangePartition(const DiscIO::Partition partition);
void InitializeIfFirstTime(); void InitializeIfFirstTime();
void ResetDIRegisters(); void ResetDIRegisters();
static void FinishDICommandCallback(u64 userdata, s64 ticksbehind); static void FinishDICommandCallback(u64 userdata, s64 ticksbehind);
@ -135,6 +140,8 @@ private:
std::optional<ExecutingCommandInfo> m_executing_command; std::optional<ExecutingCommandInfo> m_executing_command;
std::deque<u32> m_commands_to_execute; std::deque<u32> m_commands_to_execute;
DiscIO::Partition m_current_partition = DiscIO::PARTITION_NONE;
bool m_has_initialized = false; bool m_has_initialized = false;
u32 m_last_length = 0; u32 m_last_length = 0;
}; };