| @@ -133,6 +133,7 @@ set(HEADERS | |||||||
|             hle/service/srv.h |             hle/service/srv.h | ||||||
|             hle/service/ssl_c.h |             hle/service/ssl_c.h | ||||||
|             hle/config_mem.h |             hle/config_mem.h | ||||||
|  |             hle/result.h | ||||||
|             hle/function_wrappers.h |             hle/function_wrappers.h | ||||||
|             hle/hle.h |             hle/hle.h | ||||||
|             hle/svc.h |             hle/svc.h | ||||||
|   | |||||||
| @@ -799,22 +799,24 @@ pascal void SpinCursor (short increment);    /* copied from CursorCtl.h */ | |||||||
| #include "list.h" | #include "list.h" | ||||||
| #include "tb.h" | #include "tb.h" | ||||||
| */ | */ | ||||||
| #define EQ 0 | enum ConditionCode { | ||||||
| #define NE 1 |     EQ = 0, | ||||||
| #define CS 2 |     NE = 1, | ||||||
| #define CC 3 |     CS = 2, | ||||||
| #define MI 4 |     CC = 3, | ||||||
| #define PL 5 |     MI = 4, | ||||||
| #define VS 6 |     PL = 5, | ||||||
| #define VC 7 |     VS = 6, | ||||||
| #define HI 8 |     VC = 7, | ||||||
| #define LS 9 |     HI = 8, | ||||||
| #define GE 10 |     LS = 9, | ||||||
| #define LT 11 |     GE = 10, | ||||||
| #define GT 12 |     LT = 11, | ||||||
| #define LE 13 |     GT = 12, | ||||||
| #define AL 14 |     LE = 13, | ||||||
| #define NV 15 |     AL = 14, | ||||||
|  |     NV = 15, | ||||||
|  | }; | ||||||
|  |  | ||||||
| #ifndef NFLAG | #ifndef NFLAG | ||||||
| #define NFLAG    state->NFlag | #define NFLAG    state->NFlag | ||||||
|   | |||||||
| @@ -25,24 +25,6 @@ | |||||||
|  |  | ||||||
| #define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__) | #define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__) | ||||||
|  |  | ||||||
| /* Condition code values.  */ |  | ||||||
| #define EQ 0 |  | ||||||
| #define NE 1 |  | ||||||
| #define CS 2 |  | ||||||
| #define CC 3 |  | ||||||
| #define MI 4 |  | ||||||
| #define PL 5 |  | ||||||
| #define VS 6 |  | ||||||
| #define VC 7 |  | ||||||
| #define HI 8 |  | ||||||
| #define LS 9 |  | ||||||
| #define GE 10 |  | ||||||
| #define LT 11 |  | ||||||
| #define GT 12 |  | ||||||
| #define LE 13 |  | ||||||
| #define AL 14 |  | ||||||
| #define NV 15 |  | ||||||
|  |  | ||||||
| /* Shift Opcodes.  */ | /* Shift Opcodes.  */ | ||||||
| #define LSL 0 | #define LSL 0 | ||||||
| #define LSR 1 | #define LSR 1 | ||||||
|   | |||||||
| @@ -25,22 +25,17 @@ public: | |||||||
|  |  | ||||||
|     std::string name;   ///< Name of address arbiter object (optional) |     std::string name;   ///< Name of address arbiter object (optional) | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         // TODO(bunnei): ImplementMe |         // TODO(bunnei): ImplementMe | ||||||
|         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||||||
|         return 0; |         return UnimplementedFunction(ErrorModule::OS); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
| /// Arbitrate an address | /// Arbitrate an address | ||||||
| Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { | ||||||
|     switch (type) { |     switch (type) { | ||||||
|  |  | ||||||
|     // Signal thread(s) waiting for arbitrate address... |     // Signal thread(s) waiting for arbitrate address... | ||||||
| @@ -65,9 +60,9 @@ Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 va | |||||||
|  |  | ||||||
|     default: |     default: | ||||||
|         ERROR_LOG(KERNEL, "unknown type=%d", type); |         ERROR_LOG(KERNEL, "unknown type=%d", type); | ||||||
|         return -1; |         return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage); | ||||||
|     } |     } | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Create an address arbiter | /// Create an address arbiter | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ enum class ArbitrationType : u32 { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| /// Arbitrate an address | /// Arbitrate an address | ||||||
| Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); | ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); | ||||||
|  |  | ||||||
| /// Create an address arbiter | /// Create an address arbiter | ||||||
| Handle CreateAddressArbiter(const std::string& name = "Unknown"); | Handle CreateAddressArbiter(const std::string& name = "Unknown"); | ||||||
|   | |||||||
| @@ -9,8 +9,9 @@ | |||||||
| #include "core/file_sys/archive.h" | #include "core/file_sys/archive.h" | ||||||
| #include "core/file_sys/archive_sdmc.h" | #include "core/file_sys/archive_sdmc.h" | ||||||
| #include "core/file_sys/directory.h" | #include "core/file_sys/directory.h" | ||||||
| #include "core/hle/service/service.h" |  | ||||||
| #include "core/hle/kernel/archive.h" | #include "core/hle/kernel/archive.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  | #include "core/hle/service/service.h" | ||||||
|  |  | ||||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
| // Kernel namespace | // Kernel namespace | ||||||
| @@ -51,12 +52,7 @@ public: | |||||||
|     std::string name;           ///< Name of archive (optional) |     std::string name;           ///< Name of archive (optional) | ||||||
|     FileSys::Archive* backend;  ///< Archive backend interface |     FileSys::Archive* backend;  ///< Archive backend interface | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> SyncRequest() override { | ||||||
|      * Synchronize kernel object |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result SyncRequest(bool* wait) override { |  | ||||||
|         u32* cmd_buff = Service::GetCommandBuffer(); |         u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|         FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); |         FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | ||||||
|  |  | ||||||
| @@ -106,22 +102,17 @@ public: | |||||||
|         default: |         default: | ||||||
|         { |         { | ||||||
|             ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); |             ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | ||||||
|             return -1; |             return UnimplementedFunction(ErrorModule::FS); | ||||||
|         } |         } | ||||||
|         } |         } | ||||||
|         cmd_buff[1] = 0; // No error |         cmd_buff[1] = 0; // No error | ||||||
|         return 0; |         return MakeResult<bool>(false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         // TODO(bunnei): ImplementMe |         // TODO(bunnei): ImplementMe | ||||||
|         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||||||
|         return 0; |         return UnimplementedFunction(ErrorModule::FS); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -136,12 +127,7 @@ public: | |||||||
|     FileSys::Path path; ///< Path of the file |     FileSys::Path path; ///< Path of the file | ||||||
|     std::unique_ptr<FileSys::File> backend; ///< File backend interface |     std::unique_ptr<FileSys::File> backend; ///< File backend interface | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> SyncRequest() override { | ||||||
|      * Synchronize kernel object |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result SyncRequest(bool* wait) override { |  | ||||||
|         u32* cmd_buff = Service::GetCommandBuffer(); |         u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|         FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); |         FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | ||||||
|         switch (cmd) { |         switch (cmd) { | ||||||
| @@ -183,7 +169,8 @@ public: | |||||||
|         case FileCommand::SetSize: |         case FileCommand::SetSize: | ||||||
|         { |         { | ||||||
|             u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); |             u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); | ||||||
|             DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); |             DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", | ||||||
|  |                     GetTypeName().c_str(), GetName().c_str(), size); | ||||||
|             backend->SetSize(size); |             backend->SetSize(size); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -198,22 +185,18 @@ public: | |||||||
|         // Unknown command... |         // Unknown command... | ||||||
|         default: |         default: | ||||||
|             ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); |             ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | ||||||
|             cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. |             ResultCode error = UnimplementedFunction(ErrorModule::FS); | ||||||
|             return -1; |             cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. | ||||||
|  |             return error; | ||||||
|         } |         } | ||||||
|         cmd_buff[1] = 0; // No error |         cmd_buff[1] = 0; // No error | ||||||
|         return 0; |         return MakeResult<bool>(false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         // TODO(bunnei): ImplementMe |         // TODO(bunnei): ImplementMe | ||||||
|         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||||||
|         return 0; |         return UnimplementedFunction(ErrorModule::FS); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -228,12 +211,7 @@ public: | |||||||
|     FileSys::Path path; ///< Path of the directory |     FileSys::Path path; ///< Path of the directory | ||||||
|     std::unique_ptr<FileSys::Directory> backend; ///< File backend interface |     std::unique_ptr<FileSys::Directory> backend; ///< File backend interface | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> SyncRequest() override { | ||||||
|      * Synchronize kernel object |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result SyncRequest(bool* wait) override { |  | ||||||
|         u32* cmd_buff = Service::GetCommandBuffer(); |         u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|         DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); |         DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); | ||||||
|         switch (cmd) { |         switch (cmd) { | ||||||
| @@ -243,8 +221,9 @@ public: | |||||||
|         { |         { | ||||||
|             u32 count = cmd_buff[1]; |             u32 count = cmd_buff[1]; | ||||||
|             u32 address = cmd_buff[3]; |             u32 address = cmd_buff[3]; | ||||||
|             FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); |             auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); | ||||||
|             DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); |             DEBUG_LOG(KERNEL, "Read %s %s: count=%d", | ||||||
|  |                     GetTypeName().c_str(), GetName().c_str(), count); | ||||||
|  |  | ||||||
|             // Number of entries actually read |             // Number of entries actually read | ||||||
|             cmd_buff[2] = backend->Read(count, entries); |             cmd_buff[2] = backend->Read(count, entries); | ||||||
| @@ -261,22 +240,18 @@ public: | |||||||
|         // Unknown command... |         // Unknown command... | ||||||
|         default: |         default: | ||||||
|             ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); |             ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); | ||||||
|             cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. |             ResultCode error = UnimplementedFunction(ErrorModule::FS); | ||||||
|             return -1; |             cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. | ||||||
|  |             return error; | ||||||
|         } |         } | ||||||
|         cmd_buff[1] = 0; // No error |         cmd_buff[1] = 0; // No error | ||||||
|         return 0; |         return MakeResult<bool>(false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         // TODO(bunnei): ImplementMe |         // TODO(bunnei): ImplementMe | ||||||
|         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||||||
|         return 0; |         return UnimplementedFunction(ErrorModule::FS); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -284,89 +259,58 @@ public: | |||||||
|  |  | ||||||
| std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode | std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode | ||||||
|  |  | ||||||
| /** | ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) { | ||||||
|  * Opens an archive |  | ||||||
|  * @param id_code IdCode of the archive to open |  | ||||||
|  * @return Handle to archive if it exists, otherwise a null handle (0) |  | ||||||
|  */ |  | ||||||
| Handle OpenArchive(FileSys::Archive::IdCode id_code) { |  | ||||||
|     auto itr = g_archive_map.find(id_code); |     auto itr = g_archive_map.find(id_code); | ||||||
|     if (itr == g_archive_map.end()) { |     if (itr == g_archive_map.end()) { | ||||||
|         return 0; |         return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||||||
|  |                 ErrorSummary::NotFound, ErrorLevel::Permanent); | ||||||
|     } |     } | ||||||
|     return itr->second; |  | ||||||
|  |     return MakeResult<Handle>(itr->second); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { | ||||||
|  * Closes an archive |  | ||||||
|  * @param id_code IdCode of the archive to open |  | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  | ||||||
| Result CloseArchive(FileSys::Archive::IdCode id_code) { |  | ||||||
|     auto itr = g_archive_map.find(id_code); |     auto itr = g_archive_map.find(id_code); | ||||||
|     if (itr == g_archive_map.end()) { |     if (itr == g_archive_map.end()) { | ||||||
|         ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); |         ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); | ||||||
|         return -1; |         return InvalidHandle(ErrorModule::FS); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); |     INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Mounts an archive |  * Mounts an archive | ||||||
|  * @param archive Pointer to the archive to mount |  * @param archive Pointer to the archive to mount | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  */ | ||||||
| Result MountArchive(Archive* archive) { | ResultCode MountArchive(Archive* archive) { | ||||||
|     FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); |     FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); | ||||||
|     if (0 != OpenArchive(id_code)) { |     ResultVal<Handle> archive_handle = OpenArchive(id_code); | ||||||
|  |     if (archive_handle.Succeeded()) { | ||||||
|         ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); |         ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); | ||||||
|         return -1; |         return archive_handle.Code(); | ||||||
|     } |     } | ||||||
|     g_archive_map[id_code] = archive->GetHandle(); |     g_archive_map[id_code] = archive->GetHandle(); | ||||||
|     INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); |     INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { | ||||||
|  * Creates an Archive |  | ||||||
|  * @param handle Handle to newly created archive object |  | ||||||
|  * @param backend File system backend interface to the archive |  | ||||||
|  * @param name Optional name of Archive |  | ||||||
|  * @return Newly created Archive object |  | ||||||
|  */ |  | ||||||
| Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) { |  | ||||||
|     Archive* archive = new Archive; |     Archive* archive = new Archive; | ||||||
|     handle = Kernel::g_object_pool.Create(archive); |     Handle handle = Kernel::g_object_pool.Create(archive); | ||||||
|     archive->name = name; |     archive->name = name; | ||||||
|     archive->backend = backend; |     archive->backend = backend; | ||||||
|  |  | ||||||
|     MountArchive(archive); |     ResultCode result = MountArchive(archive); | ||||||
|  |     if (result.IsError()) { | ||||||
|     return archive; |         return result; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { | ||||||
|  * Creates an Archive |  | ||||||
|  * @param backend File system backend interface to the archive |  | ||||||
|  * @param name Optional name of Archive |  | ||||||
|  * @return Handle to newly created Archive object |  | ||||||
|  */ |  | ||||||
| Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { |  | ||||||
|     Handle handle; |  | ||||||
|     CreateArchive(handle, backend, name); |  | ||||||
|     return handle; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Open a File from an Archive |  | ||||||
|  * @param archive_handle Handle to an open Archive object |  | ||||||
|  * @param path Path to the File inside of the Archive |  | ||||||
|  * @param mode Mode under which to open the File |  | ||||||
|  * @return Opened File object |  | ||||||
|  */ |  | ||||||
| Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { |  | ||||||
|     // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create |     // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create | ||||||
|     // the archive file handles at app loading, and then keep them persistent throughout execution. |     // the archive file handles at app loading, and then keep them persistent throughout execution. | ||||||
|     // Archives file handles are just reused and not actually freed until emulation shut down. |     // Archives file handles are just reused and not actually freed until emulation shut down. | ||||||
| @@ -376,19 +320,24 @@ Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, con | |||||||
|         // design. While the functionally of this is OK, our implementation decision to separate |         // design. While the functionally of this is OK, our implementation decision to separate | ||||||
|         // normal files from archive file pointers is very likely wrong. |         // normal files from archive file pointers is very likely wrong. | ||||||
|         // See https://github.com/citra-emu/citra/issues/205 |         // See https://github.com/citra-emu/citra/issues/205 | ||||||
|         return archive_handle; |         return MakeResult<Handle>(archive_handle); | ||||||
|  |  | ||||||
|     File* file = new File; |     File* file = new File; | ||||||
|     Handle handle = Kernel::g_object_pool.Create(file); |     Handle handle = Kernel::g_object_pool.Create(file); | ||||||
|  |  | ||||||
|     Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); |     Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); | ||||||
|  |     if (archive == nullptr) { | ||||||
|  |         return InvalidHandle(ErrorModule::FS); | ||||||
|  |     } | ||||||
|     file->path = path; |     file->path = path; | ||||||
|     file->backend = archive->backend->OpenFile(path, mode); |     file->backend = archive->backend->OpenFile(path, mode); | ||||||
|  |  | ||||||
|     if (!file->backend) |     if (!file->backend) { | ||||||
|         return 0; |         return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, | ||||||
|  |                 ErrorSummary::NotFound, ErrorLevel::Permanent); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return handle; |     return MakeResult<Handle>(handle); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -442,15 +391,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa | |||||||
|  * @param path Path to the Directory inside of the Archive |  * @param path Path to the Directory inside of the Archive | ||||||
|  * @return Opened Directory object |  * @return Opened Directory object | ||||||
|  */ |  */ | ||||||
| Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { | ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { | ||||||
|     Directory* directory = new Directory; |     Directory* directory = new Directory; | ||||||
|     Handle handle = Kernel::g_object_pool.Create(directory); |     Handle handle = Kernel::g_object_pool.Create(directory); | ||||||
|  |  | ||||||
|     Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); |     Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); | ||||||
|  |     if (archive == nullptr) { | ||||||
|  |         return InvalidHandle(ErrorModule::FS); | ||||||
|  |     } | ||||||
|     directory->path = path; |     directory->path = path; | ||||||
|     directory->backend = archive->backend->OpenDirectory(path); |     directory->backend = archive->backend->OpenDirectory(path); | ||||||
|  |  | ||||||
|     return handle; |     return MakeResult<Handle>(handle); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Initialize archives | /// Initialize archives | ||||||
|   | |||||||
| @@ -6,8 +6,9 @@ | |||||||
|  |  | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  |  | ||||||
| #include "core/hle/kernel/kernel.h" |  | ||||||
| #include "core/file_sys/archive.h" | #include "core/file_sys/archive.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  |  | ||||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
| // Kernel namespace | // Kernel namespace | ||||||
| @@ -17,33 +18,31 @@ namespace Kernel { | |||||||
| /** | /** | ||||||
|  * Opens an archive |  * Opens an archive | ||||||
|  * @param id_code IdCode of the archive to open |  * @param id_code IdCode of the archive to open | ||||||
|  * @return Handle to archive if it exists, otherwise a null handle (0) |  * @return Handle to the opened archive | ||||||
|  */ |  */ | ||||||
| Handle OpenArchive(FileSys::Archive::IdCode id_code); | ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Closes an archive |  * Closes an archive | ||||||
|  * @param id_code IdCode of the archive to open |  * @param id_code IdCode of the archive to open | ||||||
|  * @return true if it worked fine |  | ||||||
|  */ |  */ | ||||||
| Result CloseArchive(FileSys::Archive::IdCode id_code); | ResultCode CloseArchive(FileSys::Archive::IdCode id_code); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Creates an Archive |  * Creates an Archive | ||||||
|  * @param backend File system backend interface to the archive |  * @param backend File system backend interface to the archive | ||||||
|  * @param name Optional name of Archive |  * @param name Name of Archive | ||||||
|  * @return Handle to newly created Archive object |  | ||||||
|  */ |  */ | ||||||
| Handle CreateArchive(FileSys::Archive* backend, const std::string& name); | ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Open a File from an Archive |  * Open a File from an Archive | ||||||
|  * @param archive_handle Handle to an open Archive object |  * @param archive_handle Handle to an open Archive object | ||||||
|  * @param path Path to the File inside of the Archive |  * @param path Path to the File inside of the Archive | ||||||
|  * @param mode Mode under which to open the File |  * @param mode Mode under which to open the File | ||||||
|  * @return Opened File object |  * @return Handle to the opened File object | ||||||
|  */ |  */ | ||||||
| Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); | ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Delete a File from an Archive |  * Delete a File from an Archive | ||||||
| @@ -73,9 +72,9 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa | |||||||
|  * Open a Directory from an Archive |  * Open a Directory from an Archive | ||||||
|  * @param archive_handle Handle to an open Archive object |  * @param archive_handle Handle to an open Archive object | ||||||
|  * @param path Path to the Directory inside of the Archive |  * @param path Path to the Directory inside of the Archive | ||||||
|  * @return Opened Directory object |  * @return Handle to the opened File object | ||||||
|  */ |  */ | ||||||
| Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); | ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); | ||||||
|  |  | ||||||
| /// Initialize archives | /// Initialize archives | ||||||
| void ArchiveInit(); | void ArchiveInit(); | ||||||
|   | |||||||
| @@ -30,13 +30,8 @@ public: | |||||||
|     std::vector<Handle> waiting_threads;    ///< Threads that are waiting for the event |     std::vector<Handle> waiting_threads;    ///< Threads that are waiting for the event | ||||||
|     std::string name;                       ///< Name of event (optional) |     std::string name;                       ///< Name of event (optional) | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |         bool wait = locked; | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         *wait = locked; |  | ||||||
|         if (locked) { |         if (locked) { | ||||||
|             Handle thread = GetCurrentThreadHandle(); |             Handle thread = GetCurrentThreadHandle(); | ||||||
|             if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { |             if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||||||
| @@ -47,7 +42,7 @@ public: | |||||||
|         if (reset_type != RESETTYPE_STICKY && !permanent_locked) { |         if (reset_type != RESETTYPE_STICKY && !permanent_locked) { | ||||||
|             locked = true; |             locked = true; | ||||||
|         } |         } | ||||||
|         return 0; |         return MakeResult<bool>(wait); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -57,12 +52,12 @@ public: | |||||||
|  * @param permanent_locked Boolean permanent locked value to set event |  * @param permanent_locked Boolean permanent locked value to set event | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  */ |  */ | ||||||
| Result SetPermanentLock(Handle handle, const bool permanent_locked) { | ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) { | ||||||
|     Event* evt = g_object_pool.GetFast<Event>(handle); |     Event* evt = g_object_pool.Get<Event>(handle); | ||||||
|     _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); |     if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|  |  | ||||||
|     evt->permanent_locked = permanent_locked; |     evt->permanent_locked = permanent_locked; | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -71,14 +66,14 @@ Result SetPermanentLock(Handle handle, const bool permanent_locked) { | |||||||
|  * @param locked Boolean locked value to set event |  * @param locked Boolean locked value to set event | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  */ |  */ | ||||||
| Result SetEventLocked(const Handle handle, const bool locked) { | ResultCode SetEventLocked(const Handle handle, const bool locked) { | ||||||
|     Event* evt = g_object_pool.GetFast<Event>(handle); |     Event* evt = g_object_pool.Get<Event>(handle); | ||||||
|     _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); |     if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|  |  | ||||||
|     if (!evt->permanent_locked) { |     if (!evt->permanent_locked) { | ||||||
|         evt->locked = locked; |         evt->locked = locked; | ||||||
|     } |     } | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -86,9 +81,9 @@ Result SetEventLocked(const Handle handle, const bool locked) { | |||||||
|  * @param handle Handle to event to signal |  * @param handle Handle to event to signal | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  */ |  */ | ||||||
| Result SignalEvent(const Handle handle) { | ResultCode SignalEvent(const Handle handle) { | ||||||
|     Event* evt = g_object_pool.GetFast<Event>(handle); |     Event* evt = g_object_pool.Get<Event>(handle); | ||||||
|     _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); |     if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|  |  | ||||||
|     // Resume threads waiting for event to signal |     // Resume threads waiting for event to signal | ||||||
|     bool event_caught = false; |     bool event_caught = false; | ||||||
| @@ -106,7 +101,7 @@ Result SignalEvent(const Handle handle) { | |||||||
|     if (!evt->permanent_locked) { |     if (!evt->permanent_locked) { | ||||||
|         evt->locked = event_caught; |         evt->locked = event_caught; | ||||||
|     } |     } | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -114,14 +109,14 @@ Result SignalEvent(const Handle handle) { | |||||||
|  * @param handle Handle to event to clear |  * @param handle Handle to event to clear | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  */ |  */ | ||||||
| Result ClearEvent(Handle handle) { | ResultCode ClearEvent(Handle handle) { | ||||||
|     Event* evt = g_object_pool.GetFast<Event>(handle); |     Event* evt = g_object_pool.Get<Event>(handle); | ||||||
|     _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); |     if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|  |  | ||||||
|     if (!evt->permanent_locked) { |     if (!evt->permanent_locked) { | ||||||
|         evt->locked = true; |         evt->locked = true; | ||||||
|     } |     } | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -15,31 +15,27 @@ namespace Kernel { | |||||||
|  * Changes whether an event is locked or not |  * Changes whether an event is locked or not | ||||||
|  * @param handle Handle to event to change |  * @param handle Handle to event to change | ||||||
|  * @param locked Boolean locked value to set event |  * @param locked Boolean locked value to set event | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  */ | ||||||
| Result SetEventLocked(const Handle handle, const bool locked); | ResultCode SetEventLocked(const Handle handle, const bool locked); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Hackish function to set an events permanent lock state, used to pass through synch blocks |  * Hackish function to set an events permanent lock state, used to pass through synch blocks | ||||||
|  * @param handle Handle to event to change |  * @param handle Handle to event to change | ||||||
|  * @param permanent_locked Boolean permanent locked value to set event |  * @param permanent_locked Boolean permanent locked value to set event | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  */ | ||||||
| Result SetPermanentLock(Handle handle, const bool permanent_locked); | ResultCode SetPermanentLock(Handle handle, const bool permanent_locked); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Signals an event |  * Signals an event | ||||||
|  * @param handle Handle to event to signal |  * @param handle Handle to event to signal | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  */ | ||||||
| Result SignalEvent(const Handle handle); | ResultCode SignalEvent(const Handle handle); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Clears an event |  * Clears an event | ||||||
|  * @param handle Handle to event to clear |  * @param handle Handle to event to clear | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  */ | ||||||
| Result ClearEvent(Handle handle); | ResultCode ClearEvent(Handle handle); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Creates an event |  * Creates an event | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ | |||||||
| #include <array> | #include <array> | ||||||
| #include <string> | #include <string> | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  |  | ||||||
| typedef u32 Handle; | typedef u32 Handle; | ||||||
| typedef s32 Result; | typedef s32 Result; | ||||||
| @@ -52,21 +53,19 @@ public: | |||||||
|     virtual Kernel::HandleType GetHandleType() const = 0; |     virtual Kernel::HandleType GetHandleType() const = 0; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Synchronize kernel object |      * Synchronize kernel object. | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |      * @return True if the current thread should wait as a result of the sync | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |      */ | ||||||
|     virtual Result SyncRequest(bool* wait) { |     virtual ResultVal<bool> SyncRequest() { | ||||||
|         ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); |         ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); | ||||||
|         return -1; |         return UnimplementedFunction(ErrorModule::Kernel); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Wait for kernel object to synchronize |      * Wait for kernel object to synchronize. | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |      * @return True if the current thread should wait as a result of the wait | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |      */ | ||||||
|     virtual Result WaitSynchronization(bool* wait) = 0; |     virtual ResultVal<bool> WaitSynchronization() = 0; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class ObjectPool : NonCopyable { | class ObjectPool : NonCopyable { | ||||||
| @@ -80,38 +79,29 @@ public: | |||||||
|     static Object* CreateByIDType(int type); |     static Object* CreateByIDType(int type); | ||||||
|  |  | ||||||
|     template <class T> |     template <class T> | ||||||
|     u32 Destroy(Handle handle) { |     void Destroy(Handle handle) { | ||||||
|         u32 error; |         if (Get<T>(handle)) { | ||||||
|         if (Get<T>(handle, error)) { |  | ||||||
|             occupied[handle - HANDLE_OFFSET] = false; |             occupied[handle - HANDLE_OFFSET] = false; | ||||||
|             delete pool[handle - HANDLE_OFFSET]; |             delete pool[handle - HANDLE_OFFSET]; | ||||||
|         } |         } | ||||||
|         return error; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool IsValid(Handle handle); |     bool IsValid(Handle handle); | ||||||
|  |  | ||||||
|     template <class T> |     template <class T> | ||||||
|     T* Get(Handle handle, u32& outError) { |     T* Get(Handle handle) { | ||||||
|         if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { |         if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { | ||||||
|             // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP |             if (handle != 0) { | ||||||
|             if (handle != 0 && (u32)handle != 0x80020001) { |  | ||||||
|                 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); |                 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); | ||||||
|             } |             } | ||||||
|             outError = 0;//T::GetMissingErrorCode(); |             return nullptr; | ||||||
|             return 0; |  | ||||||
|         } else { |         } else { | ||||||
|             // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally, |             Object* t = pool[handle - HANDLE_OFFSET]; | ||||||
|             // it just acted as a static case and everything worked. This means that we will never |             if (t->GetHandleType() != T::GetStaticHandleType()) { | ||||||
|             // see the Wrong type object error below, but we'll just have to live with that danger. |  | ||||||
|             T* t = static_cast<T*>(pool[handle - HANDLE_OFFSET]); |  | ||||||
|             if (t == 0 || t->GetHandleType() != T::GetStaticHandleType()) { |  | ||||||
|                 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); |                 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); | ||||||
|                 outError = 0;//T::GetMissingErrorCode(); |                 return nullptr; | ||||||
|                 return 0; |  | ||||||
|             } |             } | ||||||
|             outError = 0;//SCE_KERNEL_ERROR_OK; |             return static_cast<T*>(t); | ||||||
|             return t; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -27,31 +27,20 @@ public: | |||||||
|     std::vector<Handle> waiting_threads;        ///< Threads that are waiting for the mutex |     std::vector<Handle> waiting_threads;        ///< Threads that are waiting for the mutex | ||||||
|     std::string name;                           ///< Name of mutex (optional) |     std::string name;                           ///< Name of mutex (optional) | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> SyncRequest() override { | ||||||
|      * Synchronize kernel object |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result SyncRequest(bool* wait) override { |  | ||||||
|         // TODO(bunnei): ImplementMe |         // TODO(bunnei): ImplementMe | ||||||
|         locked = true; |         locked = true; | ||||||
|         return 0; |         return MakeResult<bool>(false); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         // TODO(bunnei): ImplementMe |         // TODO(bunnei): ImplementMe | ||||||
|         *wait = locked; |         bool wait = locked; | ||||||
|  |  | ||||||
|         if (locked) { |         if (locked) { | ||||||
|             Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); |             Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return 0; |         return MakeResult<bool>(wait); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -119,15 +108,17 @@ bool ReleaseMutex(Mutex* mutex) { | |||||||
|  * Releases a mutex |  * Releases a mutex | ||||||
|  * @param handle Handle to mutex to release |  * @param handle Handle to mutex to release | ||||||
|  */ |  */ | ||||||
| Result ReleaseMutex(Handle handle) { | ResultCode ReleaseMutex(Handle handle) { | ||||||
|     Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); |     Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle); | ||||||
|  |     if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|     _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!"); |  | ||||||
|  |  | ||||||
|     if (!ReleaseMutex(mutex)) { |     if (!ReleaseMutex(mutex)) { | ||||||
|         return -1; |         // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure | ||||||
|  |         // what error condition this is supposed to be signaling. | ||||||
|  |         return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel, | ||||||
|  |                 ErrorSummary::NothingHappened, ErrorLevel::Temporary); | ||||||
|     } |     } | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -13,9 +13,8 @@ namespace Kernel { | |||||||
| /** | /** | ||||||
|  * Releases a mutex |  * Releases a mutex | ||||||
|  * @param handle Handle to mutex to release |  * @param handle Handle to mutex to release | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  */ | ||||||
| Result ReleaseMutex(Handle handle); | ResultCode ReleaseMutex(Handle handle); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Creates a mutex |  * Creates a mutex | ||||||
|   | |||||||
| @@ -16,15 +16,10 @@ public: | |||||||
|     static Kernel::HandleType GetStaticHandleType() {  return Kernel::HandleType::SharedMemory; } |     static Kernel::HandleType GetStaticHandleType() {  return Kernel::HandleType::SharedMemory; } | ||||||
|     Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } |     Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         // TODO(bunnei): ImplementMe |         // TODO(bunnei): ImplementMe | ||||||
|         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); |         ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); | ||||||
|         return 0; |         return UnimplementedFunction(ErrorModule::OS); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     u32 base_address;                   ///< Address of shared memory block in RAM |     u32 base_address;                   ///< Address of shared memory block in RAM | ||||||
| @@ -48,11 +43,6 @@ SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { | |||||||
|     return shared_memory; |     return shared_memory; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Creates a shared memory object |  | ||||||
|  * @param name Optional name of shared memory object |  | ||||||
|  * @return Handle of newly created shared memory object |  | ||||||
|  */ |  | ||||||
| Handle CreateSharedMemory(const std::string& name) { | Handle CreateSharedMemory(const std::string& name) { | ||||||
|     Handle handle; |     Handle handle; | ||||||
|     CreateSharedMemory(handle, name); |     CreateSharedMemory(handle, name); | ||||||
| @@ -67,39 +57,36 @@ Handle CreateSharedMemory(const std::string& name) { | |||||||
|  * @param other_permissions Memory block map other permissions (specified by SVC field) |  * @param other_permissions Memory block map other permissions (specified by SVC field) | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  * @return Result of operation, 0 on success, otherwise error code | ||||||
|  */ |  */ | ||||||
| Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, | ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, | ||||||
|     MemoryPermission other_permissions) { |     MemoryPermission other_permissions) { | ||||||
|  |  | ||||||
|     if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { |     if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { | ||||||
|         ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", |         ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", | ||||||
|             handle, address); |             handle, address); | ||||||
|         return -1; |         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||||||
|  |                 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
|     } |     } | ||||||
|     SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); |     SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle); | ||||||
|     _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); |     if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|  |  | ||||||
|     shared_memory->base_address = address; |     shared_memory->base_address = address; | ||||||
|     shared_memory->permissions = permissions; |     shared_memory->permissions = permissions; | ||||||
|     shared_memory->other_permissions = other_permissions; |     shared_memory->other_permissions = other_permissions; | ||||||
|  |  | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { | ||||||
|  * Gets a pointer to the shared memory block |     SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle); | ||||||
|  * @param handle Shared memory block handle |     if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|  * @param offset Offset from the start of the shared memory block to get pointer |  | ||||||
|  * @return Pointer to the shared memory block from the specified offset |  | ||||||
|  */ |  | ||||||
| u8* GetSharedMemoryPointer(Handle handle, u32 offset) { |  | ||||||
|     SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); |  | ||||||
|     _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); |  | ||||||
|  |  | ||||||
|     if (0 != shared_memory->base_address) |     if (0 != shared_memory->base_address) | ||||||
|         return Memory::GetPointer(shared_memory->base_address + offset); |         return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); | ||||||
|  |  | ||||||
|     ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); |     ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); | ||||||
|     return nullptr; |     // TODO(yuriks): Verify error code. | ||||||
|  |     return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | ||||||
|  |             ErrorSummary::InvalidState, ErrorLevel::Permanent); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace | } // namespace | ||||||
|   | |||||||
| @@ -32,9 +32,8 @@ Handle CreateSharedMemory(const std::string& name="Unknown"); | |||||||
|  * @param address Address in system memory to map shared memory block to |  * @param address Address in system memory to map shared memory block to | ||||||
|  * @param permissions Memory block map permissions (specified by SVC field) |  * @param permissions Memory block map permissions (specified by SVC field) | ||||||
|  * @param other_permissions Memory block map other permissions (specified by SVC field) |  * @param other_permissions Memory block map other permissions (specified by SVC field) | ||||||
|  * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|  */ |  */ | ||||||
| Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, | ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions, | ||||||
|     MemoryPermission other_permissions); |     MemoryPermission other_permissions); | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -43,6 +42,6 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, | |||||||
|  * @param offset Offset from the start of the shared memory block to get pointer |  * @param offset Offset from the start of the shared memory block to get pointer | ||||||
|  * @return Pointer to the shared memory block from the specified offset |  * @return Pointer to the shared memory block from the specified offset | ||||||
|  */ |  */ | ||||||
| u8* GetSharedMemoryPointer(Handle handle, u32 offset); | ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset); | ||||||
|  |  | ||||||
| } // namespace | } // namespace | ||||||
|   | |||||||
| @@ -11,10 +11,11 @@ | |||||||
| #include "common/thread_queue_list.h" | #include "common/thread_queue_list.h" | ||||||
|  |  | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/mem_map.h" |  | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  | #include "core/mem_map.h" | ||||||
|  |  | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
|  |  | ||||||
| @@ -33,21 +34,17 @@ public: | |||||||
|     inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } |     inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } | ||||||
|     inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } |     inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |         const bool wait = status != THREADSTATUS_DORMANT; | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |         if (wait) { | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         if (status != THREADSTATUS_DORMANT) { |  | ||||||
|             Handle thread = GetCurrentThreadHandle(); |             Handle thread = GetCurrentThreadHandle(); | ||||||
|             if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { |             if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||||||
|                 waiting_threads.push_back(thread); |                 waiting_threads.push_back(thread); | ||||||
|             } |             } | ||||||
|             WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); |             WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); | ||||||
|             *wait = true; |  | ||||||
|         } |         } | ||||||
|         return 0; |  | ||||||
|  |         return MakeResult<bool>(wait); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ThreadContext context; |     ThreadContext context; | ||||||
| @@ -144,27 +141,22 @@ void ChangeReadyState(Thread* t, bool ready) { | |||||||
| } | } | ||||||
|  |  | ||||||
| /// Verify that a thread has not been released from waiting | /// Verify that a thread has not been released from waiting | ||||||
| inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { | inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { | ||||||
|     Thread* thread = g_object_pool.GetFast<Thread>(handle); |     _dbg_assert_(KERNEL, thread != nullptr); | ||||||
|     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); |     return type == thread->wait_type && wait_handle == thread->wait_handle; | ||||||
|  |  | ||||||
|     if (type != thread->wait_type || wait_handle != thread->wait_handle) |  | ||||||
|         return false; |  | ||||||
|  |  | ||||||
|     return true; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Stops the current thread | /// Stops the current thread | ||||||
| void StopThread(Handle handle, const char* reason) { | ResultCode StopThread(Handle handle, const char* reason) { | ||||||
|     Thread* thread = g_object_pool.GetFast<Thread>(handle); |     Thread* thread = g_object_pool.Get<Thread>(handle); | ||||||
|     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); |     if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|  |  | ||||||
|     ChangeReadyState(thread, false); |     ChangeReadyState(thread, false); | ||||||
|     thread->status = THREADSTATUS_DORMANT; |     thread->status = THREADSTATUS_DORMANT; | ||||||
|     for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { |     for (Handle waiting_handle : thread->waiting_threads) { | ||||||
|         const Handle waiting_thread = thread->waiting_threads[i]; |         Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); | ||||||
|         if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { |         if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { | ||||||
|             ResumeThreadFromWait(waiting_thread); |             ResumeThreadFromWait(waiting_handle); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     thread->waiting_threads.clear(); |     thread->waiting_threads.clear(); | ||||||
| @@ -172,6 +164,8 @@ void StopThread(Handle handle, const char* reason) { | |||||||
|     // Stopped threads are never waiting. |     // Stopped threads are never waiting. | ||||||
|     thread->wait_type = WAITTYPE_NONE; |     thread->wait_type = WAITTYPE_NONE; | ||||||
|     thread->wait_handle = 0; |     thread->wait_handle = 0; | ||||||
|  |  | ||||||
|  |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Changes a threads state | /// Changes a threads state | ||||||
| @@ -195,13 +189,15 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | |||||||
|     s32 priority = THREADPRIO_LOWEST; |     s32 priority = THREADPRIO_LOWEST; | ||||||
|  |  | ||||||
|     // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |     // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | ||||||
|     for (const auto& handle : thread_queue) { |     for (Handle handle : thread_queue) { | ||||||
|  |         Thread* thread = g_object_pool.Get<Thread>(handle); | ||||||
|  |  | ||||||
|         // TODO(bunnei): Verify arbiter address... |         // TODO(bunnei): Verify arbiter address... | ||||||
|         if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) |         if (!VerifyWait(thread, WAITTYPE_ARB, arbiter)) | ||||||
|             continue; |             continue; | ||||||
|  |  | ||||||
|         Thread* thread = g_object_pool.GetFast<Thread>(handle); |         if (thread == nullptr) | ||||||
|  |             continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. | ||||||
|         if(thread->current_priority <= priority) { |         if(thread->current_priority <= priority) { | ||||||
|             highest_priority_thread = handle; |             highest_priority_thread = handle; | ||||||
|             priority = thread->current_priority; |             priority = thread->current_priority; | ||||||
| @@ -218,10 +214,11 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | |||||||
| void ArbitrateAllThreads(u32 arbiter, u32 address) { | void ArbitrateAllThreads(u32 arbiter, u32 address) { | ||||||
|  |  | ||||||
|     // Iterate through threads, find highest priority thread that is waiting to be arbitrated... |     // Iterate through threads, find highest priority thread that is waiting to be arbitrated... | ||||||
|     for (const auto& handle : thread_queue) { |     for (Handle handle : thread_queue) { | ||||||
|  |         Thread* thread = g_object_pool.Get<Thread>(handle); | ||||||
|  |  | ||||||
|         // TODO(bunnei): Verify arbiter address... |         // TODO(bunnei): Verify arbiter address... | ||||||
|         if (VerifyWait(handle, WAITTYPE_ARB, arbiter)) |         if (VerifyWait(thread, WAITTYPE_ARB, arbiter)) | ||||||
|             ResumeThreadFromWait(handle); |             ResumeThreadFromWait(handle); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -272,7 +269,7 @@ Thread* NextThread() { | |||||||
|     if (next == 0) { |     if (next == 0) { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
|     return Kernel::g_object_pool.GetFast<Thread>(next); |     return Kernel::g_object_pool.Get<Thread>(next); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -289,8 +286,7 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { | |||||||
|  |  | ||||||
| /// Resumes a thread from waiting by marking it as "ready" | /// Resumes a thread from waiting by marking it as "ready" | ||||||
| void ResumeThreadFromWait(Handle handle) { | void ResumeThreadFromWait(Handle handle) { | ||||||
|     u32 error; |     Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); | ||||||
|     Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error); |  | ||||||
|     if (thread) { |     if (thread) { | ||||||
|         thread->status &= ~THREADSTATUS_WAIT; |         thread->status &= ~THREADSTATUS_WAIT; | ||||||
|         if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |         if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | ||||||
| @@ -378,19 +374,23 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 | |||||||
| } | } | ||||||
|  |  | ||||||
| /// Get the priority of the thread specified by handle | /// Get the priority of the thread specified by handle | ||||||
| u32 GetThreadPriority(const Handle handle) { | ResultVal<u32> GetThreadPriority(const Handle handle) { | ||||||
|     Thread* thread = g_object_pool.GetFast<Thread>(handle); |     Thread* thread = g_object_pool.Get<Thread>(handle); | ||||||
|     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); |     if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); | ||||||
|     return thread->current_priority; |  | ||||||
|  |     return MakeResult<u32>(thread->current_priority); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Set the priority of the thread specified by handle | /// Set the priority of the thread specified by handle | ||||||
| Result SetThreadPriority(Handle handle, s32 priority) { | ResultCode SetThreadPriority(Handle handle, s32 priority) { | ||||||
|     Thread* thread = nullptr; |     Thread* thread = nullptr; | ||||||
|     if (!handle) { |     if (!handle) { | ||||||
|         thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? |         thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? | ||||||
|     } else { |     } else { | ||||||
|         thread = g_object_pool.GetFast<Thread>(handle); |         thread = g_object_pool.Get<Thread>(handle); | ||||||
|  |         if (thread == nullptr) { | ||||||
|  |             return InvalidHandle(ErrorModule::Kernel); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); |     _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); | ||||||
|  |  | ||||||
| @@ -417,7 +417,7 @@ Result SetThreadPriority(Handle handle, s32 priority) { | |||||||
|         thread_ready_queue.push_back(thread->current_priority, handle); |         thread_ready_queue.push_back(thread->current_priority, handle); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return 0; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Sets up the primary application thread | /// Sets up the primary application thread | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
|  |  | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  |  | ||||||
| enum ThreadPriority { | enum ThreadPriority { | ||||||
|     THREADPRIO_HIGHEST      = 0,    ///< Highest thread priority |     THREADPRIO_HIGHEST      = 0,    ///< Highest thread priority | ||||||
| @@ -55,7 +56,7 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); | |||||||
| void Reschedule(); | void Reschedule(); | ||||||
|  |  | ||||||
| /// Stops the current thread | /// Stops the current thread | ||||||
| void StopThread(Handle thread, const char* reason); | ResultCode StopThread(Handle thread, const char* reason); | ||||||
|  |  | ||||||
| /// Resumes a thread from waiting by marking it as "ready" | /// Resumes a thread from waiting by marking it as "ready" | ||||||
| void ResumeThreadFromWait(Handle handle); | void ResumeThreadFromWait(Handle handle); | ||||||
| @@ -80,10 +81,10 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHa | |||||||
| void WaitThread_Synchronization(); | void WaitThread_Synchronization(); | ||||||
|  |  | ||||||
| /// Get the priority of the thread specified by handle | /// Get the priority of the thread specified by handle | ||||||
| u32 GetThreadPriority(const Handle handle); | ResultVal<u32> GetThreadPriority(const Handle handle); | ||||||
|  |  | ||||||
| /// Set the priority of the thread specified by handle | /// Set the priority of the thread specified by handle | ||||||
| Result SetThreadPriority(Handle handle, s32 priority); | ResultCode SetThreadPriority(Handle handle, s32 priority); | ||||||
|  |  | ||||||
| /// Initialize threading | /// Initialize threading | ||||||
| void ThreadingInit(); | void ThreadingInit(); | ||||||
|   | |||||||
							
								
								
									
										400
									
								
								src/core/hle/result.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								src/core/hle/result.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,400 @@ | |||||||
|  | // Copyright 2014 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <cassert> | ||||||
|  | #include <cstddef> | ||||||
|  | #include <type_traits> | ||||||
|  | #include <utility> | ||||||
|  |  | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "common/bit_field.h" | ||||||
|  |  | ||||||
|  | // All the constants in this file come from http://3dbrew.org/wiki/Error_codes | ||||||
|  |  | ||||||
|  | /// Detailed description of the error. This listing is likely incomplete. | ||||||
|  | enum class ErrorDescription : u32 { | ||||||
|  |     Success = 0, | ||||||
|  |     InvalidSection = 1000, | ||||||
|  |     TooLarge = 1001, | ||||||
|  |     NotAuthorized = 1002, | ||||||
|  |     AlreadyDone = 1003, | ||||||
|  |     InvalidSize = 1004, | ||||||
|  |     InvalidEnumValue = 1005, | ||||||
|  |     InvalidCombination = 1006, | ||||||
|  |     NoData = 1007, | ||||||
|  |     Busy = 1008, | ||||||
|  |     MisalignedAddress = 1009, | ||||||
|  |     MisalignedSize = 1010, | ||||||
|  |     OutOfMemory = 1011, | ||||||
|  |     NotImplemented = 1012, | ||||||
|  |     InvalidAddress = 1013, | ||||||
|  |     InvalidPointer = 1014, | ||||||
|  |     InvalidHandle = 1015, | ||||||
|  |     NotInitialized = 1016, | ||||||
|  |     AlreadyInitialized = 1017, | ||||||
|  |     NotFound = 1018, | ||||||
|  |     CancelRequested = 1019, | ||||||
|  |     AlreadyExists = 1020, | ||||||
|  |     OutOfRange = 1021, | ||||||
|  |     Timeout = 1022, | ||||||
|  |     InvalidResultValue = 1023, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Identifies the module which caused the error. Error codes can be propagated through a call | ||||||
|  |  * chain, meaning that this doesn't always correspond to the module where the API call made is | ||||||
|  |  * contained. | ||||||
|  |  */ | ||||||
|  | enum class ErrorModule : u32 { | ||||||
|  |     Common = 0, | ||||||
|  |     Kernel = 1, | ||||||
|  |     Util = 2, | ||||||
|  |     FileServer = 3, | ||||||
|  |     LoaderServer = 4, | ||||||
|  |     TCB = 5, | ||||||
|  |     OS = 6, | ||||||
|  |     DBG = 7, | ||||||
|  |     DMNT = 8, | ||||||
|  |     PDN = 9, | ||||||
|  |     GX = 10, | ||||||
|  |     I2C = 11, | ||||||
|  |     GPIO = 12, | ||||||
|  |     DD = 13, | ||||||
|  |     CODEC = 14, | ||||||
|  |     SPI = 15, | ||||||
|  |     PXI = 16, | ||||||
|  |     FS = 17, | ||||||
|  |     DI = 18, | ||||||
|  |     HID = 19, | ||||||
|  |     CAM = 20, | ||||||
|  |     PI = 21, | ||||||
|  |     PM = 22, | ||||||
|  |     PM_LOW = 23, | ||||||
|  |     FSI = 24, | ||||||
|  |     SRV = 25, | ||||||
|  |     NDM = 26, | ||||||
|  |     NWM = 27, | ||||||
|  |     SOC = 28, | ||||||
|  |     LDR = 29, | ||||||
|  |     ACC = 30, | ||||||
|  |     RomFS = 31, | ||||||
|  |     AM = 32, | ||||||
|  |     HIO = 33, | ||||||
|  |     Updater = 34, | ||||||
|  |     MIC = 35, | ||||||
|  |     FND = 36, | ||||||
|  |     MP = 37, | ||||||
|  |     MPWL = 38, | ||||||
|  |     AC = 39, | ||||||
|  |     HTTP = 40, | ||||||
|  |     DSP = 41, | ||||||
|  |     SND = 42, | ||||||
|  |     DLP = 43, | ||||||
|  |     HIO_LOW = 44, | ||||||
|  |     CSND = 45, | ||||||
|  |     SSL = 46, | ||||||
|  |     AM_LOW = 47, | ||||||
|  |     NEX = 48, | ||||||
|  |     Friends = 49, | ||||||
|  |     RDT = 50, | ||||||
|  |     Applet = 51, | ||||||
|  |     NIM = 52, | ||||||
|  |     PTM = 53, | ||||||
|  |     MIDI = 54, | ||||||
|  |     MC = 55, | ||||||
|  |     SWC = 56, | ||||||
|  |     FatFS = 57, | ||||||
|  |     NGC = 58, | ||||||
|  |     CARD = 59, | ||||||
|  |     CARDNOR = 60, | ||||||
|  |     SDMC = 61, | ||||||
|  |     BOSS = 62, | ||||||
|  |     DBM = 63, | ||||||
|  |     Config = 64, | ||||||
|  |     PS = 65, | ||||||
|  |     CEC = 66, | ||||||
|  |     IR = 67, | ||||||
|  |     UDS = 68, | ||||||
|  |     PL = 69, | ||||||
|  |     CUP = 70, | ||||||
|  |     Gyroscope = 71, | ||||||
|  |     MCU = 72, | ||||||
|  |     NS = 73, | ||||||
|  |     News = 74, | ||||||
|  |     RO_1 = 75, | ||||||
|  |     GD = 76, | ||||||
|  |     CardSPI = 77, | ||||||
|  |     EC = 78, | ||||||
|  |     RO_2 = 79, | ||||||
|  |     WebBrowser = 80, | ||||||
|  |     Test = 81, | ||||||
|  |     ENC = 82, | ||||||
|  |     PIA = 83, | ||||||
|  |  | ||||||
|  |     Application = 254, | ||||||
|  |     InvalidResult = 255 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// A less specific error cause. | ||||||
|  | enum class ErrorSummary : u32 { | ||||||
|  |     Success = 0, | ||||||
|  |     NothingHappened = 1, | ||||||
|  |     WouldBlock = 2, | ||||||
|  |     OutOfResource = 3,      ///< There are no more kernel resources (memory, table slots) to | ||||||
|  |                             ///< execute the operation. | ||||||
|  |     NotFound = 4,           ///< A file or resource was not found. | ||||||
|  |     InvalidState = 5, | ||||||
|  |     NotSupported = 6,       ///< The operation is not supported or not implemented. | ||||||
|  |     InvalidArgument = 7,    ///< Returned when a passed argument is invalid in the current runtime | ||||||
|  |                             ///< context. (Invalid handle, out-of-bounds pointer or size, etc.) | ||||||
|  |     WrongArgument = 8,      ///< Returned when a passed argument is in an incorrect format for use | ||||||
|  |                             ///< with the function. (E.g. Invalid enum value) | ||||||
|  |     Canceled = 9, | ||||||
|  |     StatusChanged = 10, | ||||||
|  |     Internal = 11, | ||||||
|  |  | ||||||
|  |     InvalidResult = 63 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// The severity of the error. | ||||||
|  | enum class ErrorLevel : u32 { | ||||||
|  |     Success = 0, | ||||||
|  |     Info = 1, | ||||||
|  |  | ||||||
|  |     Status = 25, | ||||||
|  |     Temporary = 26, | ||||||
|  |     Permanent = 27, | ||||||
|  |     Usage = 28, | ||||||
|  |     Reinitialize = 29, | ||||||
|  |     Reset = 30, | ||||||
|  |     Fatal = 31 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields. | ||||||
|  | union ResultCode { | ||||||
|  |     u32 raw; | ||||||
|  |  | ||||||
|  |     BitField<0, 10, ErrorDescription> description; | ||||||
|  |     BitField<10, 8, ErrorModule> module; | ||||||
|  |  | ||||||
|  |     BitField<21, 6, ErrorSummary> summary; | ||||||
|  |     BitField<27, 5, ErrorLevel> level; | ||||||
|  |  | ||||||
|  |     // The last bit of `level` is checked by apps and the kernel to determine if a result code is an error | ||||||
|  |     BitField<31, 1, u32> is_error; | ||||||
|  |  | ||||||
|  |     explicit ResultCode(u32 raw) : raw(raw) {} | ||||||
|  |     ResultCode(ErrorDescription description_, ErrorModule module_, | ||||||
|  |             ErrorSummary summary_, ErrorLevel level_) : raw(0) { | ||||||
|  |         description = description_; | ||||||
|  |         module = module_; | ||||||
|  |         summary = summary_; | ||||||
|  |         level = level_; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; } | ||||||
|  |  | ||||||
|  |     bool IsSuccess() const { | ||||||
|  |         return is_error == 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool IsError() const { | ||||||
|  |         return is_error == 1; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | inline bool operator==(const ResultCode a, const ResultCode b) { | ||||||
|  |     return a.raw == b.raw; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline bool operator!=(const ResultCode a, const ResultCode b) { | ||||||
|  |     return a.raw != b.raw; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Convenience functions for creating some common kinds of errors: | ||||||
|  |  | ||||||
|  | /// The default success `ResultCode`. | ||||||
|  | const ResultCode RESULT_SUCCESS(0); | ||||||
|  |  | ||||||
|  | /// Might be returned instead of a dummy success for unimplemented APIs. | ||||||
|  | inline ResultCode UnimplementedFunction(ErrorModule module) { | ||||||
|  |     return ResultCode(ErrorDescription::NotImplemented, module, | ||||||
|  |             ErrorSummary::NotSupported, ErrorLevel::Permanent); | ||||||
|  | } | ||||||
|  | /// Returned when a function is passed an invalid handle. | ||||||
|  | inline ResultCode InvalidHandle(ErrorModule module) { | ||||||
|  |     return ResultCode(ErrorDescription::InvalidHandle, module, | ||||||
|  |             ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This is an optional value type. It holds a `ResultCode` and, if that code is a success code, | ||||||
|  |  * also holds a result of type `T`. If the code is an error code then trying to access the inner | ||||||
|  |  * value fails, thus ensuring that the ResultCode of functions is always checked properly before | ||||||
|  |  * their return value is used.  It is similar in concept to the `std::optional` type | ||||||
|  |  * (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in | ||||||
|  |  * C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html). | ||||||
|  |  * | ||||||
|  |  * An example of how it could be used: | ||||||
|  |  * \code | ||||||
|  |  * ResultVal<int> Frobnicate(float strength) { | ||||||
|  |  *     if (strength < 0.f || strength > 1.0f) { | ||||||
|  |  *         // Can't frobnicate too weakly or too strongly | ||||||
|  |  *         return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common, | ||||||
|  |  *             ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||||||
|  |  *     } else { | ||||||
|  |  *         // Frobnicated! Give caller a cookie | ||||||
|  |  *         return MakeResult<int>(42); | ||||||
|  |  *     } | ||||||
|  |  * } | ||||||
|  |  * \endcode | ||||||
|  |  * | ||||||
|  |  * \code | ||||||
|  |  * ResultVal<int> frob_result = Frobnicate(0.75f); | ||||||
|  |  * if (frob_result) { | ||||||
|  |  *     // Frobbed ok | ||||||
|  |  *     printf("My cookie is %d\n", *frob_result); | ||||||
|  |  * } else { | ||||||
|  |  *     printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex); | ||||||
|  |  * } | ||||||
|  |  * \endcode | ||||||
|  |  */ | ||||||
|  | template <typename T> | ||||||
|  | class ResultVal { | ||||||
|  | public: | ||||||
|  |     /// Constructs an empty `ResultVal` with the given error code. The code must not be a success code. | ||||||
|  |     ResultVal(ResultCode error_code = ResultCode(-1)) | ||||||
|  |         : result_code(error_code) | ||||||
|  |     { | ||||||
|  |         assert(error_code.IsError()); | ||||||
|  |         UpdateDebugPtr(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Similar to the non-member function `MakeResult`, with the exception that you can manually | ||||||
|  |      * specify the success code. `success_code` must not be an error code. | ||||||
|  |      */ | ||||||
|  |     template <typename... Args> | ||||||
|  |     static ResultVal WithCode(ResultCode success_code, Args&&... args) { | ||||||
|  |         ResultVal<T> result; | ||||||
|  |         result.emplace(success_code, std::forward<Args>(args)...); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ResultVal(const ResultVal& o) | ||||||
|  |         : result_code(o.result_code) | ||||||
|  |     { | ||||||
|  |         if (!o.empty()) { | ||||||
|  |             new (&storage) T(*o.GetPointer()); | ||||||
|  |         } | ||||||
|  |         UpdateDebugPtr(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ResultVal(ResultVal&& o) | ||||||
|  |         : result_code(o.result_code) | ||||||
|  |     { | ||||||
|  |         if (!o.empty()) { | ||||||
|  |             new (&storage) T(std::move(*o.GetPointer())); | ||||||
|  |         } | ||||||
|  |         UpdateDebugPtr(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ~ResultVal() { | ||||||
|  |         if (!empty()) { | ||||||
|  |             GetPointer()->~T(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ResultVal& operator=(const ResultVal& o) { | ||||||
|  |         if (*this) { | ||||||
|  |             if (o) { | ||||||
|  |                 *GetPointer() = *o.GetPointer(); | ||||||
|  |             } else { | ||||||
|  |                 GetPointer()->~T(); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if (o) { | ||||||
|  |                 new (&storage) T(*o.GetPointer()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         result_code = o.result_code; | ||||||
|  |         UpdateDebugPtr(); | ||||||
|  |  | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Replaces the current result with a new constructed result value in-place. The code must not | ||||||
|  |      * be an error code. | ||||||
|  |      */ | ||||||
|  |     template <typename... Args> | ||||||
|  |     void emplace(ResultCode success_code, Args&&... args) { | ||||||
|  |         assert(success_code.IsSuccess()); | ||||||
|  |         if (!empty()) { | ||||||
|  |             GetPointer()->~T(); | ||||||
|  |         } | ||||||
|  |         new (&storage) T(std::forward<Args>(args)...); | ||||||
|  |         result_code = success_code; | ||||||
|  |         UpdateDebugPtr(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns true if the `ResultVal` contains an error code and no value. | ||||||
|  |     bool empty() const { return result_code.IsError(); } | ||||||
|  |  | ||||||
|  |     /// Returns true if the `ResultVal` contains a return value. | ||||||
|  |     bool Succeeded() const { return result_code.IsSuccess(); } | ||||||
|  |     /// Returns true if the `ResultVal` contains an error code and no value. | ||||||
|  |     bool Failed() const { return empty(); } | ||||||
|  |  | ||||||
|  |     ResultCode Code() const { return result_code; } | ||||||
|  |  | ||||||
|  |     const T& operator* () const { return *GetPointer(); } | ||||||
|  |           T& operator* ()       { return *GetPointer(); } | ||||||
|  |     const T* operator->() const { return  GetPointer(); } | ||||||
|  |           T* operator->()       { return  GetPointer(); } | ||||||
|  |  | ||||||
|  |     /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. | ||||||
|  |     template <typename U> | ||||||
|  |     T ValueOr(U&& value) const { | ||||||
|  |         return !empty() ? *GetPointer() : std::move(value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; | ||||||
|  |  | ||||||
|  |     StorageType storage; | ||||||
|  |     ResultCode result_code; | ||||||
|  | #if _DEBUG | ||||||
|  |     // The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the | ||||||
|  |     // need to cast `storage` to a pointer or pay attention to `result_code`. | ||||||
|  |     const T* debug_ptr; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     void UpdateDebugPtr() { | ||||||
|  | #if _DEBUG | ||||||
|  |         debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage)); | ||||||
|  | #endif | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const T* GetPointer() const { | ||||||
|  |         assert(!empty()); | ||||||
|  |         return static_cast<const T*>(static_cast<const void*>(&storage)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     T* GetPointer() { | ||||||
|  |         assert(!empty()); | ||||||
|  |         return static_cast<T*>(static_cast<void*>(&storage)); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This function is a helper used to construct `ResultVal`s. It receives the arguments to construct | ||||||
|  |  * `T` with and creates a success `ResultVal` contained the constructed value. | ||||||
|  |  */ | ||||||
|  | template <typename T, typename... Args> | ||||||
|  | ResultVal<T> MakeResult(Args&&... args) { | ||||||
|  |     return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...); | ||||||
|  | } | ||||||
| @@ -4,26 +4,24 @@ | |||||||
|  |  | ||||||
| #include "common/common.h" | #include "common/common.h" | ||||||
|  |  | ||||||
| #include "fs_user.h" |  | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
| #include "core/settings.h" |  | ||||||
| #include "core/hle/kernel/archive.h" | #include "core/hle/kernel/archive.h" | ||||||
|  | #include "core/hle/kernel/archive.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
|  | #include "core/hle/service/fs_user.h" | ||||||
|  | #include "core/settings.h" | ||||||
|  |  | ||||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
| // Namespace FS_User | // Namespace FS_User | ||||||
|  |  | ||||||
| namespace FS_User { | namespace FS_User { | ||||||
|  |  | ||||||
| // We currently return 0 for success and -1 for failure in cmd_buff[1].  -1 was chosen because it |  | ||||||
| // puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make |  | ||||||
| // sure we don't mislead the application into thinking something worked. |  | ||||||
|  |  | ||||||
| static void Initialize(Service::Interface* self) { | static void Initialize(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Service::GetCommandBuffer(); |     u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|  |  | ||||||
|     // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per |     // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per | ||||||
|     // http://3dbrew.org/wiki/FS:Initialize#Request |     // http://3dbrew.org/wiki/FS:Initialize#Request | ||||||
|     cmd_buff[1] = 0; |     cmd_buff[1] = RESULT_SUCCESS.raw; | ||||||
|  |  | ||||||
|     DEBUG_LOG(KERNEL, "called"); |     DEBUG_LOG(KERNEL, "called"); | ||||||
| } | } | ||||||
| @@ -59,14 +57,12 @@ static void OpenFile(Service::Interface* self) { | |||||||
|  |  | ||||||
|     DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%d", file_path.DebugStr().c_str(), mode, attributes); |     DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%d", file_path.DebugStr().c_str(), mode, attributes); | ||||||
|  |  | ||||||
|     Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); |     ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); | ||||||
|     if (handle) { |     cmd_buff[1] = handle.Code().raw; | ||||||
|         cmd_buff[1] = 0; |     if (handle.Succeeded()) { | ||||||
|         cmd_buff[3] = handle; |         cmd_buff[3] = *handle; | ||||||
|     } else { |     } else { | ||||||
|         ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |         ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | ||||||
|         // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. |  | ||||||
|         cmd_buff[1] = -1; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DEBUG_LOG(KERNEL, "called"); |     DEBUG_LOG(KERNEL, "called"); | ||||||
| @@ -111,27 +107,27 @@ static void OpenFileDirectly(Service::Interface* self) { | |||||||
|  |  | ||||||
|     if (archive_path.GetType() != FileSys::Empty) { |     if (archive_path.GetType() != FileSys::Empty) { | ||||||
|         ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); |         ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); | ||||||
|         cmd_buff[1] = -1; |         cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it |     // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it | ||||||
|     Handle archive_handle = Kernel::OpenArchive(archive_id); |     // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? | ||||||
|     if (!archive_handle) { |     ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id); | ||||||
|  |     cmd_buff[1] = archive_handle.Code().raw; | ||||||
|  |     if (archive_handle.Failed()) { | ||||||
|         ERROR_LOG(KERNEL, "failed to get a handle for archive"); |         ERROR_LOG(KERNEL, "failed to get a handle for archive"); | ||||||
|         // TODO(Link Mauve): Check for the actual error values, this one was just chosen arbitrarily |  | ||||||
|         cmd_buff[1] = -1; |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |     // cmd_buff[2] isn't used according to 3dmoo's implementation. | ||||||
|  |     cmd_buff[3] = *archive_handle; | ||||||
|  |  | ||||||
|     Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); |     ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode); | ||||||
|     if (handle) { |     cmd_buff[1] = handle.Code().raw; | ||||||
|         cmd_buff[1] = 0; |     if (handle.Succeeded()) { | ||||||
|         cmd_buff[3] = handle; |         cmd_buff[3] = *handle; | ||||||
|     } else { |     } else { | ||||||
|         ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |         ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | ||||||
|         // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. |  | ||||||
|         cmd_buff[1] = -1; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DEBUG_LOG(KERNEL, "called"); |     DEBUG_LOG(KERNEL, "called"); | ||||||
| @@ -243,14 +239,12 @@ static void OpenDirectory(Service::Interface* self) { | |||||||
|  |  | ||||||
|     DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); |     DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); | ||||||
|  |  | ||||||
|     Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); |     ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); | ||||||
|     if (handle) { |     cmd_buff[1] = handle.Code().raw; | ||||||
|         cmd_buff[1] = 0; |     if (handle.Succeeded()) { | ||||||
|         cmd_buff[3] = handle; |         cmd_buff[3] = *handle; | ||||||
|     } else { |     } else { | ||||||
|         ERROR_LOG(KERNEL, "failed to get a handle for directory"); |         ERROR_LOG(KERNEL, "failed to get a handle for directory"); | ||||||
|         // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. |  | ||||||
|         cmd_buff[1] = -1; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DEBUG_LOG(KERNEL, "called"); |     DEBUG_LOG(KERNEL, "called"); | ||||||
| @@ -282,19 +276,17 @@ static void OpenArchive(Service::Interface* self) { | |||||||
|  |  | ||||||
|     if (archive_path.GetType() != FileSys::Empty) { |     if (archive_path.GetType() != FileSys::Empty) { | ||||||
|         ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); |         ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); | ||||||
|         cmd_buff[1] = -1; |         cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Handle handle = Kernel::OpenArchive(archive_id); |     ResultVal<Handle> handle = Kernel::OpenArchive(archive_id); | ||||||
|     if (handle) { |     cmd_buff[1] = handle.Code().raw; | ||||||
|         cmd_buff[1] = 0; |     if (handle.Succeeded()) { | ||||||
|         // cmd_buff[2] isn't used according to 3dmoo's implementation. |         // cmd_buff[2] isn't used according to 3dmoo's implementation. | ||||||
|         cmd_buff[3] = handle; |         cmd_buff[3] = *handle; | ||||||
|     } else { |     } else { | ||||||
|         ERROR_LOG(KERNEL, "failed to get a handle for archive"); |         ERROR_LOG(KERNEL, "failed to get a handle for archive"); | ||||||
|         // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. |  | ||||||
|         cmd_buff[1] = -1; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DEBUG_LOG(KERNEL, "called"); |     DEBUG_LOG(KERNEL, "called"); | ||||||
|   | |||||||
| @@ -28,28 +28,23 @@ u32 g_thread_id = 1;            ///< Thread index into interrupt relay queue, 1 | |||||||
|  |  | ||||||
| /// Gets a pointer to a thread command buffer in GSP shared memory | /// Gets a pointer to a thread command buffer in GSP shared memory | ||||||
| static inline u8* GetCommandBuffer(u32 thread_id) { | static inline u8* GetCommandBuffer(u32 thread_id) { | ||||||
|     if (0 == g_shared_memory) |     ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer))); | ||||||
|         return nullptr; |     return ptr.ValueOr(nullptr); | ||||||
|  |  | ||||||
|     return Kernel::GetSharedMemoryPointer(g_shared_memory, |  | ||||||
|         0x800 + (thread_id * sizeof(CommandBuffer))); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { | static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { | ||||||
|     if (0 == g_shared_memory) |  | ||||||
|         return nullptr; |  | ||||||
|  |  | ||||||
|     _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index"); |     _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index"); | ||||||
|  |  | ||||||
|     // For each thread there are two FrameBufferUpdate fields |     // For each thread there are two FrameBufferUpdate fields | ||||||
|     u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); |     u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); | ||||||
|     return (FrameBufferUpdate*)Kernel::GetSharedMemoryPointer(g_shared_memory, offset); |     ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, offset); | ||||||
|  |     return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr)); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Gets a pointer to the interrupt relay queue for a given thread index | /// Gets a pointer to the interrupt relay queue for a given thread index | ||||||
| static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { | static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { | ||||||
|     return (InterruptRelayQueue*)Kernel::GetSharedMemoryPointer(g_shared_memory, |     ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id); | ||||||
|         sizeof(InterruptRelayQueue) * thread_id); |     return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr)); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { | static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { | ||||||
|   | |||||||
| @@ -34,10 +34,7 @@ static s16 next_circle_y = 0; | |||||||
|  * Gets a pointer to the PadData structure inside HID shared memory |  * Gets a pointer to the PadData structure inside HID shared memory | ||||||
|  */ |  */ | ||||||
| static inline PadData* GetPadData() { | static inline PadData* GetPadData() { | ||||||
|     if (0 == shared_mem) |     return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0).ValueOr(nullptr)); | ||||||
|         return nullptr; |  | ||||||
|  |  | ||||||
|     return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   | |||||||
| @@ -62,7 +62,7 @@ void Manager::DeleteService(const std::string& port_name) { | |||||||
|  |  | ||||||
| /// Get a Service Interface from its Handle | /// Get a Service Interface from its Handle | ||||||
| Interface* Manager::FetchFromHandle(Handle handle) { | Interface* Manager::FetchFromHandle(Handle handle) { | ||||||
|     return Kernel::g_object_pool.GetFast<Interface>(handle); |     return Kernel::g_object_pool.Get<Interface>(handle); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Get a Service Interface from its port | /// Get a Service Interface from its port | ||||||
|   | |||||||
| @@ -75,12 +75,7 @@ public: | |||||||
|         m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); |         m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> SyncRequest() override { | ||||||
|      * Synchronize kernel object |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result SyncRequest(bool* wait) override { |  | ||||||
|         u32* cmd_buff = GetCommandBuffer(); |         u32* cmd_buff = GetCommandBuffer(); | ||||||
|         auto itr = m_functions.find(cmd_buff[0]); |         auto itr = m_functions.find(cmd_buff[0]); | ||||||
|  |  | ||||||
| @@ -91,7 +86,7 @@ public: | |||||||
|             // TODO(bunnei): Hack - ignore error |             // TODO(bunnei): Hack - ignore error | ||||||
|             u32* cmd_buff = Service::GetCommandBuffer(); |             u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|             cmd_buff[1] = 0; |             cmd_buff[1] = 0; | ||||||
|             return 0; |             return MakeResult<bool>(false); | ||||||
|         } |         } | ||||||
|         if (itr->second.func == nullptr) { |         if (itr->second.func == nullptr) { | ||||||
|             ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", |             ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", | ||||||
| @@ -100,23 +95,18 @@ public: | |||||||
|             // TODO(bunnei): Hack - ignore error |             // TODO(bunnei): Hack - ignore error | ||||||
|             u32* cmd_buff = Service::GetCommandBuffer(); |             u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|             cmd_buff[1] = 0; |             cmd_buff[1] = 0; | ||||||
|             return 0; |             return MakeResult<bool>(false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         itr->second.func(this); |         itr->second.func(this); | ||||||
|  |  | ||||||
|         return 0; // TODO: Implement return from actual function |         return MakeResult<bool>(false); // TODO: Implement return from actual function | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     ResultVal<bool> WaitSynchronization() override { | ||||||
|      * Wait for kernel object to synchronize |  | ||||||
|      * @param wait Boolean wait set if current thread should wait as a result of sync operation |  | ||||||
|      * @return Result of operation, 0 on success, otherwise error code |  | ||||||
|      */ |  | ||||||
|     Result WaitSynchronization(bool* wait) override { |  | ||||||
|         // TODO(bunnei): ImplementMe |         // TODO(bunnei): ImplementMe | ||||||
|         ERROR_LOG(OSHLE, "unimplemented function"); |         ERROR_LOG(OSHLE, "unimplemented function"); | ||||||
|         return 0; |         return UnimplementedFunction(ErrorModule::OS); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|   | |||||||
| @@ -35,7 +35,7 @@ static void GetProcSemaphore(Service::Interface* self) { | |||||||
| } | } | ||||||
|  |  | ||||||
| static void GetServiceHandle(Service::Interface* self) { | static void GetServiceHandle(Service::Interface* self) { | ||||||
|     Result res = 0; |     ResultCode res = RESULT_SUCCESS; | ||||||
|     u32* cmd_buff = Service::GetCommandBuffer(); |     u32* cmd_buff = Service::GetCommandBuffer(); | ||||||
|  |  | ||||||
|     std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); |     std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); | ||||||
| @@ -46,9 +46,9 @@ static void GetServiceHandle(Service::Interface* self) { | |||||||
|         DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); |         DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); | ||||||
|     } else { |     } else { | ||||||
|         ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); |         ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); | ||||||
|         res = -1; |         res = UnimplementedFunction(ErrorModule::SRV); | ||||||
|     } |     } | ||||||
|     cmd_buff[1] = res; |     cmd_buff[1] = res.raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| const Interface::FunctionInfo FunctionTable[] = { | const Interface::FunctionInfo FunctionTable[] = { | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ | |||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
|  |  | ||||||
| #include "core/hle/function_wrappers.h" | #include "core/hle/function_wrappers.h" | ||||||
|  | #include "core/hle/result.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
|  |  | ||||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||||
| @@ -86,18 +87,22 @@ static Result ConnectToPort(Handle* out, const char* port_name) { | |||||||
|  |  | ||||||
| /// Synchronize to an OS service | /// Synchronize to an OS service | ||||||
| static Result SendSyncRequest(Handle handle) { | static Result SendSyncRequest(Handle handle) { | ||||||
|  |     // TODO(yuriks): ObjectPool::Get tries to check the Object type, which fails since this is a generic base Object, | ||||||
|  |     // so we are forced to use GetFast and manually verify the handle. | ||||||
|  |     if (!Kernel::g_object_pool.IsValid(handle)) { | ||||||
|  |         return InvalidHandle(ErrorModule::Kernel).raw; | ||||||
|  |     } | ||||||
|     Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); |     Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); | ||||||
|  |  | ||||||
|     _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); |     _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); | ||||||
|     DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str()); |     DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str()); | ||||||
|  |  | ||||||
|     bool wait = false; |     ResultVal<bool> wait = object->SyncRequest(); | ||||||
|     Result res = object->SyncRequest(&wait); |     if (wait.Succeeded() && *wait) { | ||||||
|     if (wait) { |  | ||||||
|         Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? |         Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return res; |     return wait.Code().raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Close a handle | /// Close a handle | ||||||
| @@ -110,25 +115,25 @@ static Result CloseHandle(Handle handle) { | |||||||
| /// Wait for a handle to synchronize, timeout after the specified nanoseconds | /// Wait for a handle to synchronize, timeout after the specified nanoseconds | ||||||
| static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { | ||||||
|     // TODO(bunnei): Do something with nano_seconds, currently ignoring this |     // TODO(bunnei): Do something with nano_seconds, currently ignoring this | ||||||
|     bool wait = false; |  | ||||||
|     bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated |     bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated | ||||||
|  |  | ||||||
|  |     if (!Kernel::g_object_pool.IsValid(handle)) { | ||||||
|  |         return InvalidHandle(ErrorModule::Kernel).raw; | ||||||
|  |     } | ||||||
|     Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); |     Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); | ||||||
|  |     _dbg_assert_(KERNEL, object != nullptr); | ||||||
|  |  | ||||||
|     DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), |     DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), | ||||||
|             object->GetName().c_str(), nano_seconds); |             object->GetName().c_str(), nano_seconds); | ||||||
|  |  | ||||||
|     _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); |     ResultVal<bool> wait = object->WaitSynchronization(); | ||||||
|  |  | ||||||
|     Result res = object->WaitSynchronization(&wait); |  | ||||||
|  |  | ||||||
|     // Check for next thread to schedule |     // Check for next thread to schedule | ||||||
|     if (wait) { |     if (wait.Succeeded() && *wait) { | ||||||
|         HLE::Reschedule(__func__); |         HLE::Reschedule(__func__); | ||||||
|         return 0; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return res; |     return wait.Code().raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | ||||||
| @@ -143,20 +148,21 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||||||
|  |  | ||||||
|     // Iterate through each handle, synchronize kernel object |     // Iterate through each handle, synchronize kernel object | ||||||
|     for (s32 i = 0; i < handle_count; i++) { |     for (s32 i = 0; i < handle_count; i++) { | ||||||
|         bool wait = false; |         if (!Kernel::g_object_pool.IsValid(handles[i])) { | ||||||
|  |             return InvalidHandle(ErrorModule::Kernel).raw; | ||||||
|  |         } | ||||||
|         Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); |         Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); | ||||||
|  |  | ||||||
|         _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object " |  | ||||||
|             "is nullptr!", handles[i]); |  | ||||||
|  |  | ||||||
|         DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), |         DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), | ||||||
|             object->GetName().c_str()); |             object->GetName().c_str()); | ||||||
|  |  | ||||||
|         Result res = object->WaitSynchronization(&wait); |         // TODO(yuriks): Verify how the real function behaves when an error happens here | ||||||
|  |         ResultVal<bool> wait_result = object->WaitSynchronization(); | ||||||
|  |         bool wait = wait_result.Succeeded() && *wait_result; | ||||||
|  |  | ||||||
|         if (!wait && !wait_all) { |         if (!wait && !wait_all) { | ||||||
|             *out = i; |             *out = i; | ||||||
|             return 0; |             return RESULT_SUCCESS.raw; | ||||||
|         } else { |         } else { | ||||||
|             unlock_all = false; |             unlock_all = false; | ||||||
|         } |         } | ||||||
| @@ -164,13 +170,13 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, | |||||||
|  |  | ||||||
|     if (wait_all && unlock_all) { |     if (wait_all && unlock_all) { | ||||||
|         *out = handle_count; |         *out = handle_count; | ||||||
|         return 0; |         return RESULT_SUCCESS.raw; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Check for next thread to schedule |     // Check for next thread to schedule | ||||||
|     HLE::Reschedule(__func__); |     HLE::Reschedule(__func__); | ||||||
|  |  | ||||||
|     return 0; |     return RESULT_SUCCESS.raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Create an address arbiter (to allocate access to shared resources) | /// Create an address arbiter (to allocate access to shared resources) | ||||||
| @@ -183,8 +189,8 @@ static Result CreateAddressArbiter(u32* arbiter) { | |||||||
|  |  | ||||||
| /// Arbitrate address | /// Arbitrate address | ||||||
| static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { | static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { | ||||||
|     return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), address, |     return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), | ||||||
|         value); |             address, value).raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Used to output a message on a debug hardware unit - does nothing on a retail unit | /// Used to output a message on a debug hardware unit - does nothing on a retail unit | ||||||
| @@ -246,13 +252,16 @@ static u32 ExitThread() { | |||||||
|  |  | ||||||
| /// Gets the priority for the specified thread | /// Gets the priority for the specified thread | ||||||
| static Result GetThreadPriority(s32* priority, Handle handle) { | static Result GetThreadPriority(s32* priority, Handle handle) { | ||||||
|     *priority = Kernel::GetThreadPriority(handle); |     ResultVal<u32> priority_result = Kernel::GetThreadPriority(handle); | ||||||
|     return 0; |     if (priority_result.Succeeded()) { | ||||||
|  |         *priority = *priority_result; | ||||||
|  |     } | ||||||
|  |     return priority_result.Code().raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Sets the priority for the specified thread | /// Sets the priority for the specified thread | ||||||
| static Result SetThreadPriority(Handle handle, s32 priority) { | static Result SetThreadPriority(Handle handle, s32 priority) { | ||||||
|     return Kernel::SetThreadPriority(handle, priority); |     return Kernel::SetThreadPriority(handle, priority).raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Create a mutex | /// Create a mutex | ||||||
| @@ -266,9 +275,8 @@ static Result CreateMutex(Handle* mutex, u32 initial_locked) { | |||||||
| /// Release a mutex | /// Release a mutex | ||||||
| static Result ReleaseMutex(Handle handle) { | static Result ReleaseMutex(Handle handle) { | ||||||
|     DEBUG_LOG(SVC, "called handle=0x%08X", handle); |     DEBUG_LOG(SVC, "called handle=0x%08X", handle); | ||||||
|     _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!"); |     ResultCode res = Kernel::ReleaseMutex(handle); | ||||||
|     Kernel::ReleaseMutex(handle); |     return res.raw; | ||||||
|     return 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Get current thread ID | /// Get current thread ID | ||||||
| @@ -310,16 +318,14 @@ static Result DuplicateHandle(Handle* out, Handle handle) { | |||||||
|  |  | ||||||
| /// Signals an event | /// Signals an event | ||||||
| static Result SignalEvent(Handle evt) { | static Result SignalEvent(Handle evt) { | ||||||
|     Result res = Kernel::SignalEvent(evt); |  | ||||||
|     DEBUG_LOG(SVC, "called event=0x%08X", evt); |     DEBUG_LOG(SVC, "called event=0x%08X", evt); | ||||||
|     return res; |     return Kernel::SignalEvent(evt).raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Clears an event | /// Clears an event | ||||||
| static Result ClearEvent(Handle evt) { | static Result ClearEvent(Handle evt) { | ||||||
|     Result res = Kernel::ClearEvent(evt); |  | ||||||
|     DEBUG_LOG(SVC, "called event=0x%08X", evt); |     DEBUG_LOG(SVC, "called event=0x%08X", evt); | ||||||
|     return res; |     return Kernel::ClearEvent(evt).raw; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Sleep the current thread | /// Sleep the current thread | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user