Merge pull request #8561 from JosJuice/di-wii-oob-2

Fix Error #001 (alternative solution)
This commit is contained in:
Tilka 2020-01-14 17:51:21 +00:00 committed by GitHub
commit 31d7b56c19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 11 deletions

View File

@ -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;
}

View File

@ -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;