summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/process.cpp6
-rw-r--r--src/core/hle/kernel/vm_manager.cpp20
-rw-r--r--src/core/hle/kernel/vm_manager.h8
-rw-r--r--src/core/hle/service/ldr/ldr.cpp52
-rw-r--r--src/core/hle/service/nfp/nfp.cpp6
-rw-r--r--src/core/hle/service/nfp/nfp.h2
-rw-r--r--src/core/loader/nro.cpp21
-rw-r--r--src/core/loader/nro.h3
-rw-r--r--src/yuzu/configuration/configure_system.cpp56
-rw-r--r--src/yuzu/configuration/configure_system.h35
-rw-r--r--src/yuzu/main.cpp49
11 files changed, 187 insertions, 71 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 073dd5a7d..420218d59 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -232,6 +232,12 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
232 MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); 232 MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic);
233 MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); 233 MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable);
234 MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); 234 MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable);
235
236 // Clear instruction cache in CPU JIT
237 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
238 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
239 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
240 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
235} 241}
236 242
237ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 243ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index e1a34eef1..1a92c8f70 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -143,6 +143,26 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
143 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); 143 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
144} 144}
145 145
146ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const {
147 // Find the first Free VMA.
148 const VAddr base = GetASLRRegionBaseAddress();
149 const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) {
150 if (vma.second.type != VMAType::Free)
151 return false;
152
153 const VAddr vma_end = vma.second.base + vma.second.size;
154 return vma_end > base && vma_end >= base + size;
155 });
156
157 if (vma_handle == vma_map.end()) {
158 // TODO(Subv): Find the correct error code here.
159 return ResultCode(-1);
160 }
161
162 const VAddr target = std::max(base, vma_handle->second.base);
163 return MakeResult<VAddr>(target);
164}
165
146ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size, 166ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u64 size,
147 MemoryState state, 167 MemoryState state,
148 Memory::MemoryHookPointer mmio_handler) { 168 Memory::MemoryHookPointer mmio_handler) {
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 84c890224..2447cbb8f 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -158,6 +158,14 @@ public:
158 ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); 158 ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state);
159 159
160 /** 160 /**
161 * Finds the first free address that can hold a region of the desired size.
162 *
163 * @param size Size of the desired region.
164 * @return The found free address.
165 */
166 ResultVal<VAddr> FindFreeRegion(u64 size) const;
167
168 /**
161 * Maps a memory-mapped IO region at a given address. 169 * Maps a memory-mapped IO region at a given address.
162 * 170 *
163 * @param target The guest address to start the mapping at. 171 * @param target The guest address to start the mapping at.
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index ec32faf15..d607d985e 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -3,9 +3,13 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory> 5#include <memory>
6#include <fmt/format.h>
6 7
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/process.h"
7#include "core/hle/service/ldr/ldr.h" 10#include "core/hle/service/ldr/ldr.h"
8#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
12#include "core/loader/nro.h"
9 13
10namespace Service::LDR { 14namespace Service::LDR {
11 15
@@ -59,16 +63,58 @@ public:
59 explicit RelocatableObject() : ServiceFramework{"ldr:ro"} { 63 explicit RelocatableObject() : ServiceFramework{"ldr:ro"} {
60 // clang-format off 64 // clang-format off
61 static const FunctionInfo functions[] = { 65 static const FunctionInfo functions[] = {
62 {0, nullptr, "LoadNro"}, 66 {0, &RelocatableObject::LoadNro, "LoadNro"},
63 {1, nullptr, "UnloadNro"}, 67 {1, nullptr, "UnloadNro"},
64 {2, nullptr, "LoadNrr"}, 68 {2, &RelocatableObject::LoadNrr, "LoadNrr"},
65 {3, nullptr, "UnloadNrr"}, 69 {3, nullptr, "UnloadNrr"},
66 {4, nullptr, "Initialize"}, 70 {4, &RelocatableObject::Initialize, "Initialize"},
67 }; 71 };
68 // clang-format on 72 // clang-format on
69 73
70 RegisterHandlers(functions); 74 RegisterHandlers(functions);
71 } 75 }
76
77 void LoadNrr(Kernel::HLERequestContext& ctx) {
78 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(RESULT_SUCCESS);
80 LOG_WARNING(Service_LDR, "(STUBBED) called");
81 }
82
83 void LoadNro(Kernel::HLERequestContext& ctx) {
84 IPC::RequestParser rp{ctx};
85 rp.Skip(2, false);
86 const VAddr nro_addr{rp.Pop<VAddr>()};
87 const u64 nro_size{rp.Pop<u64>()};
88 const VAddr bss_addr{rp.Pop<VAddr>()};
89 const u64 bss_size{rp.Pop<u64>()};
90
91 // Read NRO data from memory
92 std::vector<u8> nro_data(nro_size);
93 Memory::ReadBlock(nro_addr, nro_data.data(), nro_size);
94
95 // Load NRO as new executable module
96 const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)};
97 Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr);
98
99 // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party.
100 // It is currently missing:
101 // - Signature checks with LoadNRR
102 // - Checking if a module has already been loaded
103 // - Using/validating BSS, etc. params (these are used from NRO header instead)
104 // - Error checking
105 // - ...Probably other things
106
107 IPC::ResponseBuilder rb{ctx, 4};
108 rb.Push(RESULT_SUCCESS);
109 rb.Push(addr);
110 LOG_WARNING(Service_LDR, "(STUBBED) called");
111 }
112
113 void Initialize(Kernel::HLERequestContext& ctx) {
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(RESULT_SUCCESS);
116 LOG_WARNING(Service_LDR, "(STUBBED) called");
117 }
72}; 118};
73 119
74void InstallInterfaces(SM::ServiceManager& sm) { 120void InstallInterfaces(SM::ServiceManager& sm) {
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 9a4eb9301..c1af878fe 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -328,13 +328,15 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
328 rb.PushIpcInterface<IUser>(*this); 328 rb.PushIpcInterface<IUser>(*this);
329} 329}
330 330
331void Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { 331bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
332 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); 332 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
333 if (buffer.size() < sizeof(AmiiboFile)) { 333 if (buffer.size() < sizeof(AmiiboFile)) {
334 return; // Failed to load file 334 return false;
335 } 335 }
336
336 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); 337 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
337 nfc_tag_load->Signal(); 338 nfc_tag_load->Signal();
339 return true;
338} 340}
339const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { 341const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const {
340 return nfc_tag_load; 342 return nfc_tag_load;
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 46370dedd..5c0ae8a54 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -32,7 +32,7 @@ public:
32 static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); 32 static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size");
33 33
34 void CreateUserInterface(Kernel::HLERequestContext& ctx); 34 void CreateUserInterface(Kernel::HLERequestContext& ctx);
35 void LoadAmiibo(const std::vector<u8>& buffer); 35 bool LoadAmiibo(const std::vector<u8>& buffer);
36 const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; 36 const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const;
37 const AmiiboFile& GetAmiiboBuffer() const; 37 const AmiiboFile& GetAmiiboBuffer() const;
38 38
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 243b499f2..bc8e402a8 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -127,18 +127,23 @@ static constexpr u32 PageAlignSize(u32 size) {
127 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 127 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
128} 128}
129 129
130bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { 130/*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name,
131 // Read NSO header 131 VAddr load_base) {
132 NroHeader nro_header{}; 132
133 if (sizeof(NroHeader) != file.ReadObject(&nro_header)) { 133 if (data.size() < sizeof(NroHeader)) {
134 return {}; 134 return {};
135 } 135 }
136
137 // Read NSO header
138 NroHeader nro_header{};
139 std::memcpy(&nro_header, data.data(), sizeof(NroHeader));
136 if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) { 140 if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) {
137 return {}; 141 return {};
138 } 142 }
139 143
140 // Build program image 144 // Build program image
141 std::vector<u8> program_image = file.ReadBytes(PageAlignSize(nro_header.file_size)); 145 std::vector<u8> program_image(PageAlignSize(nro_header.file_size));
146 std::memcpy(program_image.data(), data.data(), program_image.size());
142 if (program_image.size() != PageAlignSize(nro_header.file_size)) { 147 if (program_image.size() != PageAlignSize(nro_header.file_size)) {
143 return {}; 148 return {};
144 } 149 }
@@ -182,11 +187,15 @@ bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) {
182 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); 187 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base);
183 188
184 // Register module with GDBStub 189 // Register module with GDBStub
185 GDBStub::RegisterModule(file.GetName(), load_base, load_base); 190 GDBStub::RegisterModule(name, load_base, load_base);
186 191
187 return true; 192 return true;
188} 193}
189 194
195bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) {
196 return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base);
197}
198
190ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { 199ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
191 if (is_loaded) { 200 if (is_loaded) {
192 return ResultStatus::ErrorAlreadyLoaded; 201 return ResultStatus::ErrorAlreadyLoaded;
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 50ee5a78a..3e6959302 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <string> 7#include <string>
8#include <vector>
8#include "common/common_types.h" 9#include "common/common_types.h"
9#include "core/loader/linker.h" 10#include "core/loader/linker.h"
10#include "core/loader/loader.h" 11#include "core/loader/loader.h"
@@ -40,6 +41,8 @@ public:
40 ResultStatus ReadTitle(std::string& title) override; 41 ResultStatus ReadTitle(std::string& title) override;
41 bool IsRomFSUpdatable() const override; 42 bool IsRomFSUpdatable() const override;
42 43
44 static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base);
45
43private: 46private:
44 bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); 47 bool LoadNro(const FileSys::VfsFile& file, VAddr load_base);
45 48
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 0bc307e99..20ffb0a9a 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -21,12 +21,8 @@
21#include "yuzu/configuration/configure_system.h" 21#include "yuzu/configuration/configure_system.h"
22#include "yuzu/main.h" 22#include "yuzu/main.h"
23 23
24static std::string GetImagePath(Service::Account::UUID uuid) { 24namespace {
25 return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 25constexpr std::array<int, 12> days_in_month = {{
26 "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
27}
28
29static const std::array<int, 12> days_in_month = {{
30 31, 26 31,
31 29, 27 29,
32 31, 28 31,
@@ -42,7 +38,7 @@ static const std::array<int, 12> days_in_month = {{
42}}; 38}};
43 39
44// Same backup JPEG used by acc IProfile::GetImage if no jpeg found 40// Same backup JPEG used by acc IProfile::GetImage if no jpeg found
45static constexpr std::array<u8, 107> backup_jpeg{ 41constexpr std::array<u8, 107> backup_jpeg{
46 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 42 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
47 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05, 43 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05,
48 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, 44 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e,
@@ -52,15 +48,32 @@ static constexpr std::array<u8, 107> backup_jpeg{
52 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, 48 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9,
53}; 49};
54 50
51std::string GetImagePath(Service::Account::UUID uuid) {
52 return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
53 "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
54}
55
56std::string GetAccountUsername(const Service::Account::ProfileManager& manager,
57 Service::Account::UUID uuid) {
58 Service::Account::ProfileBase profile;
59 if (!manager.GetProfileBase(uuid, profile)) {
60 return "";
61 }
62
63 return Common::StringFromFixedZeroTerminatedBuffer(
64 reinterpret_cast<const char*>(profile.username.data()), profile.username.size());
65}
66} // Anonymous namespace
67
55ConfigureSystem::ConfigureSystem(QWidget* parent) 68ConfigureSystem::ConfigureSystem(QWidget* parent)
56 : QWidget(parent), ui(new Ui::ConfigureSystem), 69 : QWidget(parent), ui(new Ui::ConfigureSystem),
57 profile_manager(std::make_unique<Service::Account::ProfileManager>()) { 70 profile_manager(std::make_unique<Service::Account::ProfileManager>()) {
58 ui->setupUi(this); 71 ui->setupUi(this);
59 connect(ui->combo_birthmonth, 72 connect(ui->combo_birthmonth,
60 static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 73 static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
61 &ConfigureSystem::updateBirthdayComboBox); 74 &ConfigureSystem::UpdateBirthdayComboBox);
62 connect(ui->button_regenerate_console_id, &QPushButton::clicked, this, 75 connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
63 &ConfigureSystem::refreshConsoleID); 76 &ConfigureSystem::RefreshConsoleID);
64 77
65 layout = new QVBoxLayout; 78 layout = new QVBoxLayout;
66 tree_view = new QTreeView; 79 tree_view = new QTreeView;
@@ -154,7 +167,7 @@ void ConfigureSystem::UpdateCurrentUser() {
154 167
155 const auto& current_user = profile_manager->GetUser(Settings::values.current_user); 168 const auto& current_user = profile_manager->GetUser(Settings::values.current_user);
156 ASSERT(current_user != std::nullopt); 169 ASSERT(current_user != std::nullopt);
157 const auto username = GetAccountUsername(*current_user); 170 const auto username = GetAccountUsername(*profile_manager, *current_user);
158 171
159 scene->clear(); 172 scene->clear();
160 scene->addPixmap( 173 scene->addPixmap(
@@ -164,14 +177,6 @@ void ConfigureSystem::UpdateCurrentUser() {
164 177
165void ConfigureSystem::ReadSystemSettings() {} 178void ConfigureSystem::ReadSystemSettings() {}
166 179
167std::string ConfigureSystem::GetAccountUsername(Service::Account::UUID uuid) const {
168 Service::Account::ProfileBase profile;
169 if (!profile_manager->GetProfileBase(uuid, profile))
170 return "";
171 return Common::StringFromFixedZeroTerminatedBuffer(
172 reinterpret_cast<const char*>(profile.username.data()), profile.username.size());
173}
174
175void ConfigureSystem::applyConfiguration() { 180void ConfigureSystem::applyConfiguration() {
176 if (!enabled) 181 if (!enabled)
177 return; 182 return;
@@ -180,7 +185,7 @@ void ConfigureSystem::applyConfiguration() {
180 Settings::Apply(); 185 Settings::Apply();
181} 186}
182 187
183void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) { 188void ConfigureSystem::UpdateBirthdayComboBox(int birthmonth_index) {
184 if (birthmonth_index < 0 || birthmonth_index >= 12) 189 if (birthmonth_index < 0 || birthmonth_index >= 12)
185 return; 190 return;
186 191
@@ -205,7 +210,7 @@ void ConfigureSystem::updateBirthdayComboBox(int birthmonth_index) {
205 ui->combo_birthday->setCurrentIndex(birthday_index); 210 ui->combo_birthday->setCurrentIndex(birthday_index);
206} 211}
207 212
208void ConfigureSystem::refreshConsoleID() { 213void ConfigureSystem::RefreshConsoleID() {
209 QMessageBox::StandardButton reply; 214 QMessageBox::StandardButton reply;
210 QString warning_text = tr("This will replace your current virtual Switch with a new one. " 215 QString warning_text = tr("This will replace your current virtual Switch with a new one. "
211 "Your current virtual Switch will not be recoverable. " 216 "Your current virtual Switch will not be recoverable. "
@@ -232,8 +237,7 @@ void ConfigureSystem::SelectUser(const QModelIndex& index) {
232} 237}
233 238
234void ConfigureSystem::AddUser() { 239void ConfigureSystem::AddUser() {
235 Service::Account::UUID uuid; 240 const auto uuid = Service::Account::UUID::Generate();
236 uuid.Generate();
237 241
238 bool ok = false; 242 bool ok = false;
239 const auto username = 243 const auto username =
@@ -253,7 +257,7 @@ void ConfigureSystem::RenameUser() {
253 const auto user = tree_view->currentIndex().row(); 257 const auto user = tree_view->currentIndex().row();
254 const auto uuid = profile_manager->GetUser(user); 258 const auto uuid = profile_manager->GetUser(user);
255 ASSERT(uuid != std::nullopt); 259 ASSERT(uuid != std::nullopt);
256 const auto username = GetAccountUsername(*uuid); 260 const auto username = GetAccountUsername(*profile_manager, *uuid);
257 261
258 Service::Account::ProfileBase profile; 262 Service::Account::ProfileBase profile;
259 if (!profile_manager->GetProfileBase(*uuid, profile)) 263 if (!profile_manager->GetProfileBase(*uuid, profile))
@@ -293,7 +297,7 @@ void ConfigureSystem::DeleteUser() {
293 const auto index = tree_view->currentIndex().row(); 297 const auto index = tree_view->currentIndex().row();
294 const auto uuid = profile_manager->GetUser(index); 298 const auto uuid = profile_manager->GetUser(index);
295 ASSERT(uuid != std::nullopt); 299 ASSERT(uuid != std::nullopt);
296 const auto username = GetAccountUsername(*uuid); 300 const auto username = GetAccountUsername(*profile_manager, *uuid);
297 301
298 const auto confirm = 302 const auto confirm =
299 QMessageBox::question(this, tr("Confirm Delete"), 303 QMessageBox::question(this, tr("Confirm Delete"),
@@ -321,10 +325,10 @@ void ConfigureSystem::SetUserImage() {
321 const auto index = tree_view->currentIndex().row(); 325 const auto index = tree_view->currentIndex().row();
322 const auto uuid = profile_manager->GetUser(index); 326 const auto uuid = profile_manager->GetUser(index);
323 ASSERT(uuid != std::nullopt); 327 ASSERT(uuid != std::nullopt);
324 const auto username = GetAccountUsername(*uuid); 328 const auto username = GetAccountUsername(*profile_manager, *uuid);
325 329
326 const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), 330 const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(),
327 "JPEG Images (*.jpg *.jpeg)"); 331 tr("JPEG Images (*.jpg *.jpeg)"));
328 332
329 if (file.isEmpty()) 333 if (file.isEmpty())
330 return; 334 return;
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index b73e0719c..07764e1f7 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -9,17 +9,16 @@
9#include <QList> 9#include <QList>
10#include <QWidget> 10#include <QWidget>
11 11
12namespace Service::Account {
13class ProfileManager;
14struct UUID;
15} // namespace Service::Account
16
17class QGraphicsScene; 12class QGraphicsScene;
18class QStandardItem; 13class QStandardItem;
19class QStandardItemModel; 14class QStandardItemModel;
20class QTreeView; 15class QTreeView;
21class QVBoxLayout; 16class QVBoxLayout;
22 17
18namespace Service::Account {
19class ProfileManager;
20}
21
23namespace Ui { 22namespace Ui {
24class ConfigureSystem; 23class ConfigureSystem;
25} 24}
@@ -29,28 +28,25 @@ class ConfigureSystem : public QWidget {
29 28
30public: 29public:
31 explicit ConfigureSystem(QWidget* parent = nullptr); 30 explicit ConfigureSystem(QWidget* parent = nullptr);
32 ~ConfigureSystem(); 31 ~ConfigureSystem() override;
33 32
34 void applyConfiguration(); 33 void applyConfiguration();
35 void setConfiguration(); 34 void setConfiguration();
36 35
37 void PopulateUserList(); 36private:
38 void UpdateCurrentUser(); 37 void ReadSystemSettings();
39 38
40public slots: 39 void UpdateBirthdayComboBox(int birthmonth_index);
41 void updateBirthdayComboBox(int birthmonth_index); 40 void RefreshConsoleID();
42 void refreshConsoleID();
43 41
42 void PopulateUserList();
43 void UpdateCurrentUser();
44 void SelectUser(const QModelIndex& index); 44 void SelectUser(const QModelIndex& index);
45 void AddUser(); 45 void AddUser();
46 void RenameUser(); 46 void RenameUser();
47 void DeleteUser(); 47 void DeleteUser();
48 void SetUserImage(); 48 void SetUserImage();
49 49
50private:
51 void ReadSystemSettings();
52 std::string GetAccountUsername(Service::Account::UUID uuid) const;
53
54 QVBoxLayout* layout; 50 QVBoxLayout* layout;
55 QTreeView* tree_view; 51 QTreeView* tree_view;
56 QStandardItemModel* item_model; 52 QStandardItemModel* item_model;
@@ -59,11 +55,12 @@ private:
59 std::vector<QList<QStandardItem*>> list_items; 55 std::vector<QList<QStandardItem*>> list_items;
60 56
61 std::unique_ptr<Ui::ConfigureSystem> ui; 57 std::unique_ptr<Ui::ConfigureSystem> ui;
62 bool enabled; 58 bool enabled = false;
63 59
64 int birthmonth, birthday; 60 int birthmonth = 0;
65 int language_index; 61 int birthday = 0;
66 int sound_index; 62 int language_index = 0;
63 int sound_index = 0;
67 64
68 std::unique_ptr<Service::Account::ProfileManager> profile_manager; 65 std::unique_ptr<Service::Account::ProfileManager> profile_manager;
69}; 66};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 55508b1e1..b5bfa6741 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -30,6 +30,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
30#define QT_NO_OPENGL 30#define QT_NO_OPENGL
31#include <QDesktopWidget> 31#include <QDesktopWidget>
32#include <QDialogButtonBox> 32#include <QDialogButtonBox>
33#include <QFile>
33#include <QFileDialog> 34#include <QFileDialog>
34#include <QMessageBox> 35#include <QMessageBox>
35#include <QtConcurrent/QtConcurrent> 36#include <QtConcurrent/QtConcurrent>
@@ -1336,20 +1337,40 @@ void GMainWindow::OnLoadAmiibo() {
1336 const QString extensions{"*.bin"}; 1337 const QString extensions{"*.bin"};
1337 const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); 1338 const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);
1338 const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter); 1339 const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter);
1339 if (!filename.isEmpty()) { 1340
1340 Core::System& system{Core::System::GetInstance()}; 1341 if (filename.isEmpty()) {
1341 Service::SM::ServiceManager& sm = system.ServiceManager(); 1342 return;
1342 auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user"); 1343 }
1343 if (nfc != nullptr) { 1344
1344 auto nfc_file = FileUtil::IOFile(filename.toStdString(), "rb"); 1345 Core::System& system{Core::System::GetInstance()};
1345 if (!nfc_file.IsOpen()) { 1346 Service::SM::ServiceManager& sm = system.ServiceManager();
1346 return; 1347 auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user");
1347 } 1348 if (nfc == nullptr) {
1348 std::vector<u8> amiibo_buffer(nfc_file.GetSize()); 1349 return;
1349 nfc_file.ReadBytes(amiibo_buffer.data(), amiibo_buffer.size()); 1350 }
1350 nfc_file.Close(); 1351
1351 nfc->LoadAmiibo(amiibo_buffer); 1352 QFile nfc_file{filename};
1352 } 1353 if (!nfc_file.open(QIODevice::ReadOnly)) {
1354 QMessageBox::warning(this, tr("Error opening Amiibo data file"),
1355 tr("Unable to open Amiibo file \"%1\" for reading.").arg(filename));
1356 return;
1357 }
1358
1359 const u64 nfc_file_size = nfc_file.size();
1360 std::vector<u8> buffer(nfc_file_size);
1361 const u64 read_size = nfc_file.read(reinterpret_cast<char*>(buffer.data()), nfc_file_size);
1362 if (nfc_file_size != read_size) {
1363 QMessageBox::warning(this, tr("Error reading Amiibo data file"),
1364 tr("Unable to fully read Amiibo data. Expected to read %1 bytes, but "
1365 "was only able to read %2 bytes.")
1366 .arg(nfc_file_size)
1367 .arg(read_size));
1368 return;
1369 }
1370
1371 if (!nfc->LoadAmiibo(buffer)) {
1372 QMessageBox::warning(this, tr("Error loading Amiibo data"),
1373 tr("Unable to load Amiibo data."));
1353 } 1374 }
1354} 1375}
1355 1376