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/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::Device::DI>(
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

View File

@ -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<DiscIO::VolumeDisc> disc,
{
bool had_disc = IsDiscInside();
bool has_disc = static_cast<bool>(disc);
if (has_disc)
s_current_partition = disc->GetGamePartition();
if (auto_disc_change_paths)
{
@ -548,12 +544,8 @@ bool UpdateRunningGameMetadata(std::optional<u64> 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<u64>(position) << 2, output_address, length, length,
s_current_partition, reply_type, &interrupt_type);
ExecuteReadCommand(static_cast<u64>(position) << 2, output_address, length, length, partition,
reply_type, &interrupt_type);
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,
// 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);

View File

@ -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::DIResult> 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<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)
{
WARN_LOG(IOS_DI,
@ -176,7 +181,7 @@ std::optional<DI::DIResult> 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::DIResult> 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::DIResult> 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::DIResult> 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<u64>(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<u8>& 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<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()
{
// 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

View File

@ -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<DIResult> 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<ExecutingCommandInfo> m_executing_command;
std::deque<u32> m_commands_to_execute;
DiscIO::Partition m_current_partition = DiscIO::PARTITION_NONE;
bool m_has_initialized = false;
u32 m_last_length = 0;
};