summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-08-11 19:25:30 -0400
committerGravatar GitHub2018-08-11 19:25:30 -0400
commitbc286c169fb8b07d21e082e05152cfd6bc611b33 (patch)
tree512bc4cca3adbe98a16cae454377c2ec2638b5e3 /src
parentMerge pull request #1018 from Subv/ssy_sync (diff)
parentgame_list: Reorder error checks (diff)
downloadyuzu-bc286c169fb8b07d21e082e05152cfd6bc611b33.tar.gz
yuzu-bc286c169fb8b07d21e082e05152cfd6bc611b33.tar.xz
yuzu-bc286c169fb8b07d21e082e05152cfd6bc611b33.zip
Merge pull request #970 from DarkLordZach/loader-errors
loader: Add more descriptive errors
Diffstat (limited to 'src')
-rw-r--r--src/core/core.cpp26
-rw-r--r--src/core/core.h24
-rw-r--r--src/core/file_sys/card_image.cpp19
-rw-r--r--src/core/file_sys/content_archive.cpp86
-rw-r--r--src/core/file_sys/content_archive.h5
-rw-r--r--src/core/file_sys/partition_filesystem.cpp8
-rw-r--r--src/core/file_sys/program_metadata.cpp12
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp14
-rw-r--r--src/core/loader/elf.cpp2
-rw-r--r--src/core/loader/loader.cpp49
-rw-r--r--src/core/loader/loader.h46
-rw-r--r--src/core/loader/nca.cpp10
-rw-r--r--src/core/loader/nro.cpp10
-rw-r--r--src/core/loader/xci.cpp11
-rw-r--r--src/yuzu/game_list.cpp5
-rw-r--r--src/yuzu/main.cpp76
-rw-r--r--src/yuzu_cmd/yuzu.cpp24
17 files changed, 248 insertions, 179 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 69c45c026..6b8004eb2 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -102,18 +102,8 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
102 LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", 102 LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
103 static_cast<int>(system_mode.second)); 103 static_cast<int>(system_mode.second));
104 104
105 switch (system_mode.second) { 105 if (system_mode.second != Loader::ResultStatus::Success)
106 case Loader::ResultStatus::ErrorMissingKeys:
107 return ResultStatus::ErrorLoader_ErrorMissingKeys;
108 case Loader::ResultStatus::ErrorDecrypting:
109 return ResultStatus::ErrorLoader_ErrorDecrypting;
110 case Loader::ResultStatus::ErrorInvalidFormat:
111 return ResultStatus::ErrorLoader_ErrorInvalidFormat;
112 case Loader::ResultStatus::ErrorUnsupportedArch:
113 return ResultStatus::ErrorUnsupportedArch;
114 default:
115 return ResultStatus::ErrorSystemMode; 106 return ResultStatus::ErrorSystemMode;
116 }
117 } 107 }
118 108
119 ResultStatus init_result{Init(emu_window)}; 109 ResultStatus init_result{Init(emu_window)};
@@ -129,17 +119,9 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
129 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); 119 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
130 System::Shutdown(); 120 System::Shutdown();
131 121
132 switch (load_result) { 122 if (load_result != Loader::ResultStatus::Success) {
133 case Loader::ResultStatus::ErrorMissingKeys: 123 return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
134 return ResultStatus::ErrorLoader_ErrorMissingKeys; 124 static_cast<u32>(load_result));
135 case Loader::ResultStatus::ErrorDecrypting:
136 return ResultStatus::ErrorLoader_ErrorDecrypting;
137 case Loader::ResultStatus::ErrorInvalidFormat:
138 return ResultStatus::ErrorLoader_ErrorInvalidFormat;
139 case Loader::ResultStatus::ErrorUnsupportedArch:
140 return ResultStatus::ErrorUnsupportedArch;
141 default:
142 return ResultStatus::ErrorLoader;
143 } 125 }
144 } 126 }
145 status = ResultStatus::Success; 127 status = ResultStatus::Success;
diff --git a/src/core/core.h b/src/core/core.h
index 7cf7ea4e1..2944b09cd 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -49,21 +49,15 @@ public:
49 49
50 /// Enumeration representing the return values of the System Initialize and Load process. 50 /// Enumeration representing the return values of the System Initialize and Load process.
51 enum class ResultStatus : u32 { 51 enum class ResultStatus : u32 {
52 Success, ///< Succeeded 52 Success, ///< Succeeded
53 ErrorNotInitialized, ///< Error trying to use core prior to initialization 53 ErrorNotInitialized, ///< Error trying to use core prior to initialization
54 ErrorGetLoader, ///< Error finding the correct application loader 54 ErrorGetLoader, ///< Error finding the correct application loader
55 ErrorSystemMode, ///< Error determining the system mode 55 ErrorSystemMode, ///< Error determining the system mode
56 ErrorLoader, ///< Error loading the specified application 56 ErrorSystemFiles, ///< Error in finding system files
57 ErrorLoader_ErrorMissingKeys, ///< Error because the key/keys needed to run could not be 57 ErrorSharedFont, ///< Error in finding shared font
58 ///< found. 58 ErrorVideoCore, ///< Error in the video core
59 ErrorLoader_ErrorDecrypting, ///< Error loading the specified application due to encryption 59 ErrorUnknown, ///< Any other error
60 ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an 60 ErrorLoader, ///< The base for loader errors (too many to repeat)
61 /// invalid format
62 ErrorSystemFiles, ///< Error in finding system files
63 ErrorSharedFont, ///< Error in finding shared font
64 ErrorVideoCore, ///< Error in the video core
65 ErrorUnsupportedArch, ///< Unsupported Architecture (32-Bit ROMs)
66 ErrorUnknown ///< Any other error
67 }; 61 };
68 62
69 /** 63 /**
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index e897d9913..a4823353e 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -12,14 +12,16 @@
12 12
13namespace FileSys { 13namespace FileSys {
14 14
15constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure", "logo"};
16
15XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) { 17XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
16 if (file->ReadObject(&header) != sizeof(GamecardHeader)) { 18 if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
17 status = Loader::ResultStatus::ErrorInvalidFormat; 19 status = Loader::ResultStatus::ErrorBadXCIHeader;
18 return; 20 return;
19 } 21 }
20 22
21 if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) { 23 if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) {
22 status = Loader::ResultStatus::ErrorInvalidFormat; 24 status = Loader::ResultStatus::ErrorBadXCIHeader;
23 return; 25 return;
24 } 26 }
25 27
@@ -31,9 +33,6 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
31 return; 33 return;
32 } 34 }
33 35
34 static constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure",
35 "logo"};
36
37 for (XCIPartition partition : 36 for (XCIPartition partition :
38 {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) { 37 {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
39 auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]); 38 auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]);
@@ -130,15 +129,21 @@ bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
130 129
131Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { 130Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
132 if (partitions[static_cast<size_t>(part)] == nullptr) { 131 if (partitions[static_cast<size_t>(part)] == nullptr) {
133 return Loader::ResultStatus::ErrorInvalidFormat; 132 return Loader::ResultStatus::ErrorXCIMissingPartition;
134 } 133 }
135 134
136 for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) { 135 for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) {
137 if (file->GetExtension() != "nca") 136 if (file->GetExtension() != "nca")
138 continue; 137 continue;
139 auto nca = std::make_shared<NCA>(file); 138 auto nca = std::make_shared<NCA>(file);
140 if (nca->GetStatus() == Loader::ResultStatus::Success) 139 if (nca->GetStatus() == Loader::ResultStatus::Success) {
141 ncas.push_back(std::move(nca)); 140 ncas.push_back(std::move(nca));
141 } else {
142 const u16 error_id = static_cast<u16>(nca->GetStatus());
143 LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})",
144 partition_names[static_cast<size_t>(part)], nca->GetName(), error_id,
145 Loader::GetMessageForResultStatus(nca->GetStatus()));
146 }
142 } 147 }
143 148
144 return Loader::ResultStatus::Success; 149 return Loader::ResultStatus::Success;
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index d3007d981..47afcad9b 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -113,17 +113,27 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty
113 return out; 113 return out;
114} 114}
115 115
116boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() const { 116boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
117 const auto master_key_id = GetCryptoRevision(); 117 const auto master_key_id = GetCryptoRevision();
118 118
119 u128 rights_id{}; 119 u128 rights_id{};
120 memcpy(rights_id.data(), header.rights_id.data(), 16); 120 memcpy(rights_id.data(), header.rights_id.data(), 16);
121 if (rights_id == u128{}) 121 if (rights_id == u128{}) {
122 status = Loader::ResultStatus::ErrorInvalidRightsID;
122 return boost::none; 123 return boost::none;
124 }
123 125
124 auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); 126 auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
125 if (titlekey == Core::Crypto::Key128{}) 127 if (titlekey == Core::Crypto::Key128{}) {
128 status = Loader::ResultStatus::ErrorMissingTitlekey;
129 return boost::none;
130 }
131
132 if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
133 status = Loader::ResultStatus::ErrorMissingTitlekek;
126 return boost::none; 134 return boost::none;
135 }
136
127 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( 137 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
128 keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id), Core::Crypto::Mode::ECB); 138 keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id), Core::Crypto::Mode::ECB);
129 cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(), Core::Crypto::Op::Decrypt); 139 cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(), Core::Crypto::Op::Decrypt);
@@ -131,7 +141,7 @@ boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() const {
131 return titlekey; 141 return titlekey;
132} 142}
133 143
134VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) const { 144VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) {
135 if (!encrypted) 145 if (!encrypted)
136 return in; 146 return in;
137 147
@@ -143,15 +153,22 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting
143 LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); 153 LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
144 { 154 {
145 boost::optional<Core::Crypto::Key128> key = boost::none; 155 boost::optional<Core::Crypto::Key128> key = boost::none;
146 if (std::find_if_not(header.rights_id.begin(), header.rights_id.end(), 156 if (has_rights_id) {
147 [](char c) { return c == 0; }) == header.rights_id.end()) { 157 status = Loader::ResultStatus::Success;
148 key = GetKeyAreaKey(NCASectionCryptoType::CTR);
149 } else {
150 key = GetTitlekey(); 158 key = GetTitlekey();
159 if (key == boost::none) {
160 if (status == Loader::ResultStatus::Success)
161 status = Loader::ResultStatus::ErrorMissingTitlekey;
162 return nullptr;
163 }
164 } else {
165 key = GetKeyAreaKey(NCASectionCryptoType::CTR);
166 if (key == boost::none) {
167 status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
168 return nullptr;
169 }
151 } 170 }
152 171
153 if (key == boost::none)
154 return nullptr;
155 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>( 172 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(
156 std::move(in), key.value(), starting_offset); 173 std::move(in), key.value(), starting_offset);
157 std::vector<u8> iv(16); 174 std::vector<u8> iv(16);
@@ -170,16 +187,31 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting
170} 187}
171 188
172NCA::NCA(VirtualFile file_) : file(std::move(file_)) { 189NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
190 status = Loader::ResultStatus::Success;
191
173 if (file == nullptr) { 192 if (file == nullptr) {
174 status = Loader::ResultStatus::ErrorInvalidFormat; 193 status = Loader::ResultStatus::ErrorNullFile;
175 return; 194 return;
176 } 195 }
177 if (sizeof(NCAHeader) != file->ReadObject(&header)) 196
197 if (sizeof(NCAHeader) != file->ReadObject(&header)) {
178 LOG_ERROR(Loader, "File reader errored out during header read."); 198 LOG_ERROR(Loader, "File reader errored out during header read.");
199 status = Loader::ResultStatus::ErrorBadNCAHeader;
200 return;
201 }
179 202
180 encrypted = false; 203 encrypted = false;
181 204
182 if (!IsValidNCA(header)) { 205 if (!IsValidNCA(header)) {
206 if (header.magic == Common::MakeMagic('N', 'C', 'A', '2')) {
207 status = Loader::ResultStatus::ErrorNCA2;
208 return;
209 }
210 if (header.magic == Common::MakeMagic('N', 'C', 'A', '0')) {
211 status = Loader::ResultStatus::ErrorNCA0;
212 return;
213 }
214
183 NCAHeader dec_header{}; 215 NCAHeader dec_header{};
184 Core::Crypto::AESCipher<Core::Crypto::Key256> cipher( 216 Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
185 keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS); 217 keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
@@ -189,14 +221,26 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
189 header = dec_header; 221 header = dec_header;
190 encrypted = true; 222 encrypted = true;
191 } else { 223 } else {
224 if (dec_header.magic == Common::MakeMagic('N', 'C', 'A', '2')) {
225 status = Loader::ResultStatus::ErrorNCA2;
226 return;
227 }
228 if (dec_header.magic == Common::MakeMagic('N', 'C', 'A', '0')) {
229 status = Loader::ResultStatus::ErrorNCA0;
230 return;
231 }
232
192 if (!keys.HasKey(Core::Crypto::S256KeyType::Header)) 233 if (!keys.HasKey(Core::Crypto::S256KeyType::Header))
193 status = Loader::ResultStatus::ErrorMissingKeys; 234 status = Loader::ResultStatus::ErrorMissingHeaderKey;
194 else 235 else
195 status = Loader::ResultStatus::ErrorDecrypting; 236 status = Loader::ResultStatus::ErrorIncorrectHeaderKey;
196 return; 237 return;
197 } 238 }
198 } 239 }
199 240
241 has_rights_id = std::find_if_not(header.rights_id.begin(), header.rights_id.end(),
242 [](char c) { return c == '\0'; }) != header.rights_id.end();
243
200 const std::ptrdiff_t number_sections = 244 const std::ptrdiff_t number_sections =
201 std::count_if(std::begin(header.section_tables), std::end(header.section_tables), 245 std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
202 [](NCASectionTableEntry entry) { return entry.media_offset > 0; }); 246 [](NCASectionTableEntry entry) { return entry.media_offset > 0; });
@@ -229,7 +273,12 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
229 files.push_back(std::move(dec)); 273 files.push_back(std::move(dec));
230 romfs = files.back(); 274 romfs = files.back();
231 } else { 275 } else {
232 status = Loader::ResultStatus::ErrorMissingKeys; 276 if (status != Loader::ResultStatus::Success)
277 return;
278 if (has_rights_id)
279 status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
280 else
281 status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey;
233 return; 282 return;
234 } 283 }
235 } else if (section.raw.header.filesystem_type == NCASectionFilesystemType::PFS0) { 284 } else if (section.raw.header.filesystem_type == NCASectionFilesystemType::PFS0) {
@@ -249,7 +298,12 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
249 exefs = dirs.back(); 298 exefs = dirs.back();
250 } 299 }
251 } else { 300 } else {
252 status = Loader::ResultStatus::ErrorMissingKeys; 301 if (status != Loader::ResultStatus::Success)
302 return;
303 if (has_rights_id)
304 status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
305 else
306 status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey;
253 return; 307 return;
254 } 308 }
255 } 309 }
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 5cfd5031a..b82e65ad5 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -98,8 +98,8 @@ protected:
98private: 98private:
99 u8 GetCryptoRevision() const; 99 u8 GetCryptoRevision() const;
100 boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const; 100 boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const;
101 boost::optional<Core::Crypto::Key128> GetTitlekey() const; 101 boost::optional<Core::Crypto::Key128> GetTitlekey();
102 VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset) const; 102 VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset);
103 103
104 std::vector<VirtualDir> dirs; 104 std::vector<VirtualDir> dirs;
105 std::vector<VirtualFile> files; 105 std::vector<VirtualFile> files;
@@ -109,6 +109,7 @@ private:
109 VirtualFile file; 109 VirtualFile file;
110 110
111 NCAHeader header{}; 111 NCAHeader header{};
112 bool has_rights_id{};
112 113
113 Loader::ResultStatus status{}; 114 Loader::ResultStatus status{};
114 115
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 47e032b19..c377edc9c 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -24,19 +24,19 @@ bool PartitionFilesystem::Header::HasValidMagicValue() const {
24PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) { 24PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
25 // At least be as large as the header 25 // At least be as large as the header
26 if (file->GetSize() < sizeof(Header)) { 26 if (file->GetSize() < sizeof(Header)) {
27 status = Loader::ResultStatus::Error; 27 status = Loader::ResultStatus::ErrorBadPFSHeader;
28 return; 28 return;
29 } 29 }
30 30
31 // For cartridges, HFSs can get very large, so we need to calculate the size up to 31 // For cartridges, HFSs can get very large, so we need to calculate the size up to
32 // the actual content itself instead of just blindly reading in the entire file. 32 // the actual content itself instead of just blindly reading in the entire file.
33 if (sizeof(Header) != file->ReadObject(&pfs_header)) { 33 if (sizeof(Header) != file->ReadObject(&pfs_header)) {
34 status = Loader::ResultStatus::Error; 34 status = Loader::ResultStatus::ErrorBadPFSHeader;
35 return; 35 return;
36 } 36 }
37 37
38 if (!pfs_header.HasValidMagicValue()) { 38 if (!pfs_header.HasValidMagicValue()) {
39 status = Loader::ResultStatus::ErrorInvalidFormat; 39 status = Loader::ResultStatus::ErrorBadPFSHeader;
40 return; 40 return;
41 } 41 }
42 42
@@ -51,7 +51,7 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
51 const size_t total_size = file_data.size(); 51 const size_t total_size = file_data.size();
52 52
53 if (total_size != metadata_size) { 53 if (total_size != metadata_size) {
54 status = Loader::ResultStatus::Error; 54 status = Loader::ResultStatus::ErrorIncorrectPFSFileSize;
55 return; 55 return;
56 } 56 }
57 57
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 63d4b6e4f..279f987d4 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -12,26 +12,26 @@ namespace FileSys {
12Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { 12Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
13 size_t total_size = static_cast<size_t>(file->GetSize()); 13 size_t total_size = static_cast<size_t>(file->GetSize());
14 if (total_size < sizeof(Header)) 14 if (total_size < sizeof(Header))
15 return Loader::ResultStatus::Error; 15 return Loader::ResultStatus::ErrorBadNPDMHeader;
16 16
17 // TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable. 17 // TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable.
18 std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header)); 18 std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header));
19 if (sizeof(Header) != npdm_header_data.size()) 19 if (sizeof(Header) != npdm_header_data.size())
20 return Loader::ResultStatus::Error; 20 return Loader::ResultStatus::ErrorBadNPDMHeader;
21 std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header)); 21 std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header));
22 22
23 std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset); 23 std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset);
24 if (sizeof(AcidHeader) != acid_header_data.size()) 24 if (sizeof(AcidHeader) != acid_header_data.size())
25 return Loader::ResultStatus::Error; 25 return Loader::ResultStatus::ErrorBadACIDHeader;
26 std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader)); 26 std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader));
27 27
28 if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) 28 if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset))
29 return Loader::ResultStatus::Error; 29 return Loader::ResultStatus::ErrorBadACIHeader;
30 30
31 if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) 31 if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset))
32 return Loader::ResultStatus::Error; 32 return Loader::ResultStatus::ErrorBadFileAccessControl;
33 if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) 33 if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset))
34 return Loader::ResultStatus::Error; 34 return Loader::ResultStatus::ErrorBadFileAccessHeader;
35 35
36 return Loader::ResultStatus::Success; 36 return Loader::ResultStatus::Success;
37} 37}
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 915d525b0..de05f21d8 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -83,13 +83,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
83 83
84 if (dir == nullptr) { 84 if (dir == nullptr) {
85 if (file == nullptr) 85 if (file == nullptr)
86 return ResultStatus::ErrorInvalidFormat; 86 return ResultStatus::ErrorNullFile;
87 dir = file->GetContainingDirectory(); 87 dir = file->GetContainingDirectory();
88 } 88 }
89 89
90 const FileSys::VirtualFile npdm = dir->GetFile("main.npdm"); 90 const FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
91 if (npdm == nullptr) 91 if (npdm == nullptr)
92 return ResultStatus::ErrorInvalidFormat; 92 return ResultStatus::ErrorMissingNPDM;
93 93
94 ResultStatus result = metadata.Load(npdm); 94 ResultStatus result = metadata.Load(npdm);
95 if (result != ResultStatus::Success) { 95 if (result != ResultStatus::Success) {
@@ -99,7 +99,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
99 99
100 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; 100 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
101 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) { 101 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
102 return ResultStatus::ErrorUnsupportedArch; 102 return ResultStatus::Error32BitISA;
103 } 103 }
104 104
105 // Load NSO modules 105 // Load NSO modules
@@ -143,28 +143,28 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
143 143
144ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) { 144ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) {
145 if (romfs == nullptr) 145 if (romfs == nullptr)
146 return ResultStatus::ErrorNotUsed; 146 return ResultStatus::ErrorNoRomFS;
147 dir = romfs; 147 dir = romfs;
148 return ResultStatus::Success; 148 return ResultStatus::Success;
149} 149}
150 150
151ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) { 151ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) {
152 if (icon_data.empty()) 152 if (icon_data.empty())
153 return ResultStatus::ErrorNotUsed; 153 return ResultStatus::ErrorNoIcon;
154 buffer = icon_data; 154 buffer = icon_data;
155 return ResultStatus::Success; 155 return ResultStatus::Success;
156} 156}
157 157
158ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { 158ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) {
159 if (name.empty()) 159 if (name.empty())
160 return ResultStatus::ErrorNotUsed; 160 return ResultStatus::ErrorNoControl;
161 out_program_id = title_id; 161 out_program_id = title_id;
162 return ResultStatus::Success; 162 return ResultStatus::Success;
163} 163}
164 164
165ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) { 165ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) {
166 if (name.empty()) 166 if (name.empty())
167 return ResultStatus::ErrorNotUsed; 167 return ResultStatus::ErrorNoControl;
168 title = name; 168 title = name;
169 return ResultStatus::Success; 169 return ResultStatus::Success;
170} 170}
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index a7133f5a6..401cad3ab 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -390,7 +390,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
390 390
391 std::vector<u8> buffer = file->ReadAllBytes(); 391 std::vector<u8> buffer = file->ReadAllBytes();
392 if (buffer.size() != file->GetSize()) 392 if (buffer.size() != file->GetSize())
393 return ResultStatus::Error; 393 return ResultStatus::ErrorIncorrectELFFileSize;
394 394
395 ElfReader elf_reader(&buffer[0]); 395 ElfReader elf_reader(&buffer[0]);
396 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); 396 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index a288654df..2f5bfc67c 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -86,6 +86,55 @@ std::string GetFileTypeString(FileType type) {
86 return "unknown"; 86 return "unknown";
87} 87}
88 88
89constexpr std::array<const char*, 36> RESULT_MESSAGES{
90 "The operation completed successfully.",
91 "The loader requested to load is already loaded.",
92 "The operation is not implemented.",
93 "The loader is not initialized properly.",
94 "The NPDM file has a bad header.",
95 "The NPDM has a bad ACID header.",
96 "The NPDM has a bad ACI header,",
97 "The NPDM file has a bad file access control.",
98 "The NPDM has a bad file access header.",
99 "The PFS/HFS partition has a bad header.",
100 "The PFS/HFS partition has incorrect size as determined by the header.",
101 "The NCA file has a bad header.",
102 "The general keyfile could not be found.",
103 "The NCA Header key could not be found.",
104 "The NCA Header key is incorrect or the header is invalid.",
105 "Support for NCA2-type NCAs is not implemented.",
106 "Support for NCA0-type NCAs is not implemented.",
107 "The titlekey for this Rights ID could not be found.",
108 "The titlekek for this crypto revision could not be found.",
109 "The Rights ID in the header is invalid.",
110 "The key area key for this application type and crypto revision could not be found.",
111 "The key area key is incorrect or the section header is invalid.",
112 "The titlekey and/or titlekek is incorrect or the section header is invalid.",
113 "The XCI file is missing a Program-type NCA.",
114 "The NCA file is not an application.",
115 "The ExeFS partition could not be found.",
116 "The XCI file has a bad header.",
117 "The XCI file is missing a partition.",
118 "The file could not be found or does not exist.",
119 "The game is missing a program metadata file (main.npdm).",
120 "The game uses the currently-unimplemented 32-bit architecture.",
121 "The RomFS could not be found.",
122 "The ELF file has incorrect size as determined by the header.",
123 "There was a general error loading the NRO into emulated memory.",
124 "There is no icon available.",
125 "There is no control data available.",
126};
127
128std::string GetMessageForResultStatus(ResultStatus status) {
129 return GetMessageForResultStatus(static_cast<size_t>(status));
130}
131
132std::string GetMessageForResultStatus(u16 status) {
133 if (status >= 36)
134 return "";
135 return RESULT_MESSAGES[status];
136}
137
89/** 138/**
90 * Get a loader for a file with a specific type 139 * Get a loader for a file with a specific type
91 * @param file The file to load 140 * @param file The file to load
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 6a9e5a68b..cfdadbee3 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -58,18 +58,46 @@ std::string GetFileTypeString(FileType type);
58/// Return type for functions in Loader namespace 58/// Return type for functions in Loader namespace
59enum class ResultStatus { 59enum class ResultStatus {
60 Success, 60 Success,
61 Error,
62 ErrorInvalidFormat,
63 ErrorNotImplemented,
64 ErrorNotLoaded,
65 ErrorNotUsed,
66 ErrorAlreadyLoaded, 61 ErrorAlreadyLoaded,
67 ErrorMemoryAllocationFailed, 62 ErrorNotImplemented,
68 ErrorMissingKeys, 63 ErrorNotInitialized,
69 ErrorDecrypting, 64 ErrorBadNPDMHeader,
70 ErrorUnsupportedArch, 65 ErrorBadACIDHeader,
66 ErrorBadACIHeader,
67 ErrorBadFileAccessControl,
68 ErrorBadFileAccessHeader,
69 ErrorBadPFSHeader,
70 ErrorIncorrectPFSFileSize,
71 ErrorBadNCAHeader,
72 ErrorMissingProductionKeyFile,
73 ErrorMissingHeaderKey,
74 ErrorIncorrectHeaderKey,
75 ErrorNCA2,
76 ErrorNCA0,
77 ErrorMissingTitlekey,
78 ErrorMissingTitlekek,
79 ErrorInvalidRightsID,
80 ErrorMissingKeyAreaKey,
81 ErrorIncorrectKeyAreaKey,
82 ErrorIncorrectTitlekeyOrTitlekek,
83 ErrorXCIMissingProgramNCA,
84 ErrorNCANotProgram,
85 ErrorNoExeFS,
86 ErrorBadXCIHeader,
87 ErrorXCIMissingPartition,
88 ErrorNullFile,
89 ErrorMissingNPDM,
90 Error32BitISA,
91 ErrorNoRomFS,
92 ErrorIncorrectELFFileSize,
93 ErrorLoadingNRO,
94 ErrorNoIcon,
95 ErrorNoControl,
71}; 96};
72 97
98std::string GetMessageForResultStatus(ResultStatus status);
99std::string GetMessageForResultStatus(u16 status);
100
73/// Interface for loading an application 101/// Interface for loading an application
74class AppLoader : NonCopyable { 102class AppLoader : NonCopyable {
75public: 103public:
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 46f5cd393..8498cc94b 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -46,12 +46,12 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
46 } 46 }
47 47
48 if (nca->GetType() != FileSys::NCAContentType::Program) 48 if (nca->GetType() != FileSys::NCAContentType::Program)
49 return ResultStatus::ErrorInvalidFormat; 49 return ResultStatus::ErrorNCANotProgram;
50 50
51 const auto exefs = nca->GetExeFS(); 51 const auto exefs = nca->GetExeFS();
52 52
53 if (exefs == nullptr) 53 if (exefs == nullptr)
54 return ResultStatus::ErrorInvalidFormat; 54 return ResultStatus::ErrorNoExeFS;
55 55
56 directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs); 56 directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs);
57 57
@@ -69,16 +69,16 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
69 69
70ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { 70ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
71 if (nca == nullptr) 71 if (nca == nullptr)
72 return ResultStatus::ErrorNotLoaded; 72 return ResultStatus::ErrorNotInitialized;
73 if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0) 73 if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0)
74 return ResultStatus::ErrorNotUsed; 74 return ResultStatus::ErrorNoRomFS;
75 dir = nca->GetRomFS(); 75 dir = nca->GetRomFS();
76 return ResultStatus::Success; 76 return ResultStatus::Success;
77} 77}
78 78
79ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { 79ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
80 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) 80 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
81 return ResultStatus::ErrorInvalidFormat; 81 return ResultStatus::ErrorNotInitialized;
82 out_program_id = nca->GetTitleId(); 82 out_program_id = nca->GetTitleId();
83 return ResultStatus::Success; 83 return ResultStatus::Success;
84} 84}
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index dc053cdad..908d91eab 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -182,7 +182,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
182 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; 182 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
183 183
184 if (!LoadNro(file, base_addr)) { 184 if (!LoadNro(file, base_addr)) {
185 return ResultStatus::ErrorInvalidFormat; 185 return ResultStatus::ErrorLoadingNRO;
186 } 186 }
187 187
188 process->svc_access_mask.set(); 188 process->svc_access_mask.set();
@@ -197,7 +197,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
197 197
198ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { 198ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
199 if (icon_data.empty()) { 199 if (icon_data.empty()) {
200 return ResultStatus::ErrorNotUsed; 200 return ResultStatus::ErrorNoIcon;
201 } 201 }
202 202
203 buffer = icon_data; 203 buffer = icon_data;
@@ -206,7 +206,7 @@ ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
206 206
207ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) { 207ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
208 if (nacp == nullptr) { 208 if (nacp == nullptr) {
209 return ResultStatus::ErrorNotUsed; 209 return ResultStatus::ErrorNoControl;
210 } 210 }
211 211
212 out_program_id = nacp->GetTitleId(); 212 out_program_id = nacp->GetTitleId();
@@ -215,7 +215,7 @@ ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
215 215
216ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) { 216ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
217 if (romfs == nullptr) { 217 if (romfs == nullptr) {
218 return ResultStatus::ErrorNotUsed; 218 return ResultStatus::ErrorNoRomFS;
219 } 219 }
220 220
221 dir = romfs; 221 dir = romfs;
@@ -224,7 +224,7 @@ ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
224 224
225ResultStatus AppLoader_NRO::ReadTitle(std::string& title) { 225ResultStatus AppLoader_NRO::ReadTitle(std::string& title) {
226 if (nacp == nullptr) { 226 if (nacp == nullptr) {
227 return ResultStatus::ErrorNotUsed; 227 return ResultStatus::ErrorNoControl;
228 } 228 }
229 229
230 title = nacp->GetApplicationName(); 230 title = nacp->GetApplicationName();
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index d3fe24419..5d67fb186 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -66,10 +66,13 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) {
66 return ResultStatus::ErrorAlreadyLoaded; 66 return ResultStatus::ErrorAlreadyLoaded;
67 } 67 }
68 68
69 if (xci->GetStatus() != ResultStatus::Success)
70 return xci->GetStatus();
71
69 if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) { 72 if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) {
70 if (!Core::Crypto::KeyManager::KeyFileExists(false)) 73 if (!Core::Crypto::KeyManager::KeyFileExists(false))
71 return ResultStatus::ErrorMissingKeys; 74 return ResultStatus::ErrorMissingProductionKeyFile;
72 return ResultStatus::ErrorDecrypting; 75 return ResultStatus::ErrorXCIMissingProgramNCA;
73 } 76 }
74 77
75 auto result = nca_loader->Load(process); 78 auto result = nca_loader->Load(process);
@@ -91,14 +94,14 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
91 94
92ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { 95ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
93 if (icon_file == nullptr) 96 if (icon_file == nullptr)
94 return ResultStatus::ErrorInvalidFormat; 97 return ResultStatus::ErrorNoControl;
95 buffer = icon_file->ReadAllBytes(); 98 buffer = icon_file->ReadAllBytes();
96 return ResultStatus::Success; 99 return ResultStatus::Success;
97} 100}
98 101
99ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { 102ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
100 if (nacp_file == nullptr) 103 if (nacp_file == nullptr)
101 return ResultStatus::ErrorInvalidFormat; 104 return ResultStatus::ErrorNoControl;
102 title = nacp_file->GetApplicationName(); 105 title = nacp_file->GetApplicationName();
103 return ResultStatus::Success; 106 return ResultStatus::Success;
104} 107}
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 1c738d2a4..85cb12594 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -453,10 +453,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
453 std::string name = " "; 453 std::string name = " ";
454 const auto res3 = loader->ReadTitle(name); 454 const auto res3 = loader->ReadTitle(name);
455 455
456 if ((res1 == Loader::ResultStatus::ErrorNotUsed || 456 if (res1 != Loader::ResultStatus::Success && res3 != Loader::ResultStatus::Success &&
457 res1 == Loader::ResultStatus::ErrorNotImplemented) &&
458 (res3 == Loader::ResultStatus::ErrorNotUsed ||
459 res3 == Loader::ResultStatus::ErrorNotImplemented) &&
460 res2 == Loader::ResultStatus::Success) { 457 res2 == Loader::ResultStatus::Success) {
461 // Use from metadata pool. 458 // Use from metadata pool.
462 if (nca_control_map.find(program_id) != nca_control_map.end()) { 459 if (nca_control_map.find(program_id) != nca_control_map.end()) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 67e3c6549..94fb8ae6a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -424,67 +424,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
424 QMessageBox::critical(this, tr("Error while loading ROM!"), 424 QMessageBox::critical(this, tr("Error while loading ROM!"),
425 tr("The ROM format is not supported.")); 425 tr("The ROM format is not supported."));
426 break; 426 break;
427 case Core::System::ResultStatus::ErrorUnsupportedArch:
428 LOG_CRITICAL(Frontend, "Unsupported architecture detected!", filename.toStdString());
429 QMessageBox::critical(this, tr("Error while loading ROM!"),
430 tr("The ROM uses currently unusable 32-bit architecture"));
431 break;
432 case Core::System::ResultStatus::ErrorSystemMode: 427 case Core::System::ResultStatus::ErrorSystemMode:
433 LOG_CRITICAL(Frontend, "Failed to load ROM!"); 428 LOG_CRITICAL(Frontend, "Failed to load ROM!");
434 QMessageBox::critical(this, tr("Error while loading ROM!"), 429 QMessageBox::critical(this, tr("Error while loading ROM!"),
435 tr("Could not determine the system mode.")); 430 tr("Could not determine the system mode."));
436 break; 431 break;
437
438 case Core::System::ResultStatus::ErrorLoader_ErrorMissingKeys: {
439 const auto reg_found = Core::Crypto::KeyManager::KeyFileExists(false);
440 const auto title_found = Core::Crypto::KeyManager::KeyFileExists(true);
441
442 std::string file_text;
443
444 if (!reg_found && !title_found) {
445 file_text = "A proper key file (prod.keys, dev.keys, or title.keys) could not be "
446 "found. You will need to dump your keys from your switch to continue.";
447 } else if (reg_found && title_found) {
448 file_text =
449 "Both key files were found in your config directory, but the correct key could"
450 "not be found. You may be missing a titlekey or general key, depending on "
451 "the game.";
452 } else if (reg_found) {
453 file_text =
454 "The regular keys file (prod.keys/dev.keys) was found in your config, but the "
455 "titlekeys file (title.keys) was not. You are either missing the correct "
456 "titlekey or missing a general key required to decrypt the game.";
457 } else {
458 file_text = "The title keys file (title.keys) was found in your config, but "
459 "the regular keys file (prod.keys/dev.keys) was not. Unfortunately, "
460 "having the titlekey is not enough, you need additional general keys "
461 "to properly decrypt the game. You should double-check to make sure "
462 "your keys are correct.";
463 }
464
465 QMessageBox::critical(
466 this, tr("Error while loading ROM!"),
467 tr(("The game you are trying to load is encrypted and the required keys to load "
468 "the game could not be found in your configuration. " +
469 file_text + " Please refer to the yuzu wiki for help.")
470 .c_str()));
471 break;
472 }
473 case Core::System::ResultStatus::ErrorLoader_ErrorDecrypting: {
474 QMessageBox::critical(
475 this, tr("Error while loading ROM!"),
476 tr("There was a general error while decrypting the game. This means that the keys "
477 "necessary were found, but were either incorrect, the game itself was not a "
478 "valid game or the game uses an unhandled cryptographic scheme. Please double "
479 "check that you have the correct "
480 "keys."));
481 break;
482 }
483 case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
484 QMessageBox::critical(this, tr("Error while loading ROM!"),
485 tr("The ROM format is not supported."));
486 break;
487
488 case Core::System::ResultStatus::ErrorVideoCore: 432 case Core::System::ResultStatus::ErrorVideoCore:
489 QMessageBox::critical( 433 QMessageBox::critical(
490 this, tr("An error occurred initializing the video core."), 434 this, tr("An error occurred initializing the video core."),
@@ -499,9 +443,23 @@ bool GMainWindow::LoadROM(const QString& filename) {
499 break; 443 break;
500 444
501 default: 445 default:
502 QMessageBox::critical( 446 if (static_cast<u32>(result) >
503 this, tr("Error while loading ROM!"), 447 static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
504 tr("An unknown error occurred. Please see the log for more details.")); 448 LOG_CRITICAL(Frontend, "Failed to load ROM!");
449 const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
450 const u16 error_id = static_cast<u16>(result) - loader_id;
451 QMessageBox::critical(
452 this, tr("Error while loading ROM!"),
453 QString::fromStdString(fmt::format(
454 "While attempting to load the ROM requested, an error occured. Please "
455 "refer to the yuzu wiki for more information or the yuzu discord for "
456 "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
457 loader_id, error_id, Loader::GetMessageForResultStatus(error_id))));
458 } else {
459 QMessageBox::critical(
460 this, tr("Error while loading ROM!"),
461 tr("An unknown error occurred. Please see the log for more details."));
462 }
505 break; 463 break;
506 } 464 }
507 return false; 465 return false;
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 0605c92e3..e44a98311 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -174,19 +174,6 @@ int main(int argc, char** argv) {
174 case Core::System::ResultStatus::ErrorLoader: 174 case Core::System::ResultStatus::ErrorLoader:
175 LOG_CRITICAL(Frontend, "Failed to load ROM!"); 175 LOG_CRITICAL(Frontend, "Failed to load ROM!");
176 return -1; 176 return -1;
177 case Core::System::ResultStatus::ErrorLoader_ErrorMissingKeys:
178 LOG_CRITICAL(Frontend, "The game you are trying to load is encrypted and the keys required "
179 "could not be found. Please refer to the yuzu wiki for help");
180 return -1;
181 case Core::System::ResultStatus::ErrorLoader_ErrorDecrypting:
182 LOG_CRITICAL(Frontend, "The game you are trying to load is encrypted and there was a "
183 "general error while decrypting. This could mean that the keys are "
184 "incorrect, game is invalid or game uses an unsupported method of "
185 "crypto. Please double-check your keys");
186 return -1;
187 case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
188 LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported.");
189 return -1;
190 case Core::System::ResultStatus::ErrorNotInitialized: 177 case Core::System::ResultStatus::ErrorNotInitialized:
191 LOG_CRITICAL(Frontend, "CPUCore not initialized"); 178 LOG_CRITICAL(Frontend, "CPUCore not initialized");
192 return -1; 179 return -1;
@@ -198,6 +185,17 @@ int main(int argc, char** argv) {
198 return -1; 185 return -1;
199 case Core::System::ResultStatus::Success: 186 case Core::System::ResultStatus::Success:
200 break; // Expected case 187 break; // Expected case
188 default:
189 if (static_cast<u32>(load_result) >
190 static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
191 const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
192 const u16 error_id = static_cast<u16>(load_result) - loader_id;
193 LOG_CRITICAL(Frontend,
194 "While attempting to load the ROM requested, an error occured. Please "
195 "refer to the yuzu wiki for more information or the yuzu discord for "
196 "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
197 loader_id, error_id, Loader::GetMessageForResultStatus(error_id));
198 }
201 } 199 }
202 200
203 Core::Telemetry().AddField(Telemetry::FieldType::App, "Frontend", "SDL"); 201 Core::Telemetry().AddField(Telemetry::FieldType::App, "Frontend", "SDL");