mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
VolumeWiiCrypted: Replace ChangePartition with a partition parameter
By removing mutable state in VolumeWiiCrypted, this change makes partition-related code simpler. It also gets rid of other ugly things, like ISOProperties's "over 9000" loop that creates a list of partitions by trying possible combinations, and DiscScrubber's volume swapping that recreates the entire volume when it needs to change partition.
This commit is contained in:
@@ -50,10 +50,10 @@ static const DiscIO::IVolume* SetDisc(std::unique_ptr<DiscIO::IVolume> volume)
|
||||
}
|
||||
|
||||
bool CBoot::DVDRead(const DiscIO::IVolume& volume, u64 dvd_offset, u32 output_address, u32 length,
|
||||
bool decrypt)
|
||||
const DiscIO::Partition& partition)
|
||||
{
|
||||
std::vector<u8> buffer(length);
|
||||
if (!volume.Read(dvd_offset, length, buffer.data(), decrypt))
|
||||
if (!volume.Read(dvd_offset, length, buffer.data(), partition))
|
||||
return false;
|
||||
Memory::CopyToEmu(output_address, buffer.data(), length);
|
||||
return true;
|
||||
@@ -64,8 +64,10 @@ void CBoot::Load_FST(bool is_wii, const DiscIO::IVolume* volume)
|
||||
if (!volume)
|
||||
return;
|
||||
|
||||
const DiscIO::Partition partition = volume->GetGamePartition();
|
||||
|
||||
// copy first 32 bytes of disc to start of Mem 1
|
||||
DVDRead(*volume, /*offset*/ 0, /*address*/ 0, /*length*/ 0x20, false);
|
||||
DVDRead(*volume, /*offset*/ 0, /*address*/ 0, /*length*/ 0x20, DiscIO::PARTITION_NONE);
|
||||
|
||||
// copy of game id
|
||||
Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180);
|
||||
@@ -78,15 +80,15 @@ void CBoot::Load_FST(bool is_wii, const DiscIO::IVolume* volume)
|
||||
u32 fst_size = 0;
|
||||
u32 max_fst_size = 0;
|
||||
|
||||
volume->ReadSwapped(0x0424, &fst_offset, is_wii);
|
||||
volume->ReadSwapped(0x0428, &fst_size, is_wii);
|
||||
volume->ReadSwapped(0x042c, &max_fst_size, is_wii);
|
||||
volume->ReadSwapped(0x0424, &fst_offset, partition);
|
||||
volume->ReadSwapped(0x0428, &fst_size, partition);
|
||||
volume->ReadSwapped(0x042c, &max_fst_size, partition);
|
||||
|
||||
u32 arena_high = Common::AlignDown(0x817FFFFF - (max_fst_size << shift), 0x20);
|
||||
Memory::Write_U32(arena_high, 0x00000034);
|
||||
|
||||
// load FST
|
||||
DVDRead(*volume, fst_offset << shift, arena_high, fst_size << shift, is_wii);
|
||||
DVDRead(*volume, fst_offset << shift, arena_high, fst_size << shift, partition);
|
||||
Memory::Write_U32(arena_high, 0x00000038);
|
||||
Memory::Write_U32(max_fst_size << shift, 0x0000003c);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace DiscIO
|
||||
{
|
||||
class IVolume;
|
||||
struct Partition;
|
||||
}
|
||||
|
||||
struct RegionSetting
|
||||
@@ -46,7 +47,7 @@ public:
|
||||
|
||||
private:
|
||||
static bool DVDRead(const DiscIO::IVolume& volume, u64 dvd_offset, u32 output_address, u32 length,
|
||||
bool decrypt);
|
||||
const DiscIO::Partition& partition);
|
||||
static void RunFunction(u32 address);
|
||||
|
||||
static void UpdateDebugger_MapLoaded();
|
||||
|
||||
@@ -79,21 +79,24 @@ void CBoot::SetupBAT(bool is_wii)
|
||||
|
||||
bool CBoot::RunApploader(bool is_wii, const DiscIO::IVolume& volume)
|
||||
{
|
||||
const DiscIO::Partition partition = volume.GetGamePartition();
|
||||
|
||||
// Load Apploader to Memory - The apploader is hardcoded to begin at 0x2440 on the disc,
|
||||
// but the size can differ between discs. Compare with YAGCD chap 13.
|
||||
const u32 apploader_offset = 0x2440;
|
||||
u32 apploader_entry = 0;
|
||||
u32 apploader_size = 0;
|
||||
u32 apploader_trailer = 0;
|
||||
if (!volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, is_wii) ||
|
||||
!volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, is_wii) ||
|
||||
!volume.ReadSwapped(apploader_offset + 0x18, &apploader_trailer, is_wii) ||
|
||||
if (!volume.ReadSwapped(apploader_offset + 0x10, &apploader_entry, partition) ||
|
||||
!volume.ReadSwapped(apploader_offset + 0x14, &apploader_size, partition) ||
|
||||
!volume.ReadSwapped(apploader_offset + 0x18, &apploader_trailer, partition) ||
|
||||
apploader_entry == (u32)-1 || apploader_size + apploader_trailer == (u32)-1)
|
||||
{
|
||||
INFO_LOG(BOOT, "Invalid apploader. Your disc image is probably corrupted.");
|
||||
return false;
|
||||
}
|
||||
DVDRead(volume, apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer, is_wii);
|
||||
DVDRead(volume, apploader_offset + 0x20, 0x01200000, apploader_size + apploader_trailer,
|
||||
partition);
|
||||
|
||||
// TODO - Make Apploader(or just RunFunction()) debuggable!!!
|
||||
|
||||
@@ -132,7 +135,7 @@ bool CBoot::RunApploader(bool is_wii, const DiscIO::IVolume& volume)
|
||||
|
||||
INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset,
|
||||
iRamAddress, iLength);
|
||||
DVDRead(volume, iDVDOffset, iRamAddress, iLength, is_wii);
|
||||
DVDRead(volume, iDVDOffset, iRamAddress, iLength, partition);
|
||||
|
||||
} while (PowerPC::ppcState.gpr[3] != 0x00);
|
||||
|
||||
@@ -163,7 +166,7 @@ bool CBoot::EmulatedBS2_GC(const DiscIO::IVolume* volume, bool skip_app_loader)
|
||||
|
||||
// It's possible to boot DOL and ELF files without a disc inserted
|
||||
if (volume)
|
||||
DVDRead(*volume, /*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, false);
|
||||
DVDRead(*volume, /*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, DiscIO::PARTITION_NONE);
|
||||
|
||||
// Booted from bootrom. 0xE5207C22 = booted from jtag
|
||||
PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020);
|
||||
@@ -280,7 +283,7 @@ bool CBoot::SetupWiiMemory(const DiscIO::IVolume* volume, u64 ios_title_id)
|
||||
|
||||
// When booting a WAD or the system menu, there will probably not be a disc inserted
|
||||
if (volume)
|
||||
DVDRead(*volume, 0x00000000, 0x00000000, 0x20, false); // Game Code
|
||||
DVDRead(*volume, 0x00000000, 0x00000000, 0x20, DiscIO::PARTITION_NONE); // Game Code
|
||||
|
||||
Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
|
||||
Memory::Write_U32(0x00000001, 0x00000024); // Unknown
|
||||
@@ -335,7 +338,8 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::IVolume* volume)
|
||||
if (volume->GetVolumeType() != DiscIO::Platform::WII_DISC)
|
||||
return false;
|
||||
|
||||
const IOS::ES::TMDReader tmd = volume->GetTMD();
|
||||
const DiscIO::Partition partition = volume->GetGamePartition();
|
||||
const IOS::ES::TMDReader tmd = volume->GetTMD(partition);
|
||||
|
||||
if (!SetupWiiMemory(volume, tmd.GetIOSId()))
|
||||
return false;
|
||||
@@ -344,7 +348,7 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::IVolume* volume)
|
||||
// values as the game boots. This location keeps the 4 byte ID for as long
|
||||
// as the game is running. The 6 byte ID at 0x00 is overwritten sometime
|
||||
// after this check during booting.
|
||||
DVDRead(*volume, 0, 0x3180, 4, true);
|
||||
DVDRead(*volume, 0, 0x3180, 4, partition);
|
||||
|
||||
SetupBAT(/*is_wii*/ true);
|
||||
|
||||
@@ -359,7 +363,7 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::IVolume* volume)
|
||||
|
||||
// Warning: This call will set incorrect running game metadata if our volume parameter
|
||||
// doesn't point to the same disc as the one that's inserted in the emulated disc drive!
|
||||
IOS::HLE::Device::ES::DIVerify(tmd, volume->GetTicket());
|
||||
IOS::HLE::Device::ES::DIVerify(tmd, volume->GetTicket(partition));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "Core/FifoPlayer/FifoDataFile.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
#include "Core/HW/DVD/DVDThread.h"
|
||||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
#include "Core/IOS/USB/Bluetooth/BTBase.h"
|
||||
@@ -746,11 +745,12 @@ void SConfig::ResetRunningGameMetadata()
|
||||
SetRunningGameMetadata("00000000", 0, 0);
|
||||
}
|
||||
|
||||
void SConfig::SetRunningGameMetadata(const DiscIO::IVolume& volume)
|
||||
void SConfig::SetRunningGameMetadata(const DiscIO::IVolume& volume,
|
||||
const DiscIO::Partition& partition)
|
||||
{
|
||||
u64 title_id = 0;
|
||||
volume.GetTitleID(&title_id);
|
||||
SetRunningGameMetadata(volume.GetGameID(), title_id, volume.GetRevision());
|
||||
volume.GetTitleID(&title_id, partition);
|
||||
SetRunningGameMetadata(volume.GetGameID(partition), title_id, volume.GetRevision(partition));
|
||||
}
|
||||
|
||||
void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd)
|
||||
@@ -761,7 +761,7 @@ void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd)
|
||||
// the disc header instead of the TMD. They can differ.
|
||||
// (IOS HLE ES calls us with a TMDReader rather than a volume when launching
|
||||
// a disc game, because ES has no reason to be accessing the disc directly.)
|
||||
if (!DVDThread::UpdateRunningGameMetadata(tmd_title_id))
|
||||
if (!DVDInterface::UpdateRunningGameMetadata(tmd_title_id))
|
||||
{
|
||||
// If not launching a disc game, just read everything from the TMD.
|
||||
SetRunningGameMetadata(tmd.GetGameID(), tmd_title_id, tmd.GetTitleVersion());
|
||||
@@ -935,7 +935,7 @@ bool SConfig::AutoSetup(EBootBS2 _BootBS2)
|
||||
m_strFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
SetRunningGameMetadata(*pVolume);
|
||||
SetRunningGameMetadata(*pVolume, pVolume->GetGamePartition());
|
||||
|
||||
// Check if we have a Wii disc
|
||||
bWii = pVolume->GetVolumeType() == DiscIO::Platform::WII_DISC;
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace DiscIO
|
||||
{
|
||||
enum class Language;
|
||||
enum class Region;
|
||||
struct Partition;
|
||||
class IVolume;
|
||||
}
|
||||
namespace IOS
|
||||
@@ -226,7 +227,7 @@ struct SConfig : NonCopyable
|
||||
u64 GetTitleID() const { return m_title_id; }
|
||||
u16 GetRevision() const { return m_revision; }
|
||||
void ResetRunningGameMetadata();
|
||||
void SetRunningGameMetadata(const DiscIO::IVolume& volume);
|
||||
void SetRunningGameMetadata(const DiscIO::IVolume& volume, const DiscIO::Partition& partition);
|
||||
void SetRunningGameMetadata(const IOS::ES::TMDReader& tmd);
|
||||
|
||||
void LoadDefaults();
|
||||
|
||||
@@ -218,6 +218,7 @@ static u32 s_pending_samples;
|
||||
|
||||
// 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;
|
||||
@@ -243,12 +244,14 @@ void UpdateInterrupts();
|
||||
void GenerateDIInterrupt(DIInterruptType _DVDInterrupt);
|
||||
|
||||
void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios);
|
||||
bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length,
|
||||
bool decrypt, ReplyType reply_type, DIInterruptType* interrupt_type);
|
||||
bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, u32 output_length,
|
||||
const DiscIO::Partition& partition, ReplyType reply_type,
|
||||
DIInterruptType* interrupt_type);
|
||||
|
||||
u64 PackFinishExecutingCommandUserdata(ReplyType reply_type, DIInterruptType interrupt_type);
|
||||
|
||||
void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, ReplyType reply_type);
|
||||
void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, u32 output_address,
|
||||
ReplyType reply_type);
|
||||
|
||||
void DoState(PointerWrap& p)
|
||||
{
|
||||
@@ -271,6 +274,7 @@ void DoState(PointerWrap& p)
|
||||
p.Do(s_pending_samples);
|
||||
|
||||
p.Do(s_error_code);
|
||||
p.Do(s_current_partition);
|
||||
|
||||
p.Do(s_read_buffer_start_time);
|
||||
p.Do(s_read_buffer_end_time);
|
||||
@@ -309,8 +313,9 @@ static u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process)
|
||||
{
|
||||
if (s_audio_position >= s_current_start + s_current_length)
|
||||
{
|
||||
DEBUG_LOG(DVDINTERFACE, "AdvanceDTK: NextStart=%08" PRIx64 ", NextLength=%08x, "
|
||||
"CurrentStart=%08" PRIx64 ", CurrentLength=%08x, AudioPos=%08" PRIx64,
|
||||
DEBUG_LOG(DVDINTERFACE,
|
||||
"AdvanceDTK: NextStart=%08" PRIx64 ", NextLength=%08x, "
|
||||
"CurrentStart=%08" PRIx64 ", CurrentLength=%08x, AudioPos=%08" PRIx64,
|
||||
s_next_start, s_next_length, s_current_start, s_current_length, s_audio_position);
|
||||
|
||||
s_audio_position = s_next_start;
|
||||
@@ -362,7 +367,8 @@ static void DTKStreamingCallback(const std::vector<u8>& audio_data, s64 cycles_l
|
||||
ticks_to_dtk -= cycles_late;
|
||||
if (read_length > 0)
|
||||
{
|
||||
DVDThread::StartRead(read_offset, read_length, false, ReplyType::DTK, ticks_to_dtk);
|
||||
DVDThread::StartRead(read_offset, read_length, DiscIO::PARTITION_NONE, ReplyType::DTK,
|
||||
ticks_to_dtk);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -432,6 +438,9 @@ void Shutdown()
|
||||
|
||||
void SetDisc(std::unique_ptr<DiscIO::IVolume> disc)
|
||||
{
|
||||
if (disc)
|
||||
s_current_partition = disc->GetGamePartition();
|
||||
|
||||
DVDThread::SetDisc(std::move(disc));
|
||||
SetLidOpen();
|
||||
}
|
||||
@@ -496,9 +505,33 @@ void SetLidOpen()
|
||||
GenerateDIInterrupt(INT_CVRINT);
|
||||
}
|
||||
|
||||
bool ChangePartition(u64 offset)
|
||||
bool UpdateRunningGameMetadata(u64 title_id)
|
||||
{
|
||||
return DVDThread::ChangePartition(offset);
|
||||
if (!DVDThread::HasDisc())
|
||||
return false;
|
||||
|
||||
const DiscIO::Partition& partition = DVDThread::GetDiscType() == DiscIO::Platform::WII_DISC ?
|
||||
s_current_partition :
|
||||
DiscIO::PARTITION_NONE;
|
||||
|
||||
return DVDThread::UpdateRunningGameMetadata(partition, title_id);
|
||||
}
|
||||
|
||||
bool UpdateRunningGameMetadata()
|
||||
{
|
||||
if (!DVDThread::HasDisc())
|
||||
return false;
|
||||
|
||||
const DiscIO::Partition& partition = DVDThread::GetDiscType() == DiscIO::Platform::WII_DISC ?
|
||||
s_current_partition :
|
||||
DiscIO::PARTITION_NONE;
|
||||
|
||||
return DVDThread::UpdateRunningGameMetadata(partition);
|
||||
}
|
||||
|
||||
void ChangePartition(const DiscIO::Partition& partition)
|
||||
{
|
||||
s_current_partition = partition;
|
||||
}
|
||||
|
||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
@@ -618,8 +651,9 @@ void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios)
|
||||
}
|
||||
|
||||
// Iff false is returned, ScheduleEvent must be used to finish executing the command
|
||||
bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length,
|
||||
bool decrypt, ReplyType reply_type, DIInterruptType* interrupt_type)
|
||||
bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, u32 output_length,
|
||||
const DiscIO::Partition& partition, ReplyType reply_type,
|
||||
DIInterruptType* interrupt_type)
|
||||
{
|
||||
if (!IsDiscInside())
|
||||
{
|
||||
@@ -634,14 +668,14 @@ bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32
|
||||
*interrupt_type = INT_TCINT;
|
||||
}
|
||||
|
||||
if (DVD_length > output_length)
|
||||
if (dvd_length > output_length)
|
||||
{
|
||||
WARN_LOG(DVDINTERFACE, "Detected an attempt to read more data from the DVD "
|
||||
"than what fits inside the out buffer. Clamping.");
|
||||
DVD_length = output_length;
|
||||
dvd_length = output_length;
|
||||
}
|
||||
|
||||
ScheduleReads(DVD_offset, DVD_length, decrypt, output_address, reply_type);
|
||||
ScheduleReads(dvd_offset, dvd_length, partition, output_address, reply_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -677,8 +711,9 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
||||
// Only seems to be used from WII_IPC, not through direct access
|
||||
case DVDLowReadDiskID:
|
||||
INFO_LOG(DVDINTERFACE, "DVDLowReadDiskID");
|
||||
command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false,
|
||||
reply_type, &interrupt_type);
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand(0, output_address, 0x20, output_length, DiscIO::PARTITION_NONE,
|
||||
reply_type, &interrupt_type);
|
||||
break;
|
||||
|
||||
// Only used from WII_IPC. This is the only read command that decrypts data
|
||||
@@ -686,8 +721,8 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
||||
INFO_LOG(DVDINTERFACE, "DVDLowRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2,
|
||||
command_1);
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true,
|
||||
reply_type, &interrupt_type);
|
||||
ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length,
|
||||
s_current_partition, reply_type, &interrupt_type);
|
||||
break;
|
||||
|
||||
// Probably only used by Wii
|
||||
@@ -768,8 +803,8 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
||||
(((command_2 + command_1) > 0x7ed40000) && (command_2 + command_1) < 0x7ed40008)))
|
||||
{
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, false,
|
||||
reply_type, &interrupt_type);
|
||||
ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length,
|
||||
DiscIO::PARTITION_NONE, reply_type, &interrupt_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -813,19 +848,22 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
||||
{
|
||||
u64 iDVDOffset = (u64)command_1 << 2;
|
||||
|
||||
INFO_LOG(DVDINTERFACE, "Read: DVDOffset=%08" PRIx64
|
||||
", DMABuffer = %08x, SrcLength = %08x, DMALength = %08x",
|
||||
INFO_LOG(DVDINTERFACE,
|
||||
"Read: DVDOffset=%08" PRIx64
|
||||
", DMABuffer = %08x, SrcLength = %08x, DMALength = %08x",
|
||||
iDVDOffset, output_address, command_2, output_length);
|
||||
|
||||
command_handled_by_thread = ExecuteReadCommand(
|
||||
iDVDOffset, output_address, command_2, output_length, false, reply_type, &interrupt_type);
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length,
|
||||
DiscIO::PARTITION_NONE, reply_type, &interrupt_type);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x40: // Read DiscID
|
||||
INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address));
|
||||
command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false,
|
||||
reply_type, &interrupt_type);
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand(0, output_address, 0x20, output_length, DiscIO::PARTITION_NONE,
|
||||
reply_type, &interrupt_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -934,9 +972,10 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
||||
switch (command_0 >> 16 & 0xFF)
|
||||
{
|
||||
case 0x00: // Returns streaming status
|
||||
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status "
|
||||
"AudioPos:%08" PRIx64 "/%08" PRIx64 " "
|
||||
"CurrentStart:%08" PRIx64 " CurrentLength:%08x",
|
||||
INFO_LOG(DVDINTERFACE,
|
||||
"(Audio): Stream Status: Request Audio status "
|
||||
"AudioPos:%08" PRIx64 "/%08" PRIx64 " "
|
||||
"CurrentStart:%08" PRIx64 " CurrentLength:%08x",
|
||||
s_audio_position, s_current_start + s_current_length, s_current_start,
|
||||
s_current_length);
|
||||
WriteImmediate(s_stream ? 1 : 0, output_address, reply_to_ios);
|
||||
@@ -1097,7 +1136,8 @@ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type
|
||||
|
||||
// Determines from a given read request how much of the request is buffered,
|
||||
// and how much is required to be read from disc.
|
||||
void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, ReplyType reply_type)
|
||||
void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, u32 output_address,
|
||||
ReplyType reply_type)
|
||||
{
|
||||
// The drive continues to read 1 MiB beyond the last read position when idle.
|
||||
// If a future read falls within this window, part of the read may be returned
|
||||
@@ -1124,9 +1164,7 @@ void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, Rep
|
||||
// The variable dvd_offset tracks the actual offset on the DVD
|
||||
// that the disc drive starts reading at, which differs in two ways:
|
||||
// It's rounded to a whole ECC block and never uses Wii partition addressing.
|
||||
u64 dvd_offset = offset;
|
||||
if (decrypt)
|
||||
dvd_offset = DVDThread::PartitionOffsetToRawOffset(offset);
|
||||
u64 dvd_offset = DiscIO::CVolumeWiiCrypted::PartitionOffsetToRawOffset(offset, partition);
|
||||
dvd_offset = Common::AlignDown(dvd_offset, DVD_ECC_BLOCK_SIZE);
|
||||
|
||||
if (SConfig::GetInstance().bFastDiscSpeed)
|
||||
@@ -1192,8 +1230,9 @@ void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, Rep
|
||||
u32 buffered_blocks = 0;
|
||||
u32 unbuffered_blocks = 0;
|
||||
|
||||
const u32 bytes_per_chunk =
|
||||
decrypt ? DiscIO::CVolumeWiiCrypted::BLOCK_DATA_SIZE : DVD_ECC_BLOCK_SIZE;
|
||||
const u32 bytes_per_chunk = partition == DiscIO::PARTITION_NONE ?
|
||||
DVD_ECC_BLOCK_SIZE :
|
||||
DiscIO::CVolumeWiiCrypted::BLOCK_DATA_SIZE;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
@@ -1240,7 +1279,7 @@ void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, Rep
|
||||
|
||||
// Schedule this read to complete at the appropriate time
|
||||
const ReplyType chunk_reply_type = chunk_length == length ? reply_type : ReplyType::NoReply;
|
||||
DVDThread::StartReadToEmulatedRAM(output_address, offset, chunk_length, decrypt,
|
||||
DVDThread::StartReadToEmulatedRAM(output_address, offset, chunk_length, partition,
|
||||
chunk_reply_type, ticks_until_completion);
|
||||
|
||||
// Advance the read window
|
||||
@@ -1280,8 +1319,9 @@ void ScheduleReads(u64 offset, u32 length, bool decrypt, u32 output_address, Rep
|
||||
s_read_buffer_end_offset - s_read_buffer_start_offset, wii_disc));
|
||||
}
|
||||
|
||||
DEBUG_LOG(DVDINTERFACE, "Schedule reads: ECC blocks unbuffered=%d, buffered=%d, "
|
||||
"ticks=%" PRId64 ", time=%" PRId64 " us",
|
||||
DEBUG_LOG(DVDINTERFACE,
|
||||
"Schedule reads: ECC blocks unbuffered=%d, buffered=%d, "
|
||||
"ticks=%" PRId64 ", time=%" PRId64 " us",
|
||||
unbuffered_blocks, buffered_blocks, ticks_until_completion,
|
||||
ticks_until_completion * 1000000 / SystemTimers::GetTicksPerSecond());
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class PointerWrap;
|
||||
namespace DiscIO
|
||||
{
|
||||
class IVolume;
|
||||
struct Partition;
|
||||
}
|
||||
namespace MMIO
|
||||
{
|
||||
@@ -113,9 +114,16 @@ bool IsDiscInside();
|
||||
void ChangeDiscAsHost(const std::string& new_path); // Can only be called by the host thread
|
||||
void ChangeDiscAsCPU(const std::string& new_path); // Can only be called by the CPU thread
|
||||
|
||||
// If a disc is inserted and its title ID is equal to the title_id argument, returns true and
|
||||
// calls SConfig::SetRunningGameMetadata(IVolume&, Partition&). Otherwise, returns false.
|
||||
bool UpdateRunningGameMetadata(u64 title_id);
|
||||
// If a disc is inserted, returns true and calls
|
||||
// SConfig::SetRunningGameMetadata(IVolume&, Partition&). Otherwise, returns false.
|
||||
bool UpdateRunningGameMetadata();
|
||||
|
||||
// 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)
|
||||
bool ChangePartition(u64 offset);
|
||||
void ChangePartition(const DiscIO::Partition& partition);
|
||||
void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address,
|
||||
u32 output_length, bool reply_to_ios);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ struct ReadRequest
|
||||
u32 output_address;
|
||||
u64 dvd_offset;
|
||||
u32 length;
|
||||
bool decrypt;
|
||||
DiscIO::Partition partition;
|
||||
|
||||
// This determines which code DVDInterface will run to reply
|
||||
// to the emulated software. We can't use callbacks,
|
||||
@@ -68,8 +68,8 @@ static void DVDThread();
|
||||
static void WaitUntilIdle();
|
||||
|
||||
static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
|
||||
bool decrypt, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion);
|
||||
const DiscIO::Partition& partition,
|
||||
DVDInterface::ReplyType reply_type, s64 ticks_until_completion);
|
||||
|
||||
static void FinishRead(u64 id, s64 cycles_late);
|
||||
static CoreTiming::EventType* s_finish_read;
|
||||
@@ -191,42 +191,25 @@ bool HasDisc()
|
||||
return s_disc != nullptr;
|
||||
}
|
||||
|
||||
u64 PartitionOffsetToRawOffset(u64 offset)
|
||||
{
|
||||
// This is thread-safe as long as the partition currently isn't being changed,
|
||||
// and that isn't supposed to be happening while running this function, because both
|
||||
// this function and ChangePartition are only supposed to be called on the CPU thread.
|
||||
_assert_(Core::IsCPUThread());
|
||||
return s_disc->PartitionOffsetToRawOffset(offset);
|
||||
}
|
||||
|
||||
DiscIO::Platform GetDiscType()
|
||||
{
|
||||
// GetVolumeType is thread-safe, so calling WaitUntilIdle isn't necessary.
|
||||
return s_disc->GetVolumeType();
|
||||
}
|
||||
|
||||
IOS::ES::TMDReader GetTMD()
|
||||
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition)
|
||||
{
|
||||
WaitUntilIdle();
|
||||
return s_disc->GetTMD();
|
||||
return s_disc->GetTMD(partition);
|
||||
}
|
||||
|
||||
IOS::ES::TicketReader GetTicket()
|
||||
IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition)
|
||||
{
|
||||
WaitUntilIdle();
|
||||
return s_disc->GetTicket();
|
||||
return s_disc->GetTicket(partition);
|
||||
}
|
||||
|
||||
bool ChangePartition(u64 offset)
|
||||
{
|
||||
WaitUntilIdle();
|
||||
const bool success = s_disc->ChangePartition(offset);
|
||||
FileMonitor::SetFileSystem(s_disc.get());
|
||||
return success;
|
||||
}
|
||||
|
||||
bool UpdateRunningGameMetadata(u64 title_id)
|
||||
bool UpdateRunningGameMetadata(const DiscIO::Partition& partition, u64 title_id)
|
||||
{
|
||||
if (!s_disc)
|
||||
return false;
|
||||
@@ -234,24 +217,24 @@ bool UpdateRunningGameMetadata(u64 title_id)
|
||||
WaitUntilIdle();
|
||||
|
||||
u64 volume_title_id;
|
||||
if (!s_disc->GetTitleID(&volume_title_id))
|
||||
if (!s_disc->GetTitleID(&volume_title_id, partition))
|
||||
return false;
|
||||
|
||||
if (volume_title_id != title_id)
|
||||
return false;
|
||||
|
||||
SConfig::GetInstance().SetRunningGameMetadata(*s_disc);
|
||||
SConfig::GetInstance().SetRunningGameMetadata(*s_disc, partition);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdateRunningGameMetadata()
|
||||
bool UpdateRunningGameMetadata(const DiscIO::Partition& partition)
|
||||
{
|
||||
if (!s_disc)
|
||||
return false;
|
||||
|
||||
DVDThread::WaitUntilIdle();
|
||||
|
||||
SConfig::GetInstance().SetRunningGameMetadata(*s_disc);
|
||||
SConfig::GetInstance().SetRunningGameMetadata(*s_disc, partition);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -266,22 +249,23 @@ void WaitUntilIdle()
|
||||
StartDVDThread();
|
||||
}
|
||||
|
||||
void StartRead(u64 dvd_offset, u32 length, bool decrypt, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion)
|
||||
void StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
|
||||
DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
|
||||
{
|
||||
StartReadInternal(false, 0, dvd_offset, length, decrypt, reply_type, ticks_until_completion);
|
||||
StartReadInternal(false, 0, dvd_offset, length, partition, reply_type, ticks_until_completion);
|
||||
}
|
||||
|
||||
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length, bool decrypt,
|
||||
DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
|
||||
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
|
||||
const DiscIO::Partition& partition, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion)
|
||||
{
|
||||
StartReadInternal(true, output_address, dvd_offset, length, decrypt, reply_type,
|
||||
StartReadInternal(true, output_address, dvd_offset, length, partition, reply_type,
|
||||
ticks_until_completion);
|
||||
}
|
||||
|
||||
static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
|
||||
bool decrypt, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion)
|
||||
const DiscIO::Partition& partition,
|
||||
DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
|
||||
{
|
||||
_assert_(Core::IsCPUThread());
|
||||
|
||||
@@ -291,7 +275,7 @@ static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offs
|
||||
request.output_address = output_address;
|
||||
request.dvd_offset = dvd_offset;
|
||||
request.length = length;
|
||||
request.decrypt = decrypt;
|
||||
request.partition = partition;
|
||||
request.reply_type = reply_type;
|
||||
|
||||
u64 id = s_next_id++;
|
||||
@@ -381,10 +365,10 @@ static void DVDThread()
|
||||
ReadRequest request;
|
||||
while (s_request_queue.Pop(request))
|
||||
{
|
||||
FileMonitor::Log(request.dvd_offset, request.decrypt);
|
||||
FileMonitor::Log(request.dvd_offset, request.partition);
|
||||
|
||||
std::vector<u8> buffer(request.length);
|
||||
if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.decrypt))
|
||||
if (!s_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))
|
||||
buffer.resize(0);
|
||||
|
||||
request.realtime_done_us = Common::Timer::GetTimeUs();
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class PointerWrap;
|
||||
namespace DiscIO
|
||||
{
|
||||
struct Partition;
|
||||
}
|
||||
namespace DVDInterface
|
||||
{
|
||||
enum class ReplyType : u32;
|
||||
@@ -37,20 +41,19 @@ void DoState(PointerWrap& p);
|
||||
void SetDisc(std::unique_ptr<DiscIO::IVolume> disc);
|
||||
bool HasDisc();
|
||||
|
||||
u64 PartitionOffsetToRawOffset(u64 offset);
|
||||
DiscIO::Platform GetDiscType();
|
||||
IOS::ES::TMDReader GetTMD();
|
||||
IOS::ES::TicketReader GetTicket();
|
||||
bool ChangePartition(u64 offset);
|
||||
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition);
|
||||
IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition);
|
||||
// If a disc is inserted and its title ID is equal to the title_id argument, returns true and
|
||||
// calls SConfig::SetRunningGameMetadata(IVolume&). Otherwise, returns false.
|
||||
bool UpdateRunningGameMetadata(u64 title_id);
|
||||
// calls SConfig::SetRunningGameMetadata(IVolume&, Partition&). Otherwise, returns false.
|
||||
bool UpdateRunningGameMetadata(const DiscIO::Partition& partition, u64 title_id);
|
||||
// If a disc is inserted, returns true and calls
|
||||
// SConfig::SetRunningGameMetadata(IVolume&). Otherwise, returns false.
|
||||
bool UpdateRunningGameMetadata();
|
||||
// SConfig::SetRunningGameMetadata(IVolume&, Partition&). Otherwise, returns false.
|
||||
bool UpdateRunningGameMetadata(const DiscIO::Partition& partition);
|
||||
|
||||
void StartRead(u64 dvd_offset, u32 length, bool decrypt, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion);
|
||||
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length, bool decrypt,
|
||||
DVDInterface::ReplyType reply_type, s64 ticks_until_completion);
|
||||
void StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
|
||||
DVDInterface::ReplyType reply_type, s64 ticks_until_completion);
|
||||
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
|
||||
const DiscIO::Partition& partition, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion);
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@
|
||||
|
||||
namespace FileMonitor
|
||||
{
|
||||
static const DiscIO::IVolume* s_volume = nullptr;
|
||||
static bool s_wii_disc;
|
||||
static const DiscIO::IVolume* s_volume;
|
||||
static bool s_new_volume = false;
|
||||
static std::unique_ptr<DiscIO::IFileSystem> s_filesystem;
|
||||
static DiscIO::Partition s_partition;
|
||||
static std::string s_previous_file;
|
||||
|
||||
// Filtered files
|
||||
@@ -57,34 +58,31 @@ void SetFileSystem(const DiscIO::IVolume* volume)
|
||||
// Instead of creating the file system object right away, we will let Log
|
||||
// create it later once we know that it actually will get used
|
||||
s_volume = volume;
|
||||
|
||||
// If the volume that was passed in was nullptr, Log won't try to create a
|
||||
// file system object later, so we have to set s_filesystem to nullptr right away
|
||||
s_filesystem = nullptr;
|
||||
s_new_volume = true;
|
||||
}
|
||||
|
||||
// Logs access to files in the file system set by SetFileSystem
|
||||
void Log(u64 offset, bool decrypt)
|
||||
void Log(u64 offset, const DiscIO::Partition& partition)
|
||||
{
|
||||
// Do nothing if the log isn't selected
|
||||
if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON, LogTypes::LWARNING))
|
||||
return;
|
||||
|
||||
// If a new volume has been set, use the file system of that volume
|
||||
if (s_volume)
|
||||
// If the volume or partition changed, load the filesystem of the new partition
|
||||
if (s_new_volume || s_partition != partition)
|
||||
{
|
||||
s_wii_disc = s_volume->GetVolumeType() == DiscIO::Platform::WII_DISC;
|
||||
if (decrypt != s_wii_disc)
|
||||
// Wii discs don't have PARTITION_NONE filesystems, so let's not waste time trying to read one
|
||||
const bool reading_from_partition = partition != DiscIO::PARTITION_NONE;
|
||||
const bool is_wii_disc = s_volume->GetVolumeType() == DiscIO::Platform::WII_DISC;
|
||||
if (reading_from_partition != is_wii_disc)
|
||||
return;
|
||||
s_filesystem = DiscIO::CreateFileSystem(s_volume);
|
||||
s_volume = nullptr;
|
||||
|
||||
s_new_volume = false;
|
||||
s_filesystem = DiscIO::CreateFileSystem(s_volume, partition);
|
||||
s_partition = partition;
|
||||
s_previous_file.clear();
|
||||
}
|
||||
|
||||
// For Wii discs, FileSystemGCWii will only load file systems from encrypted partitions
|
||||
if (decrypt != s_wii_disc)
|
||||
return;
|
||||
|
||||
// Do nothing if there is no valid file system
|
||||
if (!s_filesystem)
|
||||
return;
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
class IFileSystem;
|
||||
struct Partition;
|
||||
class IVolume;
|
||||
}
|
||||
|
||||
@@ -20,5 +18,5 @@ namespace FileMonitor
|
||||
// with nullptr, the volume must remain valid until the next SetFileSystem call.
|
||||
void SetFileSystem(const DiscIO::IVolume* volume);
|
||||
// Logs access to files in the file system set by SetFileSystem
|
||||
void Log(u64 offset, bool decrypt);
|
||||
void Log(u64 offset, const DiscIO::Partition& partition);
|
||||
}
|
||||
|
||||
@@ -101,16 +101,18 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request)
|
||||
_dbg_assert_msg_(IOS_DI, request.in_vectors[2].address == 0,
|
||||
"DVDLowOpenPartition with cert chain");
|
||||
|
||||
u64 const partition_offset = ((u64)Memory::Read_U32(request.in_vectors[0].address + 4) << 2);
|
||||
DVDInterface::ChangePartition(partition_offset);
|
||||
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);
|
||||
|
||||
INFO_LOG(IOS_DI, "DVDLowOpenPartition: partition_offset 0x%016" PRIx64, partition_offset);
|
||||
|
||||
// Read TMD to the buffer
|
||||
const IOS::ES::TMDReader tmd = DVDThread::GetTMD();
|
||||
const IOS::ES::TMDReader tmd = DVDThread::GetTMD(partition);
|
||||
const std::vector<u8> raw_tmd = tmd.GetRawTMD();
|
||||
Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
|
||||
ES::DIVerify(tmd, DVDThread::GetTicket());
|
||||
ES::DIVerify(tmd, DVDThread::GetTicket(partition));
|
||||
|
||||
return_value = 1;
|
||||
break;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HW/DSP.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
#include "Core/HW/DVD/DVDThread.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
@@ -170,7 +169,7 @@ bool Load()
|
||||
Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
|
||||
NOTICE_LOG(IOS, "IPL ready.");
|
||||
SConfig::GetInstance().m_BootType = SConfig::BOOT_MIOS;
|
||||
DVDThread::UpdateRunningGameMetadata();
|
||||
DVDInterface::UpdateRunningGameMetadata();
|
||||
return true;
|
||||
}
|
||||
} // namespace MIOS
|
||||
|
||||
@@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
||||
static std::thread g_save_thread;
|
||||
|
||||
// Don't forget to increase this after doing changes on the savestate system
|
||||
static const u32 STATE_VERSION = 85; // Last changed in PR 4241
|
||||
static const u32 STATE_VERSION = 86; // Last changed in PR 2353
|
||||
|
||||
// Maps savestate versions to Dolphin versions.
|
||||
// Versions after 42 don't need to be added to this list,
|
||||
|
||||
@@ -123,15 +123,15 @@ void DiscScrubber::MarkAsUsedE(u64 partition_data_offset, u64 offset, u64 size)
|
||||
}
|
||||
|
||||
// Helper functions for reading the BE volume
|
||||
bool DiscScrubber::ReadFromVolume(u64 offset, u32& buffer, bool decrypt)
|
||||
bool DiscScrubber::ReadFromVolume(u64 offset, u32& buffer, const Partition& partition)
|
||||
{
|
||||
return m_disc->ReadSwapped(offset, &buffer, decrypt);
|
||||
return m_disc->ReadSwapped(offset, &buffer, partition);
|
||||
}
|
||||
|
||||
bool DiscScrubber::ReadFromVolume(u64 offset, u64& buffer, bool decrypt)
|
||||
bool DiscScrubber::ReadFromVolume(u64 offset, u64& buffer, const Partition& partition)
|
||||
{
|
||||
u32 temp_buffer;
|
||||
if (!m_disc->ReadSwapped(offset, &temp_buffer, decrypt))
|
||||
if (!m_disc->ReadSwapped(offset, &temp_buffer, partition))
|
||||
return false;
|
||||
buffer = static_cast<u64>(temp_buffer) << 2;
|
||||
return true;
|
||||
@@ -142,126 +142,85 @@ bool DiscScrubber::ParseDisc()
|
||||
// Mark the header as used - it's mostly 0s anyways
|
||||
MarkAsUsed(0, 0x50000);
|
||||
|
||||
for (u32 x = 0; x < 4; x++)
|
||||
for (const DiscIO::Partition& partition : m_disc->GetPartitions())
|
||||
{
|
||||
if (!ReadFromVolume(0x40000 + (x * 8) + 0, m_partition_group[x].num_partitions, false) ||
|
||||
!ReadFromVolume(0x40000 + (x * 8) + 4, m_partition_group[x].partitions_offset, false))
|
||||
PartitionHeader header;
|
||||
|
||||
if (!ReadFromVolume(partition.offset + 0x2a4, header.tmd_size, PARTITION_NONE) ||
|
||||
!ReadFromVolume(partition.offset + 0x2a8, header.tmd_offset, PARTITION_NONE) ||
|
||||
!ReadFromVolume(partition.offset + 0x2ac, header.cert_chain_size, PARTITION_NONE) ||
|
||||
!ReadFromVolume(partition.offset + 0x2b0, header.cert_chain_offset, PARTITION_NONE) ||
|
||||
!ReadFromVolume(partition.offset + 0x2b4, header.h3_offset, PARTITION_NONE) ||
|
||||
!ReadFromVolume(partition.offset + 0x2b8, header.data_offset, PARTITION_NONE) ||
|
||||
!ReadFromVolume(partition.offset + 0x2bc, header.data_size, PARTITION_NONE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read all partitions
|
||||
for (u32 i = 0; i < m_partition_group[x].num_partitions; i++)
|
||||
{
|
||||
Partition partition;
|
||||
MarkAsUsed(partition.offset, 0x2c0);
|
||||
|
||||
partition.group_number = x;
|
||||
partition.number = i;
|
||||
MarkAsUsed(partition.offset + header.tmd_offset, header.tmd_size);
|
||||
MarkAsUsed(partition.offset + header.cert_chain_offset, header.cert_chain_size);
|
||||
MarkAsUsed(partition.offset + header.h3_offset, 0x18000);
|
||||
// This would mark the whole (encrypted) data area
|
||||
// we need to parse FST and other crap to find what's free within it!
|
||||
// MarkAsUsed(partition.offset + header.data_offset, header.data_size);
|
||||
|
||||
if (!ReadFromVolume(m_partition_group[x].partitions_offset + (i * 8) + 0, partition.offset,
|
||||
false) ||
|
||||
!ReadFromVolume(m_partition_group[x].partitions_offset + (i * 8) + 4, partition.type,
|
||||
false) ||
|
||||
!ReadFromVolume(partition.offset + 0x2a4, partition.header.tmd_size, false) ||
|
||||
!ReadFromVolume(partition.offset + 0x2a8, partition.header.tmd_offset, false) ||
|
||||
!ReadFromVolume(partition.offset + 0x2ac, partition.header.cert_chain_size, false) ||
|
||||
!ReadFromVolume(partition.offset + 0x2b0, partition.header.cert_chain_offset, false) ||
|
||||
!ReadFromVolume(partition.offset + 0x2b4, partition.header.h3_offset, false) ||
|
||||
!ReadFromVolume(partition.offset + 0x2b8, partition.header.data_offset, false) ||
|
||||
!ReadFromVolume(partition.offset + 0x2bc, partition.header.data_size, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_partition_group[x].partitions.push_back(partition);
|
||||
}
|
||||
|
||||
for (auto& partition : m_partition_group[x].partitions)
|
||||
{
|
||||
const PartitionHeader& header = partition.header;
|
||||
|
||||
MarkAsUsed(partition.offset, 0x2c0);
|
||||
|
||||
MarkAsUsed(partition.offset + header.tmd_offset, header.tmd_size);
|
||||
MarkAsUsed(partition.offset + header.cert_chain_offset, header.cert_chain_size);
|
||||
MarkAsUsed(partition.offset + header.h3_offset, 0x18000);
|
||||
// This would mark the whole (encrypted) data area
|
||||
// we need to parse FST and other crap to find what's free within it!
|
||||
// MarkAsUsed(partition.offset + header.data_offset, header.data_size);
|
||||
|
||||
// Parse Data! This is where the big gain is
|
||||
if (!ParsePartitionData(partition))
|
||||
return false;
|
||||
}
|
||||
// Parse Data! This is where the big gain is
|
||||
if (!ParsePartitionData(partition, &header))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Operations dealing with encrypted space are done here - the volume is swapped to allow this
|
||||
bool DiscScrubber::ParsePartitionData(Partition& partition)
|
||||
// Operations dealing with encrypted space are done here
|
||||
bool DiscScrubber::ParsePartitionData(const Partition& partition, PartitionHeader* header)
|
||||
{
|
||||
bool parsed_ok = true;
|
||||
|
||||
// Switch out the main volume temporarily
|
||||
std::unique_ptr<IVolume> old_volume;
|
||||
m_disc.swap(old_volume);
|
||||
|
||||
// Ready some stuff
|
||||
m_disc = CreateVolumeFromFilename(m_filename, partition.group_number, partition.number);
|
||||
if (m_disc == nullptr)
|
||||
std::unique_ptr<IFileSystem> filesystem(CreateFileSystem(m_disc.get(), partition));
|
||||
if (!filesystem)
|
||||
{
|
||||
ERROR_LOG(DISCIO, "Failed to create volume from file %s", m_filename.c_str());
|
||||
m_disc.swap(old_volume);
|
||||
ERROR_LOG(DISCIO, "Failed to read file system for the partition at 0x%" PRIx64,
|
||||
partition.offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<IFileSystem> filesystem(CreateFileSystem(m_disc.get()));
|
||||
if (!filesystem)
|
||||
const u64 partition_data_offset = partition.offset + header->data_offset;
|
||||
|
||||
// Mark things as used which are not in the filesystem
|
||||
// Header, Header Information, Apploader
|
||||
if (!ReadFromVolume(0x2440 + 0x14, header->apploader_size, partition) ||
|
||||
!ReadFromVolume(0x2440 + 0x18, header->apploader_size, partition))
|
||||
{
|
||||
ERROR_LOG(DISCIO, "Failed to create filesystem for group %u partition %u",
|
||||
partition.group_number, partition.number);
|
||||
parsed_ok = false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
MarkAsUsedE(partition_data_offset, 0,
|
||||
0x2440 + header->apploader_size + header->apploader_trailer_size);
|
||||
|
||||
// DOL
|
||||
header->dol_offset = filesystem->GetBootDOLOffset();
|
||||
header->dol_size = filesystem->GetBootDOLSize(header->dol_offset);
|
||||
if (header->dol_offset == 0 || header->dol_size == 0)
|
||||
return false;
|
||||
MarkAsUsedE(partition_data_offset, header->dol_offset, header->dol_size);
|
||||
|
||||
// FST
|
||||
if (!ReadFromVolume(0x424, header->fst_offset, partition) ||
|
||||
!ReadFromVolume(0x428, header->fst_size, partition))
|
||||
{
|
||||
// Mark things as used which are not in the filesystem
|
||||
// Header, Header Information, Apploader
|
||||
parsed_ok = parsed_ok && ReadFromVolume(0x2440 + 0x14, partition.header.apploader_size, true);
|
||||
parsed_ok =
|
||||
parsed_ok && ReadFromVolume(0x2440 + 0x18, partition.header.apploader_trailer_size, true);
|
||||
MarkAsUsedE(partition.offset + partition.header.data_offset, 0,
|
||||
0x2440 + partition.header.apploader_size + partition.header.apploader_trailer_size);
|
||||
return false;
|
||||
}
|
||||
MarkAsUsedE(partition_data_offset, header->fst_offset, header->fst_size);
|
||||
|
||||
// DOL
|
||||
partition.header.dol_offset = filesystem->GetBootDOLOffset();
|
||||
partition.header.dol_size = filesystem->GetBootDOLSize(partition.header.dol_offset);
|
||||
parsed_ok = parsed_ok && partition.header.dol_offset && partition.header.dol_size;
|
||||
MarkAsUsedE(partition.offset + partition.header.data_offset, partition.header.dol_offset,
|
||||
partition.header.dol_size);
|
||||
|
||||
// FST
|
||||
parsed_ok = parsed_ok && ReadFromVolume(0x424, partition.header.fst_offset, true);
|
||||
parsed_ok = parsed_ok && ReadFromVolume(0x428, partition.header.fst_size, true);
|
||||
MarkAsUsedE(partition.offset + partition.header.data_offset, partition.header.fst_offset,
|
||||
partition.header.fst_size);
|
||||
|
||||
// Go through the filesystem and mark entries as used
|
||||
for (const SFileInfo& file : filesystem->GetFileList())
|
||||
{
|
||||
DEBUG_LOG(DISCIO, "%s", file.m_FullPath.empty() ? "/" : file.m_FullPath.c_str());
|
||||
if ((file.m_NameOffset & 0x1000000) == 0)
|
||||
{
|
||||
MarkAsUsedE(partition.offset + partition.header.data_offset, file.m_Offset,
|
||||
file.m_FileSize);
|
||||
}
|
||||
}
|
||||
// Go through the filesystem and mark entries as used
|
||||
for (const SFileInfo& file : filesystem->GetFileList())
|
||||
{
|
||||
DEBUG_LOG(DISCIO, "%s", file.m_FullPath.empty() ? "/" : file.m_FullPath.c_str());
|
||||
if ((file.m_NameOffset & 0x1000000) == 0)
|
||||
MarkAsUsedE(partition_data_offset, file.m_Offset, file.m_FileSize);
|
||||
}
|
||||
|
||||
// Swap back
|
||||
m_disc.swap(old_volume);
|
||||
|
||||
return parsed_ok;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace DiscIO
|
||||
|
||||
@@ -26,6 +26,7 @@ class IOFile;
|
||||
namespace DiscIO
|
||||
{
|
||||
class IVolume;
|
||||
struct Partition;
|
||||
|
||||
class DiscScrubber final
|
||||
{
|
||||
@@ -57,34 +58,16 @@ private:
|
||||
u32 apploader_trailer_size;
|
||||
};
|
||||
|
||||
struct Partition final
|
||||
{
|
||||
u32 group_number;
|
||||
u32 number;
|
||||
u64 offset;
|
||||
u32 type;
|
||||
PartitionHeader header;
|
||||
};
|
||||
|
||||
struct PartitionGroup final
|
||||
{
|
||||
u32 num_partitions;
|
||||
u64 partitions_offset;
|
||||
std::vector<Partition> partitions;
|
||||
};
|
||||
|
||||
void MarkAsUsed(u64 offset, u64 size);
|
||||
void MarkAsUsedE(u64 partition_data_offset, u64 offset, u64 size);
|
||||
bool ReadFromVolume(u64 offset, u32& buffer, bool decrypt);
|
||||
bool ReadFromVolume(u64 offset, u64& buffer, bool decrypt);
|
||||
bool ReadFromVolume(u64 offset, u32& buffer, const Partition& partition);
|
||||
bool ReadFromVolume(u64 offset, u64& buffer, const Partition& partition);
|
||||
bool ParseDisc();
|
||||
bool ParsePartitionData(Partition& partition);
|
||||
bool ParsePartitionData(const Partition& partition, PartitionHeader* header);
|
||||
|
||||
std::string m_filename;
|
||||
std::unique_ptr<IVolume> m_disc;
|
||||
|
||||
std::array<PartitionGroup, 4> m_partition_group{};
|
||||
|
||||
std::vector<u8> m_free_table;
|
||||
u64 m_file_size = 0;
|
||||
u64 m_block_count = 0;
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
CFileSystemGCWii::CFileSystemGCWii(const IVolume* _rVolume)
|
||||
: IFileSystem(_rVolume), m_Initialized(false), m_Valid(false), m_Wii(false)
|
||||
CFileSystemGCWii::CFileSystemGCWii(const IVolume* _rVolume, const Partition& partition)
|
||||
: IFileSystem(_rVolume, partition), m_Initialized(false), m_Valid(false), m_Wii(false)
|
||||
{
|
||||
m_Valid = DetectFileSystem();
|
||||
}
|
||||
@@ -80,7 +80,7 @@ u64 CFileSystemGCWii::ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64
|
||||
read_length, _OffsetInFile, _rFullPath.c_str(), pFileInfo->m_Offset,
|
||||
pFileInfo->m_FileSize);
|
||||
|
||||
m_rVolume->Read(pFileInfo->m_Offset + _OffsetInFile, read_length, _pBuffer, m_Wii);
|
||||
m_rVolume->Read(pFileInfo->m_Offset + _OffsetInFile, read_length, _pBuffer, m_partition);
|
||||
return read_length;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ bool CFileSystemGCWii::ExportFile(const std::string& _rFullPath,
|
||||
|
||||
std::vector<u8> buffer(readSize);
|
||||
|
||||
result = m_rVolume->Read(fileOffset, readSize, &buffer[0], m_Wii);
|
||||
result = m_rVolume->Read(fileOffset, readSize, &buffer[0], m_partition);
|
||||
|
||||
if (!result)
|
||||
break;
|
||||
@@ -130,14 +130,14 @@ bool CFileSystemGCWii::ExportApploader(const std::string& _rExportFolder) const
|
||||
u32 apploader_size;
|
||||
u32 trailer_size;
|
||||
const u32 header_size = 0x20;
|
||||
if (!m_rVolume->ReadSwapped(0x2440 + 0x14, &apploader_size, m_Wii) ||
|
||||
!m_rVolume->ReadSwapped(0x2440 + 0x18, &trailer_size, m_Wii))
|
||||
if (!m_rVolume->ReadSwapped(0x2440 + 0x14, &apploader_size, m_partition) ||
|
||||
!m_rVolume->ReadSwapped(0x2440 + 0x18, &trailer_size, m_partition))
|
||||
return false;
|
||||
apploader_size += trailer_size + header_size;
|
||||
DEBUG_LOG(DISCIO, "Apploader size -> %x", apploader_size);
|
||||
|
||||
std::vector<u8> buffer(apploader_size);
|
||||
if (m_rVolume->Read(0x2440, apploader_size, buffer.data(), m_Wii))
|
||||
if (m_rVolume->Read(0x2440, apploader_size, buffer.data(), m_partition))
|
||||
{
|
||||
std::string exportName(_rExportFolder + "/apploader.img");
|
||||
|
||||
@@ -155,7 +155,7 @@ bool CFileSystemGCWii::ExportApploader(const std::string& _rExportFolder) const
|
||||
u64 CFileSystemGCWii::GetBootDOLOffset() const
|
||||
{
|
||||
u32 offset = 0;
|
||||
m_rVolume->ReadSwapped(0x420, &offset, m_Wii);
|
||||
m_rVolume->ReadSwapped(0x420, &offset, m_partition);
|
||||
return static_cast<u64>(offset) << GetOffsetShift();
|
||||
}
|
||||
|
||||
@@ -173,8 +173,8 @@ u32 CFileSystemGCWii::GetBootDOLSize(u64 dol_offset) const
|
||||
// Iterate through the 7 code segments
|
||||
for (u8 i = 0; i < 7; i++)
|
||||
{
|
||||
if (!m_rVolume->ReadSwapped(dol_offset + 0x00 + i * 4, &offset, m_Wii) ||
|
||||
!m_rVolume->ReadSwapped(dol_offset + 0x90 + i * 4, &size, m_Wii))
|
||||
if (!m_rVolume->ReadSwapped(dol_offset + 0x00 + i * 4, &offset, m_partition) ||
|
||||
!m_rVolume->ReadSwapped(dol_offset + 0x90 + i * 4, &size, m_partition))
|
||||
return 0;
|
||||
dol_size = std::max(offset + size, dol_size);
|
||||
}
|
||||
@@ -182,8 +182,8 @@ u32 CFileSystemGCWii::GetBootDOLSize(u64 dol_offset) const
|
||||
// Iterate through the 11 data segments
|
||||
for (u8 i = 0; i < 11; i++)
|
||||
{
|
||||
if (!m_rVolume->ReadSwapped(dol_offset + 0x1c + i * 4, &offset, m_Wii) ||
|
||||
!m_rVolume->ReadSwapped(dol_offset + 0xac + i * 4, &size, m_Wii))
|
||||
if (!m_rVolume->ReadSwapped(dol_offset + 0x1c + i * 4, &offset, m_partition) ||
|
||||
!m_rVolume->ReadSwapped(dol_offset + 0xac + i * 4, &size, m_partition))
|
||||
return 0;
|
||||
dol_size = std::max(offset + size, dol_size);
|
||||
}
|
||||
@@ -200,7 +200,7 @@ bool CFileSystemGCWii::ExportDOL(const std::string& _rExportFolder) const
|
||||
return false;
|
||||
|
||||
std::vector<u8> buffer(DolSize);
|
||||
if (m_rVolume->Read(DolOffset, DolSize, &buffer[0], m_Wii))
|
||||
if (m_rVolume->Read(DolOffset, DolSize, &buffer[0], m_partition))
|
||||
{
|
||||
std::string exportName(_rExportFolder + "/boot.dol");
|
||||
|
||||
@@ -218,7 +218,7 @@ bool CFileSystemGCWii::ExportDOL(const std::string& _rExportFolder) const
|
||||
std::string CFileSystemGCWii::GetStringFromOffset(u64 _Offset) const
|
||||
{
|
||||
std::string data(255, 0x00);
|
||||
m_rVolume->Read(_Offset, data.size(), (u8*)&data[0], m_Wii);
|
||||
m_rVolume->Read(_Offset, data.size(), (u8*)&data[0], m_partition);
|
||||
data.erase(std::find(data.begin(), data.end(), 0x00), data.end());
|
||||
|
||||
// TODO: Should we really always use SHIFT-JIS?
|
||||
@@ -251,12 +251,12 @@ const SFileInfo* CFileSystemGCWii::FindFileInfo(const std::string& _rFullPath)
|
||||
bool CFileSystemGCWii::DetectFileSystem()
|
||||
{
|
||||
u32 magic_bytes;
|
||||
if (m_rVolume->ReadSwapped(0x18, &magic_bytes, false) && magic_bytes == 0x5D1C9EA3)
|
||||
if (m_rVolume->ReadSwapped(0x18, &magic_bytes, m_partition) && magic_bytes == 0x5D1C9EA3)
|
||||
{
|
||||
m_Wii = true;
|
||||
return true;
|
||||
}
|
||||
else if (m_rVolume->ReadSwapped(0x1c, &magic_bytes, false) && magic_bytes == 0xC2339F3D)
|
||||
else if (m_rVolume->ReadSwapped(0x1c, &magic_bytes, m_partition) && magic_bytes == 0xC2339F3D)
|
||||
{
|
||||
m_Wii = false;
|
||||
return true;
|
||||
@@ -272,15 +272,15 @@ void CFileSystemGCWii::InitFileSystem()
|
||||
|
||||
// read the whole FST
|
||||
u32 fst_offset_unshifted;
|
||||
if (!m_rVolume->ReadSwapped(0x424, &fst_offset_unshifted, m_Wii))
|
||||
if (!m_rVolume->ReadSwapped(0x424, &fst_offset_unshifted, m_partition))
|
||||
return;
|
||||
u64 FSTOffset = static_cast<u64>(fst_offset_unshifted) << shift;
|
||||
|
||||
// read all fileinfos
|
||||
u32 name_offset, offset, size;
|
||||
if (!m_rVolume->ReadSwapped(FSTOffset + 0x0, &name_offset, m_Wii) ||
|
||||
!m_rVolume->ReadSwapped(FSTOffset + 0x4, &offset, m_Wii) ||
|
||||
!m_rVolume->ReadSwapped(FSTOffset + 0x8, &size, m_Wii))
|
||||
if (!m_rVolume->ReadSwapped(FSTOffset + 0x0, &name_offset, m_partition) ||
|
||||
!m_rVolume->ReadSwapped(FSTOffset + 0x4, &offset, m_partition) ||
|
||||
!m_rVolume->ReadSwapped(FSTOffset + 0x8, &size, m_partition))
|
||||
return;
|
||||
SFileInfo root = {name_offset, static_cast<u64>(offset) << shift, size};
|
||||
|
||||
@@ -308,11 +308,11 @@ void CFileSystemGCWii::InitFileSystem()
|
||||
{
|
||||
const u64 read_offset = FSTOffset + (i * 0xC);
|
||||
name_offset = 0;
|
||||
m_rVolume->ReadSwapped(read_offset + 0x0, &name_offset, m_Wii);
|
||||
m_rVolume->ReadSwapped(read_offset + 0x0, &name_offset, m_partition);
|
||||
offset = 0;
|
||||
m_rVolume->ReadSwapped(read_offset + 0x4, &offset, m_Wii);
|
||||
m_rVolume->ReadSwapped(read_offset + 0x4, &offset, m_partition);
|
||||
size = 0;
|
||||
m_rVolume->ReadSwapped(read_offset + 0x8, &size, m_Wii);
|
||||
m_rVolume->ReadSwapped(read_offset + 0x8, &size, m_partition);
|
||||
m_FileInfoVector.emplace_back(name_offset, static_cast<u64>(offset) << shift, size);
|
||||
NameTableOffset += 0xC;
|
||||
}
|
||||
|
||||
@@ -14,11 +14,12 @@
|
||||
namespace DiscIO
|
||||
{
|
||||
class IVolume;
|
||||
struct Partition;
|
||||
|
||||
class CFileSystemGCWii : public IFileSystem
|
||||
{
|
||||
public:
|
||||
CFileSystemGCWii(const IVolume* _rVolume);
|
||||
CFileSystemGCWii(const IVolume* _rVolume, const Partition& partition);
|
||||
virtual ~CFileSystemGCWii();
|
||||
|
||||
bool IsValid() const override { return m_Valid; }
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
#include "DiscIO/Filesystem.h"
|
||||
#include <memory>
|
||||
#include "DiscIO/FileSystemGCWii.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
IFileSystem::IFileSystem(const IVolume* _rVolume) : m_rVolume(_rVolume)
|
||||
IFileSystem::IFileSystem(const IVolume* _rVolume, const Partition& partition)
|
||||
: m_rVolume(_rVolume), m_partition(partition)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -16,12 +18,12 @@ IFileSystem::~IFileSystem()
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<IFileSystem> CreateFileSystem(const IVolume* volume)
|
||||
std::unique_ptr<IFileSystem> CreateFileSystem(const IVolume* volume, const Partition& partition)
|
||||
{
|
||||
if (!volume)
|
||||
return nullptr;
|
||||
|
||||
std::unique_ptr<IFileSystem> filesystem = std::make_unique<CFileSystemGCWii>(volume);
|
||||
std::unique_ptr<IFileSystem> filesystem = std::make_unique<CFileSystemGCWii>(volume, partition);
|
||||
|
||||
if (!filesystem)
|
||||
return nullptr;
|
||||
|
||||
@@ -9,11 +9,10 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
class IVolume;
|
||||
|
||||
// file info of an FST entry
|
||||
struct SFileInfo
|
||||
{
|
||||
@@ -35,7 +34,7 @@ struct SFileInfo
|
||||
class IFileSystem
|
||||
{
|
||||
public:
|
||||
IFileSystem(const IVolume* _rVolume);
|
||||
IFileSystem(const IVolume* _rVolume, const Partition& partition);
|
||||
|
||||
virtual ~IFileSystem();
|
||||
virtual bool IsValid() const = 0;
|
||||
@@ -50,10 +49,12 @@ public:
|
||||
virtual u64 GetBootDOLOffset() const = 0;
|
||||
virtual u32 GetBootDOLSize(u64 dol_offset) const = 0;
|
||||
|
||||
virtual const Partition GetPartition() const { return m_partition; }
|
||||
protected:
|
||||
const IVolume* m_rVolume;
|
||||
const IVolume* const m_rVolume;
|
||||
const Partition m_partition;
|
||||
};
|
||||
|
||||
std::unique_ptr<IFileSystem> CreateFileSystem(const IVolume* volume);
|
||||
std::unique_ptr<IFileSystem> CreateFileSystem(const IVolume* volume, const Partition& partition);
|
||||
|
||||
} // namespace
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user