summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/archive.cpp
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2014-10-23 01:20:01 -0200
committerGravatar Yuri Kunde Schlesner2014-11-24 17:08:36 -0200
commitc2588403c0b8cf198f13f903f626851c7e94266c (patch)
tree09d26cdae187a47338caf94943291c60b4a40a4c /src/core/hle/kernel/archive.cpp
parentChange some SkyEye defines to const ints (diff)
downloadyuzu-c2588403c0b8cf198f13f903f626851c7e94266c.tar.gz
yuzu-c2588403c0b8cf198f13f903f626851c7e94266c.tar.xz
yuzu-c2588403c0b8cf198f13f903f626851c7e94266c.zip
HLE: Revamp error handling throrough the HLE code
All service calls in the CTR OS return result codes indicating the success or failure of the call. Previous to this commit, Citra's HLE emulation of services and the kernel universally either ignored errors or returned dummy -1 error codes. This commit makes an initial effort to provide an infrastructure for error reporting and propagation which can be use going forward to make HLE calls accurately return errors as the original system. A few parts of the code have been updated to use the new system where applicable. One part of this effort is the definition of the `ResultCode` type, which provides facilities for constructing and parsing error codes in the structured format used by the CTR. The `ResultVal` type builds on `ResultCode` by providing a container for values returned by function that can report errors. It enforces that correct error checking will be done on function returns by preventing the use of the return value if the function returned an error code. Currently this change is mostly internal since errors are still suppressed on the ARM<->HLE border, as a temporary compatibility hack. As functionality is implemented and tested this hack can be eventually removed.
Diffstat (limited to 'src/core/hle/kernel/archive.cpp')
-rw-r--r--src/core/hle/kernel/archive.cpp147
1 files changed, 65 insertions, 82 deletions
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
index 900f484c7..e11dddc84 100644
--- a/src/core/hle/kernel/archive.cpp
+++ b/src/core/hle/kernel/archive.cpp
@@ -9,8 +9,9 @@
9#include "core/file_sys/archive.h" 9#include "core/file_sys/archive.h"
10#include "core/file_sys/archive_sdmc.h" 10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory.h" 11#include "core/file_sys/directory.h"
12#include "core/hle/service/service.h"
13#include "core/hle/kernel/archive.h" 12#include "core/hle/kernel/archive.h"
13#include "core/hle/result.h"
14#include "core/hle/service/service.h"
14 15
15//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
16// Kernel namespace 17// Kernel namespace
@@ -56,7 +57,7 @@ public:
56 * @param wait Boolean wait set if current thread should wait as a result of sync operation 57 * @param wait Boolean wait set if current thread should wait as a result of sync operation
57 * @return Result of operation, 0 on success, otherwise error code 58 * @return Result of operation, 0 on success, otherwise error code
58 */ 59 */
59 Result SyncRequest(bool* wait) override { 60 ResultVal<bool> SyncRequest() override {
60 u32* cmd_buff = Service::GetCommandBuffer(); 61 u32* cmd_buff = Service::GetCommandBuffer();
61 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 62 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
62 63
@@ -106,11 +107,11 @@ public:
106 default: 107 default:
107 { 108 {
108 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 109 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
109 return -1; 110 return UnimplementedFunction(ErrorModule::FS);
110 } 111 }
111 } 112 }
112 cmd_buff[1] = 0; // No error 113 cmd_buff[1] = 0; // No error
113 return 0; 114 return MakeResult<bool>(false);
114 } 115 }
115 116
116 /** 117 /**
@@ -118,10 +119,10 @@ public:
118 * @param wait Boolean wait set if current thread should wait as a result of sync operation 119 * @param wait Boolean wait set if current thread should wait as a result of sync operation
119 * @return Result of operation, 0 on success, otherwise error code 120 * @return Result of operation, 0 on success, otherwise error code
120 */ 121 */
121 Result WaitSynchronization(bool* wait) override { 122 ResultVal<bool> WaitSynchronization() override {
122 // TODO(bunnei): ImplementMe 123 // TODO(bunnei): ImplementMe
123 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 124 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
124 return 0; 125 return UnimplementedFunction(ErrorModule::FS);
125 } 126 }
126}; 127};
127 128
@@ -141,7 +142,7 @@ public:
141 * @param wait Boolean wait set if current thread should wait as a result of sync operation 142 * @param wait Boolean wait set if current thread should wait as a result of sync operation
142 * @return Result of operation, 0 on success, otherwise error code 143 * @return Result of operation, 0 on success, otherwise error code
143 */ 144 */
144 Result SyncRequest(bool* wait) override { 145 ResultVal<bool> SyncRequest() override {
145 u32* cmd_buff = Service::GetCommandBuffer(); 146 u32* cmd_buff = Service::GetCommandBuffer();
146 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 147 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
147 switch (cmd) { 148 switch (cmd) {
@@ -183,7 +184,8 @@ public:
183 case FileCommand::SetSize: 184 case FileCommand::SetSize:
184 { 185 {
185 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); 186 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
186 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); 187 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu",
188 GetTypeName().c_str(), GetName().c_str(), size);
187 backend->SetSize(size); 189 backend->SetSize(size);
188 break; 190 break;
189 } 191 }
@@ -198,11 +200,12 @@ public:
198 // Unknown command... 200 // Unknown command...
199 default: 201 default:
200 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 202 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
201 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 203 ResultCode error = UnimplementedFunction(ErrorModule::FS);
202 return -1; 204 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
205 return error;
203 } 206 }
204 cmd_buff[1] = 0; // No error 207 cmd_buff[1] = 0; // No error
205 return 0; 208 return MakeResult<bool>(false);
206 } 209 }
207 210
208 /** 211 /**
@@ -210,10 +213,10 @@ public:
210 * @param wait Boolean wait set if current thread should wait as a result of sync operation 213 * @param wait Boolean wait set if current thread should wait as a result of sync operation
211 * @return Result of operation, 0 on success, otherwise error code 214 * @return Result of operation, 0 on success, otherwise error code
212 */ 215 */
213 Result WaitSynchronization(bool* wait) override { 216 ResultVal<bool> WaitSynchronization() override {
214 // TODO(bunnei): ImplementMe 217 // TODO(bunnei): ImplementMe
215 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 218 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
216 return 0; 219 return UnimplementedFunction(ErrorModule::FS);
217 } 220 }
218}; 221};
219 222
@@ -233,7 +236,7 @@ public:
233 * @param wait Boolean wait set if current thread should wait as a result of sync operation 236 * @param wait Boolean wait set if current thread should wait as a result of sync operation
234 * @return Result of operation, 0 on success, otherwise error code 237 * @return Result of operation, 0 on success, otherwise error code
235 */ 238 */
236 Result SyncRequest(bool* wait) override { 239 ResultVal<bool> SyncRequest() override {
237 u32* cmd_buff = Service::GetCommandBuffer(); 240 u32* cmd_buff = Service::GetCommandBuffer();
238 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); 241 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
239 switch (cmd) { 242 switch (cmd) {
@@ -243,8 +246,9 @@ public:
243 { 246 {
244 u32 count = cmd_buff[1]; 247 u32 count = cmd_buff[1];
245 u32 address = cmd_buff[3]; 248 u32 address = cmd_buff[3];
246 FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); 249 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
247 DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); 250 DEBUG_LOG(KERNEL, "Read %s %s: count=%d",
251 GetTypeName().c_str(), GetName().c_str(), count);
248 252
249 // Number of entries actually read 253 // Number of entries actually read
250 cmd_buff[2] = backend->Read(count, entries); 254 cmd_buff[2] = backend->Read(count, entries);
@@ -261,11 +265,12 @@ public:
261 // Unknown command... 265 // Unknown command...
262 default: 266 default:
263 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 267 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
264 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 268 ResultCode error = UnimplementedFunction(ErrorModule::FS);
265 return -1; 269 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
270 return error;
266 } 271 }
267 cmd_buff[1] = 0; // No error 272 cmd_buff[1] = 0; // No error
268 return 0; 273 return MakeResult<bool>(false);
269 } 274 }
270 275
271 /** 276 /**
@@ -273,10 +278,10 @@ public:
273 * @param wait Boolean wait set if current thread should wait as a result of sync operation 278 * @param wait Boolean wait set if current thread should wait as a result of sync operation
274 * @return Result of operation, 0 on success, otherwise error code 279 * @return Result of operation, 0 on success, otherwise error code
275 */ 280 */
276 Result WaitSynchronization(bool* wait) override { 281 ResultVal<bool> WaitSynchronization() override {
277 // TODO(bunnei): ImplementMe 282 // TODO(bunnei): ImplementMe
278 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 283 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
279 return 0; 284 return UnimplementedFunction(ErrorModule::FS);
280 } 285 }
281}; 286};
282 287
@@ -284,89 +289,59 @@ public:
284 289
285std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode 290std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
286 291
287/** 292ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) {
288 * Opens an archive
289 * @param id_code IdCode of the archive to open
290 * @return Handle to archive if it exists, otherwise a null handle (0)
291 */
292Handle OpenArchive(FileSys::Archive::IdCode id_code) {
293 auto itr = g_archive_map.find(id_code); 293 auto itr = g_archive_map.find(id_code);
294 if (itr == g_archive_map.end()) { 294 if (itr == g_archive_map.end()) {
295 return 0; 295 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
296 ErrorSummary::NotFound, ErrorLevel::Permanent);
296 } 297 }
297 return itr->second; 298
299 return MakeResult<Handle>(itr->second);
298} 300}
299 301
300/** 302ResultCode CloseArchive(FileSys::Archive::IdCode id_code) {
301 * Closes an archive
302 * @param id_code IdCode of the archive to open
303 * @return Result of operation, 0 on success, otherwise error code
304 */
305Result CloseArchive(FileSys::Archive::IdCode id_code) {
306 auto itr = g_archive_map.find(id_code); 303 auto itr = g_archive_map.find(id_code);
307 if (itr == g_archive_map.end()) { 304 if (itr == g_archive_map.end()) {
308 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); 305 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code);
309 return -1; 306 return InvalidHandle(ErrorModule::FS);
310 } 307 }
311 308
312 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); 309 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
313 return 0; 310 return RESULT_SUCCESS;
314} 311}
315 312
316/** 313/**
317 * Mounts an archive 314 * Mounts an archive
318 * @param archive Pointer to the archive to mount 315 * @param archive Pointer to the archive to mount
319 * @return Result of operation, 0 on success, otherwise error code 316 * @return Result of operation
320 */ 317 */
321Result MountArchive(Archive* archive) { 318ResultCode MountArchive(Archive* archive) {
322 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); 319 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
323 if (0 != OpenArchive(id_code)) { 320 ResultVal<Handle> archive_handle = OpenArchive(id_code);
321 if (archive_handle.Succeeded()) {
324 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); 322 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
325 return -1; 323 return archive_handle.Code();
326 } 324 }
327 g_archive_map[id_code] = archive->GetHandle(); 325 g_archive_map[id_code] = archive->GetHandle();
328 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); 326 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str());
329 return 0; 327 return RESULT_SUCCESS;
330} 328}
331 329
332/** 330ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) {
333 * Creates an Archive
334 * @param handle Handle to newly created archive object
335 * @param backend File system backend interface to the archive
336 * @param name Optional name of Archive
337 * @return Newly created Archive object
338 */
339Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) {
340 Archive* archive = new Archive; 331 Archive* archive = new Archive;
341 handle = Kernel::g_object_pool.Create(archive); 332 Handle handle = Kernel::g_object_pool.Create(archive);
342 archive->name = name; 333 archive->name = name;
343 archive->backend = backend; 334 archive->backend = backend;
344 335
345 MountArchive(archive); 336 ResultCode result = MountArchive(archive);
346 337 if (result.IsError()) {
347 return archive; 338 return result;
348} 339 }
349 340
350/** 341 return RESULT_SUCCESS;
351 * Creates an Archive
352 * @param backend File system backend interface to the archive
353 * @param name Optional name of Archive
354 * @return Handle to newly created Archive object
355 */
356Handle CreateArchive(FileSys::Archive* backend, const std::string& name) {
357 Handle handle;
358 CreateArchive(handle, backend, name);
359 return handle;
360} 342}
361 343
362/** 344ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
363 * Open a File from an Archive
364 * @param archive_handle Handle to an open Archive object
365 * @param path Path to the File inside of the Archive
366 * @param mode Mode under which to open the File
367 * @return Opened File object
368 */
369Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
370 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create 345 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create
371 // the archive file handles at app loading, and then keep them persistent throughout execution. 346 // the archive file handles at app loading, and then keep them persistent throughout execution.
372 // Archives file handles are just reused and not actually freed until emulation shut down. 347 // Archives file handles are just reused and not actually freed until emulation shut down.
@@ -376,19 +351,24 @@ Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, con
376 // design. While the functionally of this is OK, our implementation decision to separate 351 // design. While the functionally of this is OK, our implementation decision to separate
377 // normal files from archive file pointers is very likely wrong. 352 // normal files from archive file pointers is very likely wrong.
378 // See https://github.com/citra-emu/citra/issues/205 353 // See https://github.com/citra-emu/citra/issues/205
379 return archive_handle; 354 return MakeResult<Handle>(archive_handle);
380 355
381 File* file = new File; 356 File* file = new File;
382 Handle handle = Kernel::g_object_pool.Create(file); 357 Handle handle = Kernel::g_object_pool.Create(file);
383 358
384 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 359 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
360 if (archive == nullptr) {
361 return InvalidHandle(ErrorModule::FS);
362 }
385 file->path = path; 363 file->path = path;
386 file->backend = archive->backend->OpenFile(path, mode); 364 file->backend = archive->backend->OpenFile(path, mode);
387 365
388 if (!file->backend) 366 if (!file->backend) {
389 return 0; 367 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
368 ErrorSummary::NotFound, ErrorLevel::Permanent);
369 }
390 370
391 return handle; 371 return MakeResult<Handle>(handle);
392} 372}
393 373
394/** 374/**
@@ -442,15 +422,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa
442 * @param path Path to the Directory inside of the Archive 422 * @param path Path to the Directory inside of the Archive
443 * @return Opened Directory object 423 * @return Opened Directory object
444 */ 424 */
445Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { 425ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
446 Directory* directory = new Directory; 426 Directory* directory = new Directory;
447 Handle handle = Kernel::g_object_pool.Create(directory); 427 Handle handle = Kernel::g_object_pool.Create(directory);
448 428
449 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 429 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
430 if (archive == nullptr) {
431 return InvalidHandle(ErrorModule::FS);
432 }
450 directory->path = path; 433 directory->path = path;
451 directory->backend = archive->backend->OpenDirectory(path); 434 directory->backend = archive->backend->OpenDirectory(path);
452 435
453 return handle; 436 return MakeResult<Handle>(handle);
454} 437}
455 438
456/// Initialize archives 439/// Initialize archives