From 21c152f51f91baec8e5187ead264db9e1c748da9 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 14 Jan 2020 16:09:38 +0100 Subject: [PATCH] Fix Error #001 (alternative solution) This is an alternative to PR 8557 and PR 8558. The way this PR solves the problem is essentially the same as what we had before PR 8394 (except the code we had back then only worked because it was broken). --- Source/Core/Core/HW/DVD/DVDInterface.cpp | 20 ++++++++++++++++++++ Source/Core/Core/HW/DVD/DVDThread.cpp | 13 ++----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index 5050cd906e..9ecb58dc03 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -748,6 +748,26 @@ bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, u32 dvd_length = output_length; } + // Many Wii games intentionally try to read from an offset which is just past the end of a regular + // DVD but just before the end of a DVD-R, displaying "Error #001" and failing to boot if the read + // succeeds (see https://wiibrew.org/wiki//dev/di#0x8D_DVDLowUnencryptedRead for more details). + // It would be nice if we simply could rely on DiscIO for letting us know whether a read is out + // of bounds, but this unfortunately doesn't work when using a disc image format that doesn't + // store the original size of the disc, most notably WBFS. Instead, we have a little hack here: + // reject all non-partition reads that come from IOS that go past the offset 0x50000. IOS only + // allows non-partition reads if they are before 0x50000 or if they are in one of the two small + // areas 0x118240000-0x118240020 and 0x1FB4E0000-0x1FB4E0020 (both of which only are used for + // Error #001 checks), so the only thing we disallow with this hack that actually should be + // allowed is non-partition reads in the 0x118240000-0x118240020 area on dual-layer discs. + // In practice, dual-layer games don't attempt to do non-partition reads in that area. + if (reply_type == ReplyType::IOS && partition == DiscIO::PARTITION_NONE && + dvd_offset + dvd_length > 0x50000) + { + SetHighError(DVDInterface::ERROR_BLOCK_OOB); + *interrupt_type = DIInterruptType::DEINT; + return false; + } + ScheduleReads(dvd_offset, dvd_length, partition, output_address, reply_type); return true; } diff --git a/Source/Core/Core/HW/DVD/DVDThread.cpp b/Source/Core/Core/HW/DVD/DVDThread.cpp index 5f28518a91..00279c5df4 100644 --- a/Source/Core/Core/HW/DVD/DVDThread.cpp +++ b/Source/Core/Core/HW/DVD/DVDThread.cpp @@ -345,17 +345,8 @@ static void FinishRead(u64 id, s64 cycles_late) DVDInterface::DIInterruptType interrupt; if (buffer.size() != request.length) { - if (request.dvd_offset != 0x118280000 && request.dvd_offset != 0x1FB500000) - { - PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").", - request.dvd_offset, request.dvd_offset + request.length); - } - else - { - // Part of the error 001 check. - INFO_LOG(DVDINTERFACE, "Ignoring out of bounds test read (at 0x%" PRIx64 " - 0x%" PRIx64 ")", - request.dvd_offset, request.dvd_offset + request.length); - } + PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").", + request.dvd_offset, request.dvd_offset + request.length); DVDInterface::SetHighError(DVDInterface::ERROR_BLOCK_OOB); interrupt = DVDInterface::DIInterruptType::DEINT;