Mark console as "linked" when using the azahar artic setup tool (#833)

* Mark console as "linked" when using the azahar artic setup tool

* Updated strings related to console linking

---------

Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
This commit is contained in:
PabloMK7 2025-03-28 12:10:59 +01:00 committed by GitHub
parent dee576bfeb
commit eda2d6f9fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 285 additions and 121 deletions

View File

@ -182,6 +182,10 @@ object NativeLibrary {
external fun uninstallSystemFiles(old3DS: Boolean) external fun uninstallSystemFiles(old3DS: Boolean)
external fun isFullConsoleLinked(): Boolean
external fun unlinkConsole()
private var coreErrorAlertResult = false private var coreErrorAlertResult = false
private val coreErrorAlertLock = Object() private val coreErrorAlertLock = Object()

View File

@ -4,6 +4,7 @@
package org.citra.citra_emu.fragments package org.citra.citra_emu.fragments
import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.view.Gravity import android.view.Gravity
@ -157,6 +158,22 @@ class SystemFilesFragment : Fragment() {
movementMethod = LinkMovementMethod.getInstance() movementMethod = LinkMovementMethod.getInstance()
} }
binding.buttonUnlinkConsoleData.isEnabled = NativeLibrary.isFullConsoleLinked()
binding.buttonUnlinkConsoleData.setOnClickListener {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.delete_system_files)
.setMessage(HtmlCompat.fromHtml(
requireContext().getString(R.string.delete_system_files_description),
HtmlCompat.FROM_HTML_MODE_COMPACT
))
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
NativeLibrary.unlinkConsole()
binding.buttonUnlinkConsoleData.isEnabled = NativeLibrary.isFullConsoleLinked()
}
.setNegativeButton(android.R.string.cancel, null)
.show()
}
binding.buttonSetUpSystemFiles.setOnClickListener { binding.buttonSetUpSystemFiles.setOnClickListener {
val inflater = LayoutInflater.from(context) val inflater = LayoutInflater.from(context)
val inputBinding = DialogSoftwareKeyboardBinding.inflate(inflater) val inputBinding = DialogSoftwareKeyboardBinding.inflate(inflater)

View File

@ -36,6 +36,7 @@
#include "core/frontend/camera/factory.h" #include "core/frontend/camera/factory.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
#include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfc/nfc.h"
#include "core/hw/unique_data.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/savestate.h" #include "core/savestate.h"
#include "core/system_titles.h" #include "core/system_titles.h"
@ -772,4 +773,12 @@ void Java_org_citra_citra_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIE
LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level()); LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
} }
jboolean Java_org_citra_citra_1emu_NativeLibrary_isFullConsoleLinked(JNIEnv* env, jobject obj) {
return HW::UniqueData::IsFullConsoleLinked();
}
void Java_org_citra_citra_1emu_NativeLibrary_unlinkConsole(JNIEnv* env, jobject obj) {
HW::UniqueData::UnlinkConsole();
}
} // extern "C" } // extern "C"

View File

@ -61,6 +61,13 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/setup_tool_connect" /> android:text="@string/setup_tool_connect" />
<Button
android:id="@+id/button_unlink_console_data"
style="@style/Widget.Material3.Button.UnelevatedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/delete_system_files" />
<View <View
android:id="@+id/divider2" android:id="@+id/divider2"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -150,8 +150,10 @@
<string name="setup_system_files">System Files</string> <string name="setup_system_files">System Files</string>
<string name="setup_system_files_description">Perform system file operations such as installing system files or booting the Home Menu</string> <string name="setup_system_files_description">Perform system file operations such as installing system files or booting the Home Menu</string>
<string name="setup_tool_connect">Connect to Artic Setup Tool</string> <string name="setup_tool_connect">Connect to Artic Setup Tool</string>
<string name="setup_system_files_preamble"><![CDATA[Azahar needs files from a real console to be able to use some of its features. You can get such files with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a>.<br> Notes:<ul><li><b>This operation will install console unique files to Azahar, do not share your user or nand folders<br>after performing the setup process!</b></li><li>Old 3DS setup is needed for the New 3DS setup to work.</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul>]]></string> <string name="setup_system_files_preamble"><![CDATA[Azahar needs console unique data and firmware files from a real console to be able to use some of its features. Such files and data can be set up with the <a href=https://github.com/azahar-emu/ArticSetupTool>Azahar Artic Setup Tool</a>.<br>Notes:<ul><li><b>This operation will install console unique data to Azahar, do not share your user or nand folders after performing the setup process!</b></li><li>While doing the setup process, Azahar will link to the console running the setup tool. You can unlink the console later from the System Files tab in the emulator options menu.</li><li>Do not go online with both Azahar and your 3DS console at the same time after setting up system files, as this could cause issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (setting up both is recommended).</li><li>Both setup modes will work regardless of the model of the console running the setup tool.</li></ul>]]></string>
<string name="setup_system_files_detect">Fetching current system files status, please wait...</string> <string name="setup_system_files_detect">Fetching current system files status, please wait...</string>
<string name="delete_system_files">Unlink Console Unique Data</string>
<string name="delete_system_files_description"><![CDATA[This action will unlink your real console from Azahar, with the following consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed from Azahar.</li><li>Your friend list will reset and you will be logged out of your NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will become inaccessible until the same console is linked again using the setup tool (save data will not be lost).</li></ul><br>Continue?]]></string>
<string name="setup_system_files_o3ds">Old 3DS Setup</string> <string name="setup_system_files_o3ds">Old 3DS Setup</string>
<string name="setup_system_files_n3ds">New 3DS Setup</string> <string name="setup_system_files_n3ds">New 3DS Setup</string>
<string name="setup_system_files_possible">Setup is possible.</string> <string name="setup_system_files_possible">Setup is possible.</string>

View File

@ -2112,15 +2112,18 @@ void GMainWindow::OnMenuSetUpSystemFiles() {
QVBoxLayout layout(&dialog); QVBoxLayout layout(&dialog);
QLabel label_description( QLabel label_description(
tr("<p>Azahar needs files from a real console to be able to use some of its features.<br>" tr("<p>Azahar needs console unique data and firmware files from a real console to be "
"You can get such files with the <a " "able to use some of its features.<br>Such files and data can be set up with the <a "
"href=https://github.com/azahar-emu/ArticSetupTool>Azahar " "href=https://github.com/azahar-emu/ArticSetupTool>Azahar "
"Artic Setup Tool</a><br> Notes:<ul><li><b>This operation will install console unique " "Artic Setup Tool</a><br>Notes:<ul><li><b>This operation will install console unique "
"files " "data to Azahar, do not share your user or nand folders<br>after performing the setup "
"to Azahar, do not share your user or nand folders<br>after performing the setup " "process!</b></li><li>While doing the setup process, Azahar will link to the console "
"process!</b></li><li>Old 3DS setup is needed for the New 3DS setup to " "running the setup tool. You can unlink the<br>console later from the System tab in the "
"work.</li><li>Both setup modes will work regardless of the model of the console " "emulator configuration menu.</li><li>Do not go online with both Azahar and your 3DS "
"running the setup tool.</li></ul><hr></p>"), "console at the same time after setting up system files,<br>as it could cause "
"issues.</li><li>Old 3DS setup is needed for the New 3DS setup to work (doing both "
"setup modes is recommended).</li><li>Both setup modes will work regardless of the "
"model of the console running the setup tool.</li></ul><hr></p>"),
&dialog); &dialog);
label_description.setOpenExternalLinks(true); label_description.setOpenExternalLinks(true);
layout.addWidget(&label_description); layout.addWidget(&label_description);

View File

@ -238,6 +238,8 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
&ConfigureSystem::RefreshConsoleID); &ConfigureSystem::RefreshConsoleID);
connect(ui->button_regenerate_mac, &QPushButton::clicked, this, &ConfigureSystem::RefreshMAC); connect(ui->button_regenerate_mac, &QPushButton::clicked, this, &ConfigureSystem::RefreshMAC);
connect(ui->button_linked_console, &QPushButton::clicked, this,
&ConfigureSystem::UnlinkConsole);
connect(ui->button_secure_info, &QPushButton::clicked, this, [this] { connect(ui->button_secure_info, &QPushButton::clicked, this, [this] {
ui->button_secure_info->setEnabled(false); ui->button_secure_info->setEnabled(false);
@ -561,6 +563,25 @@ void ConfigureSystem::RefreshMAC() {
ui->label_mac->setText(tr("MAC: %1").arg(QString::fromStdString(mac_address))); ui->label_mac->setText(tr("MAC: %1").arg(QString::fromStdString(mac_address)));
} }
void ConfigureSystem::UnlinkConsole() {
QMessageBox::StandardButton reply;
QString warning_text =
tr("This action will unlink your real console from Azahar, with the following "
"consequences:<br><ul><li>Your OTP, SecureInfo and LocalFriendCodeSeed will be removed "
"from Azahar.</li><li>Your friend list will reset and you will be logged out of your "
"NNID/PNID account.</li><li>System files and eshop titles obtained through Azahar will "
"become inaccessible until the same console is linked again (save data will not be "
"lost).</li></ul><br>Continue?");
reply =
QMessageBox::warning(this, tr("Warning"), warning_text, QMessageBox::No | QMessageBox::Yes);
if (reply == QMessageBox::No) {
return;
}
HW::UniqueData::UnlinkConsole();
RefreshSecureDataStatus();
}
void ConfigureSystem::InstallSecureData(const std::string& from_path, const std::string& to_path) { void ConfigureSystem::InstallSecureData(const std::string& from_path, const std::string& to_path) {
std::string from = std::string from =
FileUtil::SanitizePath(from_path, FileUtil::DirectorySeparator::PlatformDefault); FileUtil::SanitizePath(from_path, FileUtil::DirectorySeparator::PlatformDefault);
@ -601,6 +622,15 @@ void ConfigureSystem::RefreshSecureDataStatus() {
tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadOTP())).c_str())); tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadOTP())).c_str()));
ui->label_movable_status->setText( ui->label_movable_status->setText(
tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadMovable())).c_str())); tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadMovable())).c_str()));
if (HW::UniqueData::IsFullConsoleLinked()) {
ui->linked_console->setVisible(true);
ui->button_otp->setEnabled(false);
ui->button_secure_info->setEnabled(false);
ui->button_friend_code_seed->setEnabled(false);
} else {
ui->linked_console->setVisible(false);
}
} }
void ConfigureSystem::RetranslateUI() { void ConfigureSystem::RetranslateUI() {
@ -625,6 +655,7 @@ void ConfigureSystem::SetupPerGameUI() {
ui->label_init_ticks_type->setVisible(false); ui->label_init_ticks_type->setVisible(false);
ui->label_init_ticks_value->setVisible(false); ui->label_init_ticks_value->setVisible(false);
ui->label_console_id->setVisible(false); ui->label_console_id->setVisible(false);
ui->label_mac->setVisible(false);
ui->label_sound->setVisible(false); ui->label_sound->setVisible(false);
ui->label_language->setVisible(false); ui->label_language->setVisible(false);
ui->label_country->setVisible(false); ui->label_country->setVisible(false);
@ -646,6 +677,7 @@ void ConfigureSystem::SetupPerGameUI() {
ui->edit_init_ticks_value->setVisible(false); ui->edit_init_ticks_value->setVisible(false);
ui->toggle_system_setup->setVisible(false); ui->toggle_system_setup->setVisible(false);
ui->button_regenerate_console_id->setVisible(false); ui->button_regenerate_console_id->setVisible(false);
ui->button_regenerate_mac->setVisible(false);
// Apps can change the state of the plugin loader, so plugins load // Apps can change the state of the plugin loader, so plugins load
// to a chainloaded app with specific parameters. Don't allow // to a chainloaded app with specific parameters. Don't allow
// the plugin loader state to be configured per-game as it may // the plugin loader state to be configured per-game as it may
@ -653,6 +685,7 @@ void ConfigureSystem::SetupPerGameUI() {
ui->label_plugin_loader->setVisible(false); ui->label_plugin_loader->setVisible(false);
ui->plugin_loader->setVisible(false); ui->plugin_loader->setVisible(false);
ui->allow_plugin_loader->setVisible(false); ui->allow_plugin_loader->setVisible(false);
ui->group_real_console_unique_data->setVisible(false);
ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds, ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds,
is_new_3ds); is_new_3ds);

View File

@ -52,6 +52,7 @@ private:
void UpdateInitTicks(int init_ticks_type); void UpdateInitTicks(int init_ticks_type);
void RefreshConsoleID(); void RefreshConsoleID();
void RefreshMAC(); void RefreshMAC();
void UnlinkConsole();
void InstallSecureData(const std::string& from_path, const std::string& to_path); void InstallSecureData(const std::string& from_path, const std::string& to_path);
void RefreshSecureDataStatus(); void RefreshSecureDataStatus();

View File

@ -518,86 +518,46 @@ online features (if installed)</string>
<string>Real Console Unique Data</string> <string>Real Console Unique Data</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout1"> <layout class="QGridLayout" name="gridLayout1">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="group_real_console_unique_data_core">
<layout class="QGridLayout" name="gridLayout2">
<item row="0" column="0" colspan="2">
<widget class="QWidget" name="linked_console">
<layout class="QHBoxLayout" name="horizontalLayout_linked_console">
<item>
<widget class="QLabel" name="label_linked_console">
<property name="text">
<string>Your real console is linked to Azahar.</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_linked_console">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Unlink</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_secure_info">
<property name="text">
<string>SecureInfo_A/B</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="secure_info">
<layout class="QHBoxLayout" name="horizontalLayout_secure_info">
<item>
<widget class="QLabel" name="label_secure_info_status">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_secure_info">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_friend_code_seed">
<property name="text">
<string>LocalFriendCodeSeed_A/B</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="friend_code_seed">
<layout class="QHBoxLayout" name="horizontalLayout_friend_code_seed">
<item>
<widget class="QLabel" name="label_friend_code_seed_status">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_friend_code_seed">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_otp"> <widget class="QLabel" name="label_otp">
<property name="text"> <property name="text">
<string>OTP</string> <string>OTP</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="1" column="1">
<widget class="QWidget" name="otp"> <widget class="QWidget" name="otp">
<layout class="QHBoxLayout" name="horizontalLayout_otp"> <layout class="QHBoxLayout" name="horizontalLayout_otp">
<item> <item>
@ -626,14 +586,89 @@ online features (if installed)</string>
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_secure_info">
<property name="text">
<string>SecureInfo_A/B</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="secure_info">
<layout class="QHBoxLayout" name="horizontalLayout_secure_info">
<item>
<widget class="QLabel" name="label_secure_info_status">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_secure_info">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_friend_code_seed">
<property name="text">
<string>LocalFriendCodeSeed_A/B</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QWidget" name="friend_code_seed">
<layout class="QHBoxLayout" name="horizontalLayout_friend_code_seed">
<item>
<widget class="QLabel" name="label_friend_code_seed_status">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_friend_code_seed">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_movable"> <widget class="QLabel" name="label_movable">
<property name="text"> <property name="text">
<string>movable.sed</string> <string>movable.sed</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="1" column="1">
<widget class="QWidget" name="movable"> <widget class="QWidget" name="movable">
<layout class="QHBoxLayout" name="horizontalLayout_movable"> <layout class="QHBoxLayout" name="horizontalLayout_movable">
<item> <item>

View File

@ -5,6 +5,7 @@
#include <cryptopp/sha.h> #include <cryptopp/sha.h>
#include "common/common_paths.h" #include "common/common_paths.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/file_sys/archive_systemsavedata.h"
#include "core/file_sys/certificate.h" #include "core/file_sys/certificate.h"
#include "core/file_sys/otp.h" #include "core/file_sys/otp.h"
#include "core/hw/aes/key.h" #include "core/hw/aes/key.h"
@ -262,4 +263,30 @@ std::unique_ptr<FileUtil::IOFile> OpenUniqueCryptoFile(const std::string& filena
return std::make_unique<FileUtil::CryptoIOFile>(filename, openmode, key, ctr, flags); return std::make_unique<FileUtil::CryptoIOFile>(filename, openmode, key, ctr, flags);
} }
bool IsFullConsoleLinked() {
return GetOTP().Valid() && GetSecureInfoA().IsValid() && GetLocalFriendCodeSeedB().IsValid();
}
void UnlinkConsole() {
// Remove all console unique data, as well as the act, nim and frd savefiles
const std::string system_save_data_path =
FileSys::GetSystemSaveDataContainerPath(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
constexpr std::array<std::array<u8, 8>, 3> save_data_ids{{
{0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x01, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x01, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0x00},
}};
for (auto& id : save_data_ids) {
const std::string final_path = FileSys::GetSystemSaveDataPath(system_save_data_path, id);
FileUtil::DeleteDirRecursively(final_path, 2);
}
FileUtil::Delete(GetOTPPath());
FileUtil::Delete(GetSecureInfoAPath());
FileUtil::Delete(GetLocalFriendCodeSeedBPath());
InvalidateSecureData();
}
} // namespace HW::UniqueData } // namespace HW::UniqueData

View File

@ -154,4 +154,7 @@ void InvalidateSecureData();
std::unique_ptr<FileUtil::IOFile> OpenUniqueCryptoFile(const std::string& filename, std::unique_ptr<FileUtil::IOFile> OpenUniqueCryptoFile(const std::string& filename,
const char openmode[], UniqueCryptoFileID id, const char openmode[], UniqueCryptoFileID id,
int flags = 0); int flags = 0);
bool IsFullConsoleLinked();
void UnlinkConsole();
} // namespace HW::UniqueData } // namespace HW::UniqueData

View File

@ -342,7 +342,8 @@ void Apploader_Artic::EnsureClientConnected() {
if (is_initial_setup) { if (is_initial_setup) {
// Ensure we are running the initial setup app in the correct version // Ensure we are running the initial setup app in the correct version
auto req = client->NewRequest("System_IsAzaharInitialSetup"); auto req = client->NewRequest("System_ArticSetupVersion");
req.AddParameterU32(SETUP_TOOL_VERSION);
auto resp = client->Send(req); auto resp = client->Send(req);
if (!resp.has_value()) { if (!resp.has_value()) {
client_connected = false; client_connected = false;
@ -355,7 +356,15 @@ void Apploader_Artic::EnsureClientConnected() {
return; return;
} }
client_connected = *reinterpret_cast<u32*>(ret_buf->first) == INITIAL_SETUP_APP_VERSION; if (*reinterpret_cast<u32*>(ret_buf->first) != SETUP_TOOL_VERSION) {
system.SetStatus(Core::System::ResultStatus::ErrorArticDisconnected,
"\nIncompatible Artic Setup Tool version.\nCheck for Artic Setup Tool "
"or Azahar updates.");
client_connected = false;
client->Stop();
} else {
client_connected = true;
}
} }
} }
@ -385,6 +394,20 @@ ResultStatus Apploader_Artic::Load(std::shared_ptr<Kernel::Process>& process) {
if (is_initial_setup) { if (is_initial_setup) {
// If there is already a console linked, check it's the same device.
// Otherwise it could cause weird issues with account save data.
if (HW::UniqueData::IsFullConsoleLinked()) {
auto req = client->NewRequest("System_ReportDeviceID");
req.AddParameterU32(HW::UniqueData::GetOTP().GetDeviceID());
auto resp = client->Send(req);
if (!resp.has_value() || !resp->Succeeded())
return ResultStatus::ErrorArtic;
if (resp->GetMethodResult() != 0)
return ResultStatus::ErrorArtic;
}
// Request console unique data // Request console unique data
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
std::string path; std::string path;

View File

@ -93,7 +93,7 @@ public:
} }
private: private:
static constexpr u32 INITIAL_SETUP_APP_VERSION = 0; static constexpr u32 SETUP_TOOL_VERSION = 1;
/** /**
* Loads .code section into memory for booting * Loads .code section into memory for booting
* @param process The newly created process * @param process The newly created process