From 790830278249c5059d3fef92ea5dfa707de8a0bd Mon Sep 17 00:00:00 2001 From: Dwayne Slater Date: Mon, 13 Mar 2017 13:18:51 -0400 Subject: [PATCH 1/7] VolumeDirectory: Fix off-by-one in entry count calculation The size field in FSTEntry contains the total amount of children, not including the parent, but the parent needs to be included. VolumeDirectory: Fix off-by-one in entry count calculation The size field in FSTEntry contains the total amount of children, not including the parent, but the parent needs to be included. --- Source/Core/DiscIO/VolumeDirectory.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index 8668b2b936..7f552e4195 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -351,8 +351,9 @@ void CVolumeDirectory::BuildFST() File::FSTEntry rootEntry = File::ScanDirectoryTree(m_root_directory, true); u32 name_table_size = ComputeNameSize(rootEntry); + u64 total_entries = rootEntry.size + 1; // The root entry itself isn't counted in rootEntry.size - m_fst_name_offset = rootEntry.size * ENTRY_SIZE; // offset of name table in FST + m_fst_name_offset = total_entries * ENTRY_SIZE; // offset of name table in FST m_fst_data.resize(m_fst_name_offset + name_table_size); // if FST hasn't been assigned (ie no apploader/dol setup), set to default @@ -368,7 +369,7 @@ void CVolumeDirectory::BuildFST() u32 root_offset = 0; // Offset of root of FST // write root entry - WriteEntryData(&fst_offset, DIRECTORY_ENTRY, 0, 0, rootEntry.size); + WriteEntryData(&fst_offset, DIRECTORY_ENTRY, 0, 0, total_entries); WriteDirectory(rootEntry, &fst_offset, &name_offset, ¤t_data_address, root_offset); @@ -454,9 +455,6 @@ void CVolumeDirectory::WriteDirectory(const File::FSTEntry& parent_entry, u32* f // Sort for determinism std::sort(sorted_entries.begin(), sorted_entries.end(), [](const File::FSTEntry& one, const File::FSTEntry& two) { - // For some reason, sorting by lowest ASCII value first prevents many games from - // fully booting. We make the comparison case insensitive to solve the problem. - // (Highest ASCII value first seems to work regardless of case sensitivity.) const std::string one_lower = ASCIIToLowercase(one.virtualName); const std::string two_lower = ASCIIToLowercase(two.virtualName); return one_lower == two_lower ? one.virtualName < two.virtualName : one_lower < two_lower; From d3e9569cf0d74fe70a2ce04fc448d5d8d7cfe938 Mon Sep 17 00:00:00 2001 From: Dwayne Slater Date: Sat, 15 Apr 2017 13:53:53 -0400 Subject: [PATCH 2/7] VolumeDirectory: Compare case-insensitive file names as uppercase, not lowercase Fixes file ordering in games that use ASCII characters between lowercase 'z' and uppercase 'A' (underscores). MySims Kingdom has the files "terrainLightMapTinted.shader", "terrainLightMapTintedGrid.shader", and "terrainLightMapTinted_no_shadow.shader". In lowercase, "terrainLightMapTinted_no_shadow.shader" comes before "terrainLightMapTinted.shader" and "terrainLightMapTintedGrid.shader", which is invalid. --- Source/Core/DiscIO/VolumeDirectory.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index 7f552e4195..b2ffe7f98d 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -25,7 +25,7 @@ namespace DiscIO { static u32 ComputeNameSize(const File::FSTEntry& parent_entry); -static std::string ASCIIToLowercase(std::string str); +static std::string ASCIIToUppercase(std::string str); const size_t CVolumeDirectory::MAX_NAME_LENGTH; const size_t CVolumeDirectory::MAX_ID_LENGTH; @@ -455,9 +455,9 @@ void CVolumeDirectory::WriteDirectory(const File::FSTEntry& parent_entry, u32* f // Sort for determinism std::sort(sorted_entries.begin(), sorted_entries.end(), [](const File::FSTEntry& one, const File::FSTEntry& two) { - const std::string one_lower = ASCIIToLowercase(one.virtualName); - const std::string two_lower = ASCIIToLowercase(two.virtualName); - return one_lower == two_lower ? one.virtualName < two.virtualName : one_lower < two_lower; + const std::string one_upper = ASCIIToUppercase(one.virtualName); + const std::string two_upper = ASCIIToUppercase(two.virtualName); + return one_upper == two_upper ? one.virtualName < two.virtualName : one_upper < two_upper; }); for (const File::FSTEntry& entry : sorted_entries) @@ -500,10 +500,10 @@ static u32 ComputeNameSize(const File::FSTEntry& parent_entry) return name_size; } -static std::string ASCIIToLowercase(std::string str) +static std::string ASCIIToUppercase(std::string str) { std::transform(str.begin(), str.end(), str.begin(), - [](char c) { return std::tolower(c, std::locale::classic()); }); + [](char c) { return std::toupper(c, std::locale::classic()); }); return str; } From 9d633307e31e41545c975072dd866f0e454e29e5 Mon Sep 17 00:00:00 2001 From: Dwayne Slater Date: Mon, 13 Mar 2017 13:29:45 -0400 Subject: [PATCH 3/7] VolumeDirectory: Shift parent_entry_index by m_address_shift Parent entrys were written correctly for GameCube (since the address shift is 0), but not for Wii (since the address shift is 2). --- Source/Core/DiscIO/VolumeDirectory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index b2ffe7f98d..ea9462c423 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -465,8 +465,8 @@ void CVolumeDirectory::WriteDirectory(const File::FSTEntry& parent_entry, u32* f if (entry.isDirectory) { u32 entry_index = *fst_offset / ENTRY_SIZE; - WriteEntryData(fst_offset, DIRECTORY_ENTRY, *name_offset, parent_entry_index, - entry_index + entry.size + 1); + WriteEntryData(fst_offset, DIRECTORY_ENTRY, *name_offset, + parent_entry_index << m_address_shift, entry_index + entry.size + 1); WriteEntryName(name_offset, entry.virtualName); WriteDirectory(entry, fst_offset, name_offset, data_offset, entry_index); From 138b0cb14ed1761d4285a6546e6d53050f4e6a45 Mon Sep 17 00:00:00 2001 From: Dwayne Slater Date: Mon, 13 Mar 2017 14:49:31 -0400 Subject: [PATCH 4/7] VolumeDirectory: Align the name table size up properly If the name table isn't rounded up, a Wii game can read an incorrect number of bytes when fetching the FST. --- Source/Core/DiscIO/VolumeDirectory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index ea9462c423..c10a900777 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -350,7 +350,7 @@ void CVolumeDirectory::BuildFST() m_fst_data.clear(); File::FSTEntry rootEntry = File::ScanDirectoryTree(m_root_directory, true); - u32 name_table_size = ComputeNameSize(rootEntry); + u32 name_table_size = Common::AlignUp(ComputeNameSize(rootEntry), 1ull << m_address_shift); u64 total_entries = rootEntry.size + 1; // The root entry itself isn't counted in rootEntry.size m_fst_name_offset = total_entries * ENTRY_SIZE; // offset of name table in FST From ec9579ebcdc94bb1ce1a8dd3f81c37c0d27bc546 Mon Sep 17 00:00:00 2001 From: Dwayne Slater Date: Mon, 13 Mar 2017 13:47:58 -0400 Subject: [PATCH 5/7] Boot: When loading an FST for a Wii game, update IOS_MEM1_ARENA_END Without doing this, Wii games loaded as an ELF will zero out the FST. This mirrors the behavior of the actual apploader. --- Source/Core/Core/Boot/Boot.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 529810b694..d5e1cb786a 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -79,6 +79,12 @@ void CBoot::Load_FST(bool is_wii) DVDRead(fst_offset << shift, arena_high, fst_size << shift, is_wii); Memory::Write_U32(arena_high, 0x00000038); Memory::Write_U32(max_fst_size << shift, 0x0000003c); + + if (is_wii) + { + // the apploader changes IOS MEM1_ARENA_END too + Memory::Write_U32(arena_high, 0x00003110); + } } void CBoot::UpdateDebugger_MapLoaded() From 108d59b1315f48173359d3784b7b39225bd77b12 Mon Sep 17 00:00:00 2001 From: Dwayne Slater Date: Mon, 27 Mar 2017 20:52:40 -0400 Subject: [PATCH 6/7] VolumeDirectory: Correctly check name_offset alignment in assert --- Source/Core/DiscIO/VolumeDirectory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index c10a900777..56e9553a4b 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -373,8 +373,8 @@ void CVolumeDirectory::BuildFST() WriteDirectory(rootEntry, &fst_offset, &name_offset, ¤t_data_address, root_offset); - // overflow check - _dbg_assert_(DVDINTERFACE, name_offset == name_table_size); + // overflow check, compare the aligned name offset with the aligned name table size + _assert_(Common::AlignUp(name_offset, 1ull << m_address_shift) == name_table_size); // write FST size and location Write32((u32)(m_fst_address >> m_address_shift), 0x0424, &m_disk_header); From 1b9268485c7f626035e5c0f7a9e8a8d91be2e2a8 Mon Sep 17 00:00:00 2001 From: Dwayne Slater Date: Mon, 27 Mar 2017 20:53:42 -0400 Subject: [PATCH 7/7] VolumeDirectory: Pass address shift to WriteEntryData as argument --- Source/Core/DiscIO/VolumeDirectory.cpp | 13 +++++++------ Source/Core/DiscIO/VolumeDirectory.h | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp index 56e9553a4b..35970f7d02 100644 --- a/Source/Core/DiscIO/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/VolumeDirectory.cpp @@ -369,7 +369,7 @@ void CVolumeDirectory::BuildFST() u32 root_offset = 0; // Offset of root of FST // write root entry - WriteEntryData(&fst_offset, DIRECTORY_ENTRY, 0, 0, total_entries); + WriteEntryData(&fst_offset, DIRECTORY_ENTRY, 0, 0, total_entries, m_address_shift); WriteDirectory(rootEntry, &fst_offset, &name_offset, ¤t_data_address, root_offset); @@ -425,7 +425,7 @@ void CVolumeDirectory::Write32(u32 data, u32 offset, std::vector* const buff } void CVolumeDirectory::WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, - u64 length) + u64 length, u32 address_shift) { m_fst_data[(*entry_offset)++] = type; @@ -433,7 +433,7 @@ void CVolumeDirectory::WriteEntryData(u32* entry_offset, u8 type, u32 name_offse m_fst_data[(*entry_offset)++] = (name_offset >> 8) & 0xff; m_fst_data[(*entry_offset)++] = (name_offset)&0xff; - Write32((u32)(data_offset >> m_address_shift), *entry_offset, &m_fst_data); + Write32((u32)(data_offset >> address_shift), *entry_offset, &m_fst_data); *entry_offset += 4; Write32((u32)length, *entry_offset, &m_fst_data); @@ -465,8 +465,8 @@ void CVolumeDirectory::WriteDirectory(const File::FSTEntry& parent_entry, u32* f if (entry.isDirectory) { u32 entry_index = *fst_offset / ENTRY_SIZE; - WriteEntryData(fst_offset, DIRECTORY_ENTRY, *name_offset, - parent_entry_index << m_address_shift, entry_index + entry.size + 1); + WriteEntryData(fst_offset, DIRECTORY_ENTRY, *name_offset, parent_entry_index, + entry_index + entry.size + 1, 0); WriteEntryName(name_offset, entry.virtualName); WriteDirectory(entry, fst_offset, name_offset, data_offset, entry_index); @@ -474,7 +474,8 @@ void CVolumeDirectory::WriteDirectory(const File::FSTEntry& parent_entry, u32* f else { // put entry in FST - WriteEntryData(fst_offset, FILE_ENTRY, *name_offset, *data_offset, entry.size); + WriteEntryData(fst_offset, FILE_ENTRY, *name_offset, *data_offset, entry.size, + m_address_shift); WriteEntryName(name_offset, entry.virtualName); // write entry to virtual disk diff --git a/Source/Core/DiscIO/VolumeDirectory.h b/Source/Core/DiscIO/VolumeDirectory.h index 13a8799eda..155459285c 100644 --- a/Source/Core/DiscIO/VolumeDirectory.h +++ b/Source/Core/DiscIO/VolumeDirectory.h @@ -85,7 +85,8 @@ private: void Write32(u32 data, u32 offset, std::vector* const buffer); // FST creation - void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length); + void WriteEntryData(u32* entry_offset, u8 type, u32 name_offset, u64 data_offset, u64 length, + u32 address_shift); void WriteEntryName(u32* name_offset, const std::string& name); void WriteDirectory(const File::FSTEntry& parent_entry, u32* fst_offset, u32* name_offset, u64* data_offset, u32 parent_entry_index);