From 52ccaabca84713f87d53c851d082612af031b9fb Mon Sep 17 00:00:00 2001 From: PabloMK7 Date: Sun, 13 Apr 2025 19:31:40 +0200 Subject: [PATCH] Fix system files setup for region changed consoles --- .../configuration/configure_system.cpp | 26 ++++---- src/core/hw/unique_data.cpp | 31 ++++++++-- src/core/hw/unique_data.h | 14 +++++ src/core/loader/artic.h | 2 +- src/core/system_titles.cpp | 59 ++++++++++++------- 5 files changed, 92 insertions(+), 40 deletions(-) diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp index c0be39424..fb9f6d7bb 100644 --- a/src/citra_qt/configuration/configure_system.cpp +++ b/src/citra_qt/configuration/configure_system.cpp @@ -662,29 +662,27 @@ void ConfigureSystem::RefreshSecureDataStatus() { auto status_to_str = [](HW::UniqueData::SecureDataLoadStatus status) { switch (status) { case HW::UniqueData::SecureDataLoadStatus::Loaded: - return "Loaded"; + return tr("Status: Loaded"); case HW::UniqueData::SecureDataLoadStatus::InvalidSignature: - return "Loaded (Invalid Signature)"; + return tr("Status: Loaded (Invalid Signature)"); + case HW::UniqueData::SecureDataLoadStatus::RegionChanged: + return tr("Status: Loaded (Region Changed)"); case HW::UniqueData::SecureDataLoadStatus::NotFound: - return "Not Found"; + return tr("Status: Not Found"); case HW::UniqueData::SecureDataLoadStatus::Invalid: - return "Invalid"; + return tr("Status: Invalid"); case HW::UniqueData::SecureDataLoadStatus::IOError: - return "IO Error"; + return tr("Status: IO Error"); default: - return ""; + return QString(); } }; - ui->label_secure_info_status->setText( - tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadSecureInfoA())).c_str())); + ui->label_secure_info_status->setText(status_to_str(HW::UniqueData::LoadSecureInfoA())); ui->label_friend_code_seed_status->setText( - tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadLocalFriendCodeSeedB())) - .c_str())); - ui->label_otp_status->setText( - tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadOTP())).c_str())); - ui->label_movable_status->setText( - tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadMovable())).c_str())); + status_to_str(HW::UniqueData::LoadLocalFriendCodeSeedB())); + ui->label_otp_status->setText(status_to_str(HW::UniqueData::LoadOTP())); + ui->label_movable_status->setText(status_to_str(HW::UniqueData::LoadMovable())); if (HW::UniqueData::IsFullConsoleLinked()) { ui->linked_console->setVisible(true); diff --git a/src/core/hw/unique_data.cpp b/src/core/hw/unique_data.cpp index 988c42e19..8d7ac9035 100644 --- a/src/core/hw/unique_data.cpp +++ b/src/core/hw/unique_data.cpp @@ -18,6 +18,7 @@ namespace HW::UniqueData { static SecureInfoA secure_info_a; static bool secure_info_a_signature_valid = false; +static bool secure_info_a_region_changed = false; static LocalFriendCodeSeedB local_friend_code_seed_b; static bool local_friend_code_seed_b_signature_valid = false; static FileSys::OTP otp; @@ -41,8 +42,10 @@ bool MovableSed::VerifySignature() const { SecureDataLoadStatus LoadSecureInfoA() { if (secure_info_a.IsValid()) { - return secure_info_a_signature_valid ? SecureDataLoadStatus::Loaded - : SecureDataLoadStatus::InvalidSignature; + return secure_info_a_signature_valid + ? SecureDataLoadStatus::Loaded + : (secure_info_a_region_changed ? SecureDataLoadStatus::RegionChanged + : SecureDataLoadStatus::InvalidSignature); } std::string file_path = GetSecureInfoAPath(); if (!FileUtil::Exists(file_path)) { @@ -61,13 +64,31 @@ SecureDataLoadStatus LoadSecureInfoA() { } HW::AES::InitKeys(); + secure_info_a_region_changed = false; secure_info_a_signature_valid = secure_info_a.VerifySignature(); if (!secure_info_a_signature_valid) { - LOG_WARNING(HW, "SecureInfo_A signature check failed"); + // Check if the file has been region changed + SecureInfoA copy = secure_info_a; + for (u8 orig_reg = 0; orig_reg < Region::COUNT; orig_reg++) { + if (orig_reg == secure_info_a.body.region) { + continue; + } + copy.body.region = orig_reg; + if (copy.VerifySignature()) { + secure_info_a_region_changed = true; + LOG_WARNING(HW, "SecureInfo_A is region changed and its signature invalid"); + break; + } + } + if (!secure_info_a_region_changed) { + LOG_WARNING(HW, "SecureInfo_A signature check failed"); + } } - return secure_info_a_signature_valid ? SecureDataLoadStatus::Loaded - : SecureDataLoadStatus::InvalidSignature; + return secure_info_a_signature_valid + ? SecureDataLoadStatus::Loaded + : (secure_info_a_region_changed ? SecureDataLoadStatus::RegionChanged + : SecureDataLoadStatus::InvalidSignature); } SecureDataLoadStatus LoadLocalFriendCodeSeedB() { diff --git a/src/core/hw/unique_data.h b/src/core/hw/unique_data.h index 463d8e8e0..dd3a4bb8b 100644 --- a/src/core/hw/unique_data.h +++ b/src/core/hw/unique_data.h @@ -17,6 +17,19 @@ class OTP; namespace HW::UniqueData { +struct Region { + enum : u8 { + JPN, + USA, + EUR, + AUS, + CHN, + KOR, + TWN, + }; + static constexpr u8 COUNT = TWN + 1; +}; + struct SecureInfoA { std::array signature; struct { @@ -122,6 +135,7 @@ static_assert(sizeof(MovableSedFull) == 0x140); enum class SecureDataLoadStatus { Loaded = 0, InvalidSignature = 1, + RegionChanged = 2, NotFound = -1, Invalid = -2, diff --git a/src/core/loader/artic.h b/src/core/loader/artic.h index f5b148364..18ba31d87 100644 --- a/src/core/loader/artic.h +++ b/src/core/loader/artic.h @@ -93,7 +93,7 @@ public: } private: - static constexpr u32 SETUP_TOOL_VERSION = 1; + static constexpr u32 SETUP_TOOL_VERSION = 2; /** * Loads .code section into memory for booting * @param process The newly created process diff --git a/src/core/system_titles.cpp b/src/core/system_titles.cpp index 9014c9ca7..5ac29e171 100644 --- a/src/core/system_titles.cpp +++ b/src/core/system_titles.cpp @@ -5,6 +5,7 @@ #include #include "core/hle/service/am/am.h" #include "core/hle/service/fs/archive.h" +#include "core/hw/unique_data.h" #include "core/system_titles.h" namespace Core { @@ -193,22 +194,22 @@ static const std::array .name = "NNID Web Browser Data", .sets = SystemTitleSet::Old3ds | SystemTitleSet::New3ds | SystemTitleSet::Minimal, - .title_id_lows = {0x00018002, 0x00018002, 0x00018002, 0x00018002, - 0x00018002, 0x00018002, 0x00018002}, + .title_id_lows = {0x00018002, 0x00018002, 0x00018002, 0x00018002, 0, + 0, 0}, }, { .name = "Miiverse Offline Mode Web Browser Data", .sets = SystemTitleSet::Old3ds | SystemTitleSet::New3ds | SystemTitleSet::Minimal, - .title_id_lows = {0x00018102, 0x00018102, 0x00018102, 0x00018102, - 0x00018102, 0x00018102, 0x00018102}, + .title_id_lows = {0x00018102, 0x00018102, 0x00018102, 0x00018102, 0, + 0, 0}, }, { .name = "NNID/Miiverse OSS CROs", .sets = SystemTitleSet::Old3ds | SystemTitleSet::New3ds | SystemTitleSet::Minimal, - .title_id_lows = {0x00018202, 0x00018202, 0x00018202, 0x00018202, - 0x00018202, 0x00018202, 0x00018202}, + .title_id_lows = {0x00018202, 0x00018202, 0x00018202, 0x00018202, 0, + 0, 0}, }, { .name = "NFC Peripheral Firmware", @@ -258,8 +259,8 @@ static const std::array { .name = "Error Display (Safe Mode, O3DS)", .sets = SystemTitleSet::Old3ds, - .title_id_lows = {0x00008A03, 0x00008A03, 0x00008A03, 0x00008A03, - 0x00008A03, 0x00008A03, 0x00008A03}, + .title_id_lows = {0x00008A03, 0x00008A03, 0x00008A03, 0x00008A03, 0, + 0, 0}, }, { .name = "Error Display (Safe Mode, N3DS)", @@ -483,8 +484,8 @@ static const std::array .name = "EULA", .sets = SystemTitleSet::Old3ds | SystemTitleSet::New3ds | SystemTitleSet::Minimal, - .title_id_lows = {0x00013202, 0x00013302, 0x00013102, 0x00013102, - 0x00013502, 0, 0}, + .title_id_lows = {0x00013202, 0x00013302, 0x00013102, 0x00013102, 0, + 0, 0}, }, { .name = "JPN/EUR/USA System Font", @@ -904,8 +905,8 @@ static const std::array { .name = "NIM Module (Safe Mode, O3DS)", .sets = SystemTitleSet::Old3ds, - .title_id_lows = {0x00002C03, 0x00002C03, 0x00002C03, 0x00002C03, - 0x00002C03, 0x00002C03, 0x00002C03}, + .title_id_lows = {0x00002C03, 0x00002C03, 0x00002C03, 0x00002C03, 0, + 0, 0}, }, { .name = "NIM Module (Safe Mode, N3DS)", @@ -1067,8 +1068,8 @@ static const std::array { .name = "NS Module (Safe Mode, O3DS)", .sets = SystemTitleSet::Old3ds, - .title_id_lows = {0x00008003, 0x00008003, 0x00008003, 0x00008003, - 0x00008003, 0x00008003, 0x00008003}, + .title_id_lows = {0x00008003, 0x00008003, 0x00008003, 0x00008003, 0, + 0, 0}, }, { .name = "NS Module (Safe Mode, N3DS)", @@ -1120,8 +1121,8 @@ static const std::array { .name = "AGB_FIRM (O3DS)", .sets = SystemTitleSet::Old3ds, - .title_id_lows = {0x00000202, 0x00000202, 0x00000202, 0x00000202, - 0x00000202, 0x00000202, 0x00000202}, + .title_id_lows = {0x00000202, 0x00000202, 0x00000202, 0x00000202, 0, + 0x00000202, 0}, }, { .name = "AGB_FIRM (N3DS)", @@ -1215,6 +1216,10 @@ std::pair AreSystemTitlesInstalled() { std::array n_installed_titles{}; std::array n_total_titles{}; + static const char* region_names[NUM_SYSTEM_TITLE_REGIONS] = { + "JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN", + }; + for (auto categ = system_titles.begin(); categ != system_titles.end(); categ++) { for (auto title = categ->titles.begin(); title != categ->titles.end(); title++) { @@ -1241,6 +1246,14 @@ std::pair AreSystemTitlesInstalled() { if (title->sets & SystemTitleSet::New3ds) { n_installed_titles[i]++; } + } else { + std::string set = (title->sets & SystemTitleSet::Old3ds) ? "O3DS" : ""; + if (title->sets & SystemTitleSet::New3ds) { + set += set.empty() ? "N3DS" : "/N3DS"; + } + + LOG_DEBUG(Service_AM, "{}, {}, {}, {} not found", categ->name, title->name, + region_names[i], set); } } } @@ -1252,13 +1265,19 @@ std::pair AreSystemTitlesInstalled() { for (size_t i = 0; i < o_installed_titles.size(); i++) { if (o_installed_titles[i] == o_total_titles[i]) { o_all = true; + // CHN/TWN don't have n3ds variants + if (i == HW::UniqueData::Region::CHN || i == HW::UniqueData::Region::TWN) { + n_all = true; + } break; } } - for (size_t i = 0; i < n_installed_titles.size(); i++) { - if (n_installed_titles[i] == n_total_titles[i]) { - n_all = true; - break; + if (!n_all) { + for (size_t i = 0; i < n_installed_titles.size(); i++) { + if (n_installed_titles[i] == n_total_titles[i]) { + n_all = true; + break; + } } }