From c759739ee9ec9f577c524a7b48116ac933e91623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Tue, 4 Jul 2017 16:09:31 +0200 Subject: [PATCH 1/2] SysConf: Handle array entries properly It turns out that the last byte of array entries isn't unused (as we thought); instead, it looks like it's actually part of the main data, and the length stored next to the name is in fact the length minus one. Getting it wrong and always storing a null byte in there won't affect most entries (since the last byte is zeroed most of the time), except: - IPL.NIK: the length is stored in the last byte, and it must be kept. - BT.DINF: u8 unknown[0x45] should be another Bluetooth device entry. - Possibly other unknown affected entries. --- Source/Core/Common/SysConf.cpp | 30 ++++++++++--------- Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp | 9 ++---- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp | 6 ++-- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Source/Core/Common/SysConf.cpp b/Source/Core/Common/SysConf.cpp index 4e5e88fb83..422bbb3f2e 100644 --- a/Source/Core/Common/SysConf.cpp +++ b/Source/Core/Common/SysConf.cpp @@ -100,14 +100,15 @@ bool SysConf::LoadFromFile(const std::string& file_name) { u16 data_length = 0; file.ReadBytes(&data_length, sizeof(data_length)); - data.resize(Common::swap16(data_length)); + // The stored u16 is length - 1, not length. + data.resize(Common::swap16(data_length) + 1); break; } case Entry::Type::SmallArray: { u8 data_length = 0; file.ReadBytes(&data_length, sizeof(data_length)); - data.resize(data_length); + data.resize(data_length + 1); break; } case Entry::Type::Byte: @@ -165,20 +166,17 @@ bool SysConf::Save() const case Entry::Type::BigArray: { const u16 data_size = static_cast(item.bytes.size()); - AppendToBuffer(&entries, data_size); + // length - 1 is stored, not length. + AppendToBuffer(&entries, data_size - 1); entries.insert(entries.end(), item.bytes.cbegin(), item.bytes.cbegin() + data_size); - // Unused byte. - entries.insert(entries.end(), '\0'); break; } case Entry::Type::SmallArray: { const u8 data_size = static_cast(item.bytes.size()); - AppendToBuffer(&entries, data_size); + AppendToBuffer(&entries, data_size - 1); entries.insert(entries.end(), item.bytes.cbegin(), item.bytes.cbegin() + data_size); - // Unused byte. - entries.insert(entries.end(), '\0'); break; } @@ -272,22 +270,26 @@ void SysConf::ApplySettingsFromMovie() void SysConf::InsertDefaultEntries() { - AddEntry({Entry::Type::BigArray, "BT.DINF", std::vector(0x460)}); - AddEntry({Entry::Type::BigArray, "BT.CDIF", std::vector(0x204)}); + AddEntry({Entry::Type::BigArray, "BT.DINF", std::vector(0x460 + 1)}); + AddEntry({Entry::Type::BigArray, "BT.CDIF", std::vector(0x204 + 1)}); AddEntry({Entry::Type::Long, "BT.SENS", {0, 0, 0, 3}}); AddEntry({Entry::Type::Byte, "BT.BAR", {1}}); AddEntry({Entry::Type::Byte, "BT.SPKV", {0x58}}); AddEntry({Entry::Type::Byte, "BT.MOT", {1}}); - const std::vector console_nick = {0, 'd', 0, 'o', 0, 'l', 0, 'p', 0, 'h', 0, 'i', 0, 'n'}; + std::vector console_nick = {0, 'd', 0, 'o', 0, 'l', 0, 'p', 0, 'h', 0, 'i', 0, 'n'}; + // 22 bytes: 2 bytes per character (10 characters maximum), + // 1 for a null terminating character, 1 for the string length + console_nick.resize(22); + console_nick[21] = static_cast(strlen("dolphin")); AddEntry({Entry::Type::SmallArray, "IPL.NIK", std::move(console_nick)}); AddEntry({Entry::Type::Byte, "IPL.LNG", {1}}); - std::vector ipl_sadr(0x1007); + std::vector ipl_sadr(0x1007 + 1); ipl_sadr[0] = 0x6c; AddEntry({Entry::Type::BigArray, "IPL.SADR", std::move(ipl_sadr)}); - std::vector ipl_pc(0x50); + std::vector ipl_pc(0x49 + 1); ipl_pc[1] = 0x04; ipl_pc[2] = 0x14; AddEntry({Entry::Type::SmallArray, "IPL.PC", std::move(ipl_pc)}); @@ -305,7 +307,7 @@ void SysConf::InsertDefaultEntries() AddEntry({Entry::Type::Byte, "IPL.DH", {0}}); AddEntry({Entry::Type::Long, "IPL.INC", {0, 0, 0, 8}}); AddEntry({Entry::Type::Long, "IPL.FRC", {0, 0, 0, 0x28}}); - AddEntry({Entry::Type::SmallArray, "IPL.IDL", {0}}); + AddEntry({Entry::Type::SmallArray, "IPL.IDL", {0, 1}}); AddEntry({Entry::Type::Long, "NET.WCFG", {0, 0, 0, 1}}); AddEntry({Entry::Type::Long, "NET.CTPC", std::vector(4)}); diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp index ada80f2f17..ddf887c32e 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp @@ -19,8 +19,6 @@ namespace IOS { namespace HLE { -constexpr u16 BT_INFO_SECTION_LENGTH = 0x460; - void BackUpBTInfoSection(const SysConf* sysconf) { const std::string filename = File::GetUserPath(D_SESSION_WIIROOT_IDX) + DIR_SEP WII_BTDINF_BACKUP; @@ -33,7 +31,7 @@ void BackUpBTInfoSection(const SysConf* sysconf) return; const std::vector& section = btdinf->bytes; - if (!backup.WriteBytes(section.data(), section.size())) + if (!backup.WriteBytes(section.data(), section.size() - 1)) ERROR_LOG(IOS_WIIMOTE, "Failed to back up BT.DINF section"); } @@ -43,14 +41,13 @@ void RestoreBTInfoSection(SysConf* sysconf) File::IOFile backup(filename, "rb"); if (!backup) return; - std::vector section(BT_INFO_SECTION_LENGTH); - if (!backup.ReadBytes(section.data(), section.size())) + auto& section = sysconf->GetOrAddEntry("BT.DINF", SysConf::Entry::Type::BigArray)->bytes; + if (!backup.ReadBytes(section.data(), section.size() - 1)) { ERROR_LOG(IOS_WIIMOTE, "Failed to read backed up BT.DINF section"); return; } - sysconf->GetOrAddEntry("BT.DINF", SysConf::Entry::Type::BigArray)->bytes = std::move(section); File::Delete(filename); } } // namespace HLE diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index 98aaf7393f..dd2feab4c6 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -78,9 +78,9 @@ BluetoothEmu::BluetoothEmu(Kernel& ios, const std::string& device_name) // save now so that when games load sysconf file it includes the new Wii Remotes // and the correct order for connected Wii Remotes - std::vector data(sizeof(_conf_pads)); - std::memcpy(data.data(), &BT_DINF, data.size()); - sysconf.GetOrAddEntry("BT.DINF", SysConf::Entry::Type::BigArray)->bytes = std::move(data); + auto& section = sysconf.GetOrAddEntry("BT.DINF", SysConf::Entry::Type::BigArray)->bytes; + section.resize(sizeof(_conf_pads) + 1); + std::memcpy(section.data(), &BT_DINF, sizeof(_conf_pads)); if (!sysconf.Save()) PanicAlertT("Failed to write BT.DINF to SYSCONF"); } From 02f32a9b2670ec7df3e8ae947b1b755d6933b5b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 16 Jul 2017 22:11:53 +0800 Subject: [PATCH 2/2] Handle BT.DINF properly The section is 0x461 bytes long, not 0x460. The config data is also now initialised to zero to avoid garbage being written to the SYSCONF. Because our handling has been wrong forever, we discard older BT.DINF section backups as using them would result in the section being the wrong size / incomplete again. --- Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp | 8 ++++---- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp | 4 ++-- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp index ddf887c32e..75e8fef2a0 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTBase.cpp @@ -21,7 +21,7 @@ namespace HLE { void BackUpBTInfoSection(const SysConf* sysconf) { - const std::string filename = File::GetUserPath(D_SESSION_WIIROOT_IDX) + DIR_SEP WII_BTDINF_BACKUP; + const std::string filename = File::GetUserPath(D_CONFIG_IDX) + DIR_SEP WII_BTDINF_BACKUP; if (File::Exists(filename)) return; File::IOFile backup(filename, "wb"); @@ -31,18 +31,18 @@ void BackUpBTInfoSection(const SysConf* sysconf) return; const std::vector& section = btdinf->bytes; - if (!backup.WriteBytes(section.data(), section.size() - 1)) + if (!backup.WriteBytes(section.data(), section.size())) ERROR_LOG(IOS_WIIMOTE, "Failed to back up BT.DINF section"); } void RestoreBTInfoSection(SysConf* sysconf) { - const std::string filename = File::GetUserPath(D_SESSION_WIIROOT_IDX) + DIR_SEP WII_BTDINF_BACKUP; + const std::string filename = File::GetUserPath(D_CONFIG_IDX) + DIR_SEP WII_BTDINF_BACKUP; File::IOFile backup(filename, "rb"); if (!backup) return; auto& section = sysconf->GetOrAddEntry("BT.DINF", SysConf::Entry::Type::BigArray)->bytes; - if (!backup.ReadBytes(section.data(), section.size() - 1)) + if (!backup.ReadBytes(section.data(), section.size())) { ERROR_LOG(IOS_WIIMOTE, "Failed to read backed up BT.DINF section"); return; diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index dd2feab4c6..0761720c9c 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -47,7 +47,7 @@ BluetoothEmu::BluetoothEmu(Kernel& ios, const std::string& device_name) if (!Core::WantsDeterminism()) BackUpBTInfoSection(&sysconf); - _conf_pads BT_DINF; + _conf_pads BT_DINF{}; bdaddr_t tmpBD; u8 i = 0; while (i < MAX_BBMOTES) @@ -79,7 +79,7 @@ BluetoothEmu::BluetoothEmu(Kernel& ios, const std::string& device_name) // save now so that when games load sysconf file it includes the new Wii Remotes // and the correct order for connected Wii Remotes auto& section = sysconf.GetOrAddEntry("BT.DINF", SysConf::Entry::Type::BigArray)->bytes; - section.resize(sizeof(_conf_pads) + 1); + section.resize(sizeof(_conf_pads)); std::memcpy(section.data(), &BT_DINF, sizeof(_conf_pads)); if (!sysconf.Save()) PanicAlertT("Failed to write BT.DINF to SYSCONF"); diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h index c772ce6a50..0e6f4d0173 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h @@ -191,7 +191,7 @@ private: u8 num_registered; _conf_pad_device registered[CONF_PAD_MAX_REGISTERED]; _conf_pad_device active[MAX_BBMOTES]; - u8 unknown[0x45]; + _conf_pad_device unknown; }; #pragma pack(pop) };