IOS/DI: Fake the error 001 read when running DirectoryBlobs or Riivolution-patched games.
This commit is contained in:
parent
ffe0bcbb84
commit
8d0f52032b
|
@ -15,4 +15,6 @@ const Info<bool> SESSION_GCI_FOLDER_CURRENT_GAME_ONLY{
|
|||
{System::Session, "Core", "GCIFolderCurrentGameOnly"}, false};
|
||||
const Info<bool> SESSION_CODE_SYNC_OVERRIDE{{System::Session, "Core", "CheatSyncOverride"}, false};
|
||||
const Info<bool> SESSION_SAVE_DATA_WRITABLE{{System::Session, "Core", "SaveDataWritable"}, true};
|
||||
const Info<bool> SESSION_SHOULD_FAKE_ERROR_001{{System::Session, "Core", "ShouldFakeError001"},
|
||||
false};
|
||||
} // namespace Config
|
||||
|
|
|
@ -13,4 +13,5 @@ extern const Info<bool> SESSION_LOAD_IPL_DUMP;
|
|||
extern const Info<bool> SESSION_GCI_FOLDER_CURRENT_GAME_ONLY;
|
||||
extern const Info<bool> SESSION_CODE_SYNC_OVERRIDE;
|
||||
extern const Info<bool> SESSION_SAVE_DATA_WRITABLE;
|
||||
extern const Info<bool> SESSION_SHOULD_FAKE_ERROR_001;
|
||||
} // namespace Config
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Config/SessionSettings.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/DolphinAnalytics.h"
|
||||
#include "Core/HW/AudioInterface.h"
|
||||
|
@ -462,6 +463,14 @@ void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
|
|||
WARN_LOG_FMT(DVDINTERFACE, "Unknown disc size, guessing {0} bytes", s_disc_end_offset);
|
||||
|
||||
const DiscIO::BlobReader& blob = disc->GetBlobReader();
|
||||
|
||||
// DirectoryBlobs (including Riivolution-patched discs) may end up larger than a real physical
|
||||
// Wii disc, which triggers Error #001. In those cases we manually make the check succeed to
|
||||
// avoid problems.
|
||||
const bool should_fake_error_001 =
|
||||
SConfig::GetInstance().bWii && blob.GetBlobType() == DiscIO::BlobType::DIRECTORY;
|
||||
Config::SetCurrent(Config::SESSION_SHOULD_FAKE_ERROR_001, should_fake_error_001);
|
||||
|
||||
if (!blob.HasFastRandomAccessInBlock() && blob.GetBlockSize() > 0x200000)
|
||||
{
|
||||
OSD::AddMessage("You are running a disc image with a very large block size.", 60000);
|
||||
|
@ -1263,6 +1272,22 @@ void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
|
|||
}
|
||||
}
|
||||
|
||||
void ForceOutOfBoundsRead(ReplyType reply_type)
|
||||
{
|
||||
INFO_LOG_FMT(DVDINTERFACE, "Forcing an out-of-bounds disc read.");
|
||||
|
||||
if (s_drive_state == DriveState::ReadyNoReadsMade)
|
||||
SetDriveState(DriveState::Ready);
|
||||
|
||||
SetDriveError(DriveError::BlockOOB);
|
||||
|
||||
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
|
||||
const DIInterruptType interrupt_type = DIInterruptType::DEINT;
|
||||
CoreTiming::ScheduleEvent(
|
||||
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
|
||||
s_finish_executing_command, PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
|
||||
}
|
||||
|
||||
void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length)
|
||||
{
|
||||
s_enable_dtk = enable_dtk;
|
||||
|
|
|
@ -134,6 +134,10 @@ bool UpdateRunningGameMetadata(std::optional<u64> title_id = {});
|
|||
void ExecuteCommand(ReplyType reply_type);
|
||||
void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
|
||||
const DiscIO::Partition& partition, ReplyType reply_type);
|
||||
|
||||
// For circumventing Error #001 in DirectoryBlobs, which may have data in the offsets being checked.
|
||||
void ForceOutOfBoundsRead(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);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Core/Config/SessionSettings.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/DolphinAnalytics.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
|
@ -132,6 +133,16 @@ std::optional<DIDevice::DIResult> DIDevice::WriteIfFits(const IOCtlRequest& requ
|
|||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct DiscRange
|
||||
{
|
||||
u32 start;
|
||||
u32 end;
|
||||
bool is_error_001_range;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& request)
|
||||
{
|
||||
if (request.buffer_in_size != 0x20)
|
||||
|
@ -315,22 +326,33 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
|||
// (start, end) as 32-bit offsets
|
||||
// Older IOS versions only accept the first range. Later versions added the extra ranges to
|
||||
// check how the drive responds to out of bounds reads (an error 001 check).
|
||||
constexpr std::array<std::pair<u32, u32>, 3> valid_ranges = {
|
||||
std::make_pair(0, 0x14000), // "System area"
|
||||
std::make_pair(0x460A0000, 0x460A0008),
|
||||
std::make_pair(0x7ED40000, 0x7ED40008),
|
||||
constexpr std::array<DiscRange, 3> valid_ranges = {
|
||||
DiscRange{0, 0x14000, false}, // "System area"
|
||||
DiscRange{0x460A0000, 0x460A0008, true},
|
||||
DiscRange{0x7ED40000, 0x7ED40008, true},
|
||||
};
|
||||
for (auto range : valid_ranges)
|
||||
{
|
||||
if (range.first <= position && position <= range.second && range.first <= end &&
|
||||
end <= range.second)
|
||||
if (range.start <= position && position <= range.end && range.start <= end &&
|
||||
end <= range.end)
|
||||
{
|
||||
DICMDBUF0 = 0xA8000000;
|
||||
DICMDBUF1 = position;
|
||||
DICMDBUF2 = length;
|
||||
if (range.is_error_001_range && Config::Get(Config::SESSION_SHOULD_FAKE_ERROR_001))
|
||||
{
|
||||
DIMAR = request.buffer_out;
|
||||
m_last_length = length;
|
||||
DILENGTH = length;
|
||||
DVDInterface::ForceOutOfBoundsRead(DVDInterface::ReplyType::IOS);
|
||||
return {};
|
||||
}
|
||||
else
|
||||
{
|
||||
return StartDMATransfer(length, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
WARN_LOG_FMT(IOS_DI, "DVDLowUnencryptedRead: trying to read from an illegal region!");
|
||||
return DIResult::SecurityError;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue