mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 15:45:42 +00:00
CDImageDevice: Verify MSF of SUBQ before use
This commit is contained in:
parent
4d5c8cb134
commit
084a76afa0
|
@ -4,6 +4,9 @@
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "cd_image.h"
|
#include "cd_image.h"
|
||||||
|
|
||||||
|
// TODO: Remove me..
|
||||||
|
#include "core/host.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
@ -91,7 +94,8 @@ enum class SCSIReadMode : u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] static bool VerifySCSIReadData(std::span<const u8> buffer, SCSIReadMode mode)
|
[[maybe_unused]] static bool VerifySCSIReadData(std::span<const u8> buffer, SCSIReadMode mode,
|
||||||
|
CDImage::LBA expected_sector)
|
||||||
{
|
{
|
||||||
const u32 expected_size = SCSIReadCommandOutputSize(mode);
|
const u32 expected_size = SCSIReadCommandOutputSize(mode);
|
||||||
if (buffer.size() != expected_size)
|
if (buffer.size() != expected_size)
|
||||||
|
@ -100,6 +104,8 @@ enum class SCSIReadMode : u8
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CDImage::Position expected_pos = CDImage::Position::FromLBA(expected_sector);
|
||||||
|
|
||||||
if (mode == SCSIReadMode::Full)
|
if (mode == SCSIReadMode::Full)
|
||||||
{
|
{
|
||||||
// Validate subcode.
|
// Validate subcode.
|
||||||
|
@ -107,6 +113,11 @@ enum class SCSIReadMode : u8
|
||||||
CDImage::SubChannelQ subq;
|
CDImage::SubChannelQ subq;
|
||||||
CDImage::DeinterleaveSubcode(buffer.data() + CDImage::RAW_SECTOR_SIZE, deinterleaved_subcode);
|
CDImage::DeinterleaveSubcode(buffer.data() + CDImage::RAW_SECTOR_SIZE, deinterleaved_subcode);
|
||||||
std::memcpy(&subq, &deinterleaved_subcode[CDImage::SUBCHANNEL_BYTES_PER_FRAME], sizeof(subq));
|
std::memcpy(&subq, &deinterleaved_subcode[CDImage::SUBCHANNEL_BYTES_PER_FRAME], sizeof(subq));
|
||||||
|
|
||||||
|
Log_DevFmt("SCSI full subcode read returned [{}] for {:02d}:{:02d}:{:02d}",
|
||||||
|
StringUtil::EncodeHex(subq.data.data(), static_cast<int>(subq.data.size())), expected_pos.minute,
|
||||||
|
expected_pos.second, expected_pos.frame);
|
||||||
|
|
||||||
if (!subq.IsCRCValid())
|
if (!subq.IsCRCValid())
|
||||||
{
|
{
|
||||||
Log_WarningFmt("SCSI full subcode read returned invalid SubQ CRC (got {:02X} expected {:02X})", subq.crc,
|
Log_WarningFmt("SCSI full subcode read returned invalid SubQ CRC (got {:02X} expected {:02X})", subq.crc,
|
||||||
|
@ -114,12 +125,27 @@ enum class SCSIReadMode : u8
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CDImage::Position got_pos =
|
||||||
|
CDImage::Position::FromBCD(subq.absolute_minute_bcd, subq.absolute_second_bcd, subq.absolute_frame_bcd);
|
||||||
|
if (expected_pos != got_pos)
|
||||||
|
{
|
||||||
|
Log_WarningFmt(
|
||||||
|
"SCSI full subcode read returned invalid MSF (got {:02x}:{:02x}:{:02x}, expected {:02d}:{:02d}:{:02d})",
|
||||||
|
subq.absolute_minute_bcd, subq.absolute_second_bcd, subq.absolute_frame_bcd, expected_pos.minute,
|
||||||
|
expected_pos.second, expected_pos.frame);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (mode == SCSIReadMode::SubQOnly)
|
else if (mode == SCSIReadMode::SubQOnly)
|
||||||
{
|
{
|
||||||
CDImage::SubChannelQ subq;
|
CDImage::SubChannelQ subq;
|
||||||
std::memcpy(&subq, buffer.data() + CDImage::RAW_SECTOR_SIZE, sizeof(subq));
|
std::memcpy(&subq, buffer.data() + CDImage::RAW_SECTOR_SIZE, sizeof(subq));
|
||||||
|
Log_DevFmt("SCSI subq read returned [{}] for {:02d}:{:02d}:{:02d}",
|
||||||
|
StringUtil::EncodeHex(subq.data.data(), static_cast<int>(subq.data.size())), expected_pos.minute,
|
||||||
|
expected_pos.second, expected_pos.frame);
|
||||||
|
|
||||||
if (!subq.IsCRCValid())
|
if (!subq.IsCRCValid())
|
||||||
{
|
{
|
||||||
Log_WarningFmt("SCSI subq read returned invalid SubQ CRC (got {:02X} expected {:02X})", subq.crc,
|
Log_WarningFmt("SCSI subq read returned invalid SubQ CRC (got {:02X} expected {:02X})", subq.crc,
|
||||||
|
@ -127,6 +153,16 @@ enum class SCSIReadMode : u8
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CDImage::Position got_pos =
|
||||||
|
CDImage::Position::FromBCD(subq.absolute_minute_bcd, subq.absolute_second_bcd, subq.absolute_frame_bcd);
|
||||||
|
if (expected_pos != got_pos)
|
||||||
|
{
|
||||||
|
Log_WarningFmt("SCSI subq read returned invalid MSF (got {:02x}:{:02x}:{:02x}, expected {:02d}:{:02d}:{:02d})",
|
||||||
|
subq.absolute_minute_bcd, subq.absolute_second_bcd, subq.absolute_frame_bcd, expected_pos.minute,
|
||||||
|
expected_pos.second, expected_pos.frame);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else // if (mode == SCSIReadMode::None || mode == SCSIReadMode::Raw)
|
else // if (mode == SCSIReadMode::None || mode == SCSIReadMode::Raw)
|
||||||
|
@ -136,6 +172,11 @@ enum class SCSIReadMode : u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] static bool ShouldTryReadingSubcode()
|
||||||
|
{
|
||||||
|
return !Host::GetBaseBoolSettingValue("CDROM", "IgnoreHostSubcode", false);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
// The include order here is critical.
|
// The include order here is critical.
|
||||||
|
@ -522,13 +563,15 @@ bool CDImageDeviceWin32::DetermineReadMode(bool try_sptd)
|
||||||
{
|
{
|
||||||
// Prefer raw reads if we can use them
|
// Prefer raw reads if we can use them
|
||||||
const LBA track_1_lba = static_cast<LBA>(m_indices[m_tracks[0].first_index].file_offset);
|
const LBA track_1_lba = static_cast<LBA>(m_indices[m_tracks[0].first_index].file_offset);
|
||||||
|
const LBA track_1_subq_lba = track_1_lba + FRAMES_PER_SECOND * 2;
|
||||||
|
const bool check_subcode = ShouldTryReadingSubcode();
|
||||||
|
|
||||||
Log_DevPrint("Trying raw reads...");
|
Log_DevPrint("Trying raw reads...");
|
||||||
if (DoRawRead(track_1_lba))
|
if (check_subcode && DoRawRead(track_1_lba))
|
||||||
{
|
{
|
||||||
// verify subcode
|
// verify subcode
|
||||||
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), SCSIReadCommandOutputSize(SCSIReadMode::Full)),
|
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), SCSIReadCommandOutputSize(SCSIReadMode::Full)),
|
||||||
SCSIReadMode::Full))
|
SCSIReadMode::Full, track_1_subq_lba))
|
||||||
{
|
{
|
||||||
Log_VerbosePrint("Using raw reads with full subcode");
|
Log_VerbosePrint("Using raw reads with full subcode");
|
||||||
m_scsi_read_mode = SCSIReadMode::None;
|
m_scsi_read_mode = SCSIReadMode::None;
|
||||||
|
@ -540,9 +583,9 @@ bool CDImageDeviceWin32::DetermineReadMode(bool try_sptd)
|
||||||
std::optional<u32> transfer_size;
|
std::optional<u32> transfer_size;
|
||||||
|
|
||||||
Log_DevPrint("Trying SCSI read with full subcode...");
|
Log_DevPrint("Trying SCSI read with full subcode...");
|
||||||
if ((transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::Full)).has_value())
|
if (check_subcode && (transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::Full)).has_value())
|
||||||
{
|
{
|
||||||
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::Full))
|
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::Full, track_1_subq_lba))
|
||||||
{
|
{
|
||||||
Log_VerbosePrint("Using SCSI reads with subcode");
|
Log_VerbosePrint("Using SCSI reads with subcode");
|
||||||
m_scsi_read_mode = SCSIReadMode::Full;
|
m_scsi_read_mode = SCSIReadMode::Full;
|
||||||
|
@ -552,9 +595,10 @@ bool CDImageDeviceWin32::DetermineReadMode(bool try_sptd)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_WarningPrint("Full subcode failed, trying SCSI read with only subq...");
|
Log_WarningPrint("Full subcode failed, trying SCSI read with only subq...");
|
||||||
if ((transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::SubQOnly)).has_value())
|
if (check_subcode && (transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::SubQOnly)).has_value())
|
||||||
{
|
{
|
||||||
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::SubQOnly))
|
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::SubQOnly,
|
||||||
|
track_1_subq_lba))
|
||||||
{
|
{
|
||||||
Log_VerbosePrint("Using SCSI reads with subq only");
|
Log_VerbosePrint("Using SCSI reads with subq only");
|
||||||
m_scsi_read_mode = SCSIReadMode::SubQOnly;
|
m_scsi_read_mode = SCSIReadMode::SubQOnly;
|
||||||
|
@ -567,7 +611,7 @@ bool CDImageDeviceWin32::DetermineReadMode(bool try_sptd)
|
||||||
Log_WarningPrint("Subq only failed failed, trying SCSI without subcode...");
|
Log_WarningPrint("Subq only failed failed, trying SCSI without subcode...");
|
||||||
if ((transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::Raw)).has_value())
|
if ((transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::Raw)).has_value())
|
||||||
{
|
{
|
||||||
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::Raw))
|
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::Raw, track_1_subq_lba))
|
||||||
{
|
{
|
||||||
Log_WarningPrint("Using SCSI raw reads, libcrypt games will not run correctly");
|
Log_WarningPrint("Using SCSI raw reads, libcrypt games will not run correctly");
|
||||||
m_scsi_read_mode = SCSIReadMode::Raw;
|
m_scsi_read_mode = SCSIReadMode::Raw;
|
||||||
|
@ -990,12 +1034,14 @@ bool CDImageDeviceLinux::ReadSectorToBuffer(LBA lba)
|
||||||
bool CDImageDeviceLinux::DetermineReadMode(Error* error)
|
bool CDImageDeviceLinux::DetermineReadMode(Error* error)
|
||||||
{
|
{
|
||||||
const LBA track_1_lba = static_cast<LBA>(m_indices[m_tracks[0].first_index].file_offset);
|
const LBA track_1_lba = static_cast<LBA>(m_indices[m_tracks[0].first_index].file_offset);
|
||||||
|
const LBA track_1_subq_lba = track_1_lba + FRAMES_PER_SECOND * 2;
|
||||||
|
const bool check_subcode = ShouldTryReadingSubcode();
|
||||||
std::optional<u32> transfer_size;
|
std::optional<u32> transfer_size;
|
||||||
|
|
||||||
Log_DevPrint("Trying SCSI read with full subcode...");
|
Log_DevPrint("Trying SCSI read with full subcode...");
|
||||||
if ((transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::Full)).has_value())
|
if (check_subcode && (transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::Full)).has_value())
|
||||||
{
|
{
|
||||||
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::Full))
|
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::Full, track_1_subq_lba))
|
||||||
{
|
{
|
||||||
Log_VerbosePrint("Using SCSI reads with subcode");
|
Log_VerbosePrint("Using SCSI reads with subcode");
|
||||||
m_scsi_read_mode = SCSIReadMode::Full;
|
m_scsi_read_mode = SCSIReadMode::Full;
|
||||||
|
@ -1004,9 +1050,10 @@ bool CDImageDeviceLinux::DetermineReadMode(Error* error)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_WarningPrint("Full subcode failed, trying SCSI read with only subq...");
|
Log_WarningPrint("Full subcode failed, trying SCSI read with only subq...");
|
||||||
if ((transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::SubQOnly)).has_value())
|
if (check_subcode && (transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::SubQOnly)).has_value())
|
||||||
{
|
{
|
||||||
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::SubQOnly))
|
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::SubQOnly,
|
||||||
|
track_1_subq_lba))
|
||||||
{
|
{
|
||||||
Log_VerbosePrint("Using SCSI reads with subq only");
|
Log_VerbosePrint("Using SCSI reads with subq only");
|
||||||
m_scsi_read_mode = SCSIReadMode::SubQOnly;
|
m_scsi_read_mode = SCSIReadMode::SubQOnly;
|
||||||
|
@ -1026,7 +1073,7 @@ bool CDImageDeviceLinux::DetermineReadMode(Error* error)
|
||||||
Log_WarningPrint("CDROMREADRAW failed, trying SCSI without subcode...");
|
Log_WarningPrint("CDROMREADRAW failed, trying SCSI without subcode...");
|
||||||
if ((transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::Raw)).has_value())
|
if ((transfer_size = DoSCSIRead(track_1_lba, SCSIReadMode::Raw)).has_value())
|
||||||
{
|
{
|
||||||
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::Raw))
|
if (VerifySCSIReadData(std::span<u8>(m_buffer.data(), transfer_size.value()), SCSIReadMode::Raw, track_1_subq_lba))
|
||||||
{
|
{
|
||||||
Log_WarningPrint("Using SCSI raw reads, libcrypt games will not run correctly");
|
Log_WarningPrint("Using SCSI raw reads, libcrypt games will not run correctly");
|
||||||
m_scsi_read_mode = SCSIReadMode::Raw;
|
m_scsi_read_mode = SCSIReadMode::Raw;
|
||||||
|
|
Loading…
Reference in a new issue