mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-23 01:50:04 +00:00
commit
bb730855e5
@ -133,6 +133,7 @@ set(HEADERS
|
||||
hle/service/srv.h
|
||||
hle/service/ssl_c.h
|
||||
hle/config_mem.h
|
||||
hle/result.h
|
||||
hle/function_wrappers.h
|
||||
hle/hle.h
|
||||
hle/svc.h
|
||||
|
@ -799,22 +799,24 @@ pascal void SpinCursor (short increment); /* copied from CursorCtl.h */
|
||||
#include "list.h"
|
||||
#include "tb.h"
|
||||
*/
|
||||
#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
|
||||
enum ConditionCode {
|
||||
EQ = 0,
|
||||
NE = 1,
|
||||
CS = 2,
|
||||
CC = 3,
|
||||
MI = 4,
|
||||
PL = 5,
|
||||
VS = 6,
|
||||
VC = 7,
|
||||
HI = 8,
|
||||
LS = 9,
|
||||
GE = 10,
|
||||
LT = 11,
|
||||
GT = 12,
|
||||
LE = 13,
|
||||
AL = 14,
|
||||
NV = 15,
|
||||
};
|
||||
|
||||
#ifndef NFLAG
|
||||
#define NFLAG state->NFlag
|
||||
|
@ -25,24 +25,6 @@
|
||||
|
||||
#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. */
|
||||
#define LSL 0
|
||||
#define LSR 1
|
||||
|
@ -25,22 +25,17 @@ public:
|
||||
|
||||
std::string name; ///< Name of address arbiter object (optional)
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
// TODO(bunnei): ImplementMe
|
||||
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
|
||||
return 0;
|
||||
return UnimplementedFunction(ErrorModule::OS);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// 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) {
|
||||
|
||||
// Signal thread(s) waiting for arbitrate address...
|
||||
@ -65,9 +60,9 @@ Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 va
|
||||
|
||||
default:
|
||||
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
|
||||
|
@ -28,7 +28,7 @@ enum class ArbitrationType : u32 {
|
||||
};
|
||||
|
||||
/// 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
|
||||
Handle CreateAddressArbiter(const std::string& name = "Unknown");
|
||||
|
@ -9,8 +9,9 @@
|
||||
#include "core/file_sys/archive.h"
|
||||
#include "core/file_sys/archive_sdmc.h"
|
||||
#include "core/file_sys/directory.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/kernel/archive.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Kernel namespace
|
||||
@ -51,12 +52,7 @@ public:
|
||||
std::string name; ///< Name of archive (optional)
|
||||
FileSys::Archive* backend; ///< Archive backend interface
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> SyncRequest() override {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
|
||||
|
||||
@ -106,22 +102,17 @@ public:
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
|
||||
return -1;
|
||||
return UnimplementedFunction(ErrorModule::FS);
|
||||
}
|
||||
}
|
||||
cmd_buff[1] = 0; // No error
|
||||
return 0;
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
// TODO(bunnei): ImplementMe
|
||||
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
|
||||
return 0;
|
||||
return UnimplementedFunction(ErrorModule::FS);
|
||||
}
|
||||
};
|
||||
|
||||
@ -136,12 +127,7 @@ public:
|
||||
FileSys::Path path; ///< Path of the file
|
||||
std::unique_ptr<FileSys::File> backend; ///< File backend interface
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> SyncRequest() override {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
|
||||
switch (cmd) {
|
||||
@ -183,7 +169,8 @@ public:
|
||||
case FileCommand::SetSize:
|
||||
{
|
||||
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);
|
||||
break;
|
||||
}
|
||||
@ -198,22 +185,18 @@ public:
|
||||
// Unknown command...
|
||||
default:
|
||||
ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
|
||||
cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that.
|
||||
return -1;
|
||||
ResultCode error = UnimplementedFunction(ErrorModule::FS);
|
||||
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
|
||||
return error;
|
||||
}
|
||||
cmd_buff[1] = 0; // No error
|
||||
return 0;
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
// TODO(bunnei): ImplementMe
|
||||
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
|
||||
return 0;
|
||||
return UnimplementedFunction(ErrorModule::FS);
|
||||
}
|
||||
};
|
||||
|
||||
@ -228,12 +211,7 @@ public:
|
||||
FileSys::Path path; ///< Path of the directory
|
||||
std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> SyncRequest() override {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
|
||||
switch (cmd) {
|
||||
@ -243,8 +221,9 @@ public:
|
||||
{
|
||||
u32 count = cmd_buff[1];
|
||||
u32 address = cmd_buff[3];
|
||||
FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
|
||||
DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count);
|
||||
auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
|
||||
DEBUG_LOG(KERNEL, "Read %s %s: count=%d",
|
||||
GetTypeName().c_str(), GetName().c_str(), count);
|
||||
|
||||
// Number of entries actually read
|
||||
cmd_buff[2] = backend->Read(count, entries);
|
||||
@ -261,22 +240,18 @@ public:
|
||||
// Unknown command...
|
||||
default:
|
||||
ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
|
||||
cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that.
|
||||
return -1;
|
||||
ResultCode error = UnimplementedFunction(ErrorModule::FS);
|
||||
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
|
||||
return error;
|
||||
}
|
||||
cmd_buff[1] = 0; // No error
|
||||
return 0;
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
// TODO(bunnei): ImplementMe
|
||||
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
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) {
|
||||
auto itr = g_archive_map.find(id_code);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
ResultCode CloseArchive(FileSys::Archive::IdCode id_code) {
|
||||
auto itr = g_archive_map.find(id_code);
|
||||
if (itr == g_archive_map.end()) {
|
||||
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);
|
||||
return 0;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts an archive
|
||||
* @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();
|
||||
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);
|
||||
return -1;
|
||||
return archive_handle.Code();
|
||||
}
|
||||
g_archive_map[id_code] = archive->GetHandle();
|
||||
INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str());
|
||||
return 0;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) {
|
||||
Archive* archive = new Archive;
|
||||
handle = Kernel::g_object_pool.Create(archive);
|
||||
Handle handle = Kernel::g_object_pool.Create(archive);
|
||||
archive->name = name;
|
||||
archive->backend = backend;
|
||||
|
||||
MountArchive(archive);
|
||||
ResultCode result = MountArchive(archive);
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return archive;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
ResultVal<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
|
||||
// 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.
|
||||
@ -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
|
||||
// normal files from archive file pointers is very likely wrong.
|
||||
// See https://github.com/citra-emu/citra/issues/205
|
||||
return archive_handle;
|
||||
return MakeResult<Handle>(archive_handle);
|
||||
|
||||
File* file = new 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->backend = archive->backend->OpenFile(path, mode);
|
||||
|
||||
if (!file->backend)
|
||||
return 0;
|
||||
if (!file->backend) {
|
||||
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
|
||||
* @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;
|
||||
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->backend = archive->backend->OpenDirectory(path);
|
||||
|
||||
return handle;
|
||||
return MakeResult<Handle>(handle);
|
||||
}
|
||||
|
||||
/// Initialize archives
|
||||
|
@ -6,8 +6,9 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/file_sys/archive.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Kernel namespace
|
||||
@ -17,33 +18,31 @@ namespace Kernel {
|
||||
/**
|
||||
* Opens an archive
|
||||
* @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
|
||||
* @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
|
||||
* @param backend File system backend interface to the archive
|
||||
* @param name Optional name of Archive
|
||||
* @return Handle to newly created Archive object
|
||||
* @param name Name of Archive
|
||||
*/
|
||||
Handle CreateArchive(FileSys::Archive* backend, const std::string& name);
|
||||
ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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
|
||||
@ -73,9 +72,9 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa
|
||||
* Open a Directory from an Archive
|
||||
* @param archive_handle Handle to an open Archive object
|
||||
* @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
|
||||
void ArchiveInit();
|
||||
|
@ -30,13 +30,8 @@ public:
|
||||
std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
|
||||
std::string name; ///< Name of event (optional)
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
*wait = locked;
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
bool wait = locked;
|
||||
if (locked) {
|
||||
Handle thread = GetCurrentThreadHandle();
|
||||
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) {
|
||||
locked = true;
|
||||
}
|
||||
return 0;
|
||||
return MakeResult<bool>(wait);
|
||||
}
|
||||
};
|
||||
|
||||
@ -57,12 +52,12 @@ public:
|
||||
* @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) {
|
||||
Event* evt = g_object_pool.GetFast<Event>(handle);
|
||||
_assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
|
||||
ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
|
||||
Event* evt = g_object_pool.Get<Event>(handle);
|
||||
if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
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
|
||||
* @return Result of operation, 0 on success, otherwise error code
|
||||
*/
|
||||
Result SetEventLocked(const Handle handle, const bool locked) {
|
||||
Event* evt = g_object_pool.GetFast<Event>(handle);
|
||||
_assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
|
||||
ResultCode SetEventLocked(const Handle handle, const bool locked) {
|
||||
Event* evt = g_object_pool.Get<Event>(handle);
|
||||
if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
if (!evt->permanent_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
|
||||
* @return Result of operation, 0 on success, otherwise error code
|
||||
*/
|
||||
Result SignalEvent(const Handle handle) {
|
||||
Event* evt = g_object_pool.GetFast<Event>(handle);
|
||||
_assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
|
||||
ResultCode SignalEvent(const Handle handle) {
|
||||
Event* evt = g_object_pool.Get<Event>(handle);
|
||||
if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
// Resume threads waiting for event to signal
|
||||
bool event_caught = false;
|
||||
@ -106,7 +101,7 @@ Result SignalEvent(const Handle handle) {
|
||||
if (!evt->permanent_locked) {
|
||||
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
|
||||
* @return Result of operation, 0 on success, otherwise error code
|
||||
*/
|
||||
Result ClearEvent(Handle handle) {
|
||||
Event* evt = g_object_pool.GetFast<Event>(handle);
|
||||
_assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
|
||||
ResultCode ClearEvent(Handle handle) {
|
||||
Event* evt = g_object_pool.Get<Event>(handle);
|
||||
if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
if (!evt->permanent_locked) {
|
||||
evt->locked = true;
|
||||
}
|
||||
return 0;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,31 +15,27 @@ namespace Kernel {
|
||||
* Changes whether an event is locked or not
|
||||
* @param handle Handle to event to change
|
||||
* @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
|
||||
* @param handle Handle to event to change
|
||||
* @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
|
||||
* @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
|
||||
* @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
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include "common/common.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
typedef u32 Handle;
|
||||
typedef s32 Result;
|
||||
@ -52,21 +53,19 @@ public:
|
||||
virtual Kernel::HandleType GetHandleType() const = 0;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Synchronize kernel object.
|
||||
* @return True if the current thread should wait as a result of the sync
|
||||
*/
|
||||
virtual Result SyncRequest(bool* wait) {
|
||||
virtual ResultVal<bool> SyncRequest() {
|
||||
ERROR_LOG(KERNEL, "(UNIMPLEMENTED)");
|
||||
return -1;
|
||||
return UnimplementedFunction(ErrorModule::Kernel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Wait for kernel object to synchronize.
|
||||
* @return True if the current thread should wait as a result of the wait
|
||||
*/
|
||||
virtual Result WaitSynchronization(bool* wait) = 0;
|
||||
virtual ResultVal<bool> WaitSynchronization() = 0;
|
||||
};
|
||||
|
||||
class ObjectPool : NonCopyable {
|
||||
@ -80,38 +79,29 @@ public:
|
||||
static Object* CreateByIDType(int type);
|
||||
|
||||
template <class T>
|
||||
u32 Destroy(Handle handle) {
|
||||
u32 error;
|
||||
if (Get<T>(handle, error)) {
|
||||
void Destroy(Handle handle) {
|
||||
if (Get<T>(handle)) {
|
||||
occupied[handle - HANDLE_OFFSET] = false;
|
||||
delete pool[handle - HANDLE_OFFSET];
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
bool IsValid(Handle handle);
|
||||
|
||||
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]) {
|
||||
// Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP
|
||||
if (handle != 0 && (u32)handle != 0x80020001) {
|
||||
if (handle != 0) {
|
||||
WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
|
||||
}
|
||||
outError = 0;//T::GetMissingErrorCode();
|
||||
return 0;
|
||||
return nullptr;
|
||||
} else {
|
||||
// Previously we had a dynamic_cast here, but since RTTI was disabled traditionally,
|
||||
// it just acted as a static case and everything worked. This means that we will never
|
||||
// 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()) {
|
||||
Object* t = pool[handle - HANDLE_OFFSET];
|
||||
if (t->GetHandleType() != T::GetStaticHandleType()) {
|
||||
WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
|
||||
outError = 0;//T::GetMissingErrorCode();
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
outError = 0;//SCE_KERNEL_ERROR_OK;
|
||||
return t;
|
||||
return static_cast<T*>(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,31 +27,20 @@ public:
|
||||
std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
|
||||
std::string name; ///< Name of mutex (optional)
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> SyncRequest() override {
|
||||
// TODO(bunnei): ImplementMe
|
||||
locked = true;
|
||||
return 0;
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
// TODO(bunnei): ImplementMe
|
||||
*wait = locked;
|
||||
|
||||
bool wait = locked;
|
||||
if (locked) {
|
||||
Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
|
||||
}
|
||||
|
||||
return 0;
|
||||
return MakeResult<bool>(wait);
|
||||
}
|
||||
};
|
||||
|
||||
@ -119,15 +108,17 @@ bool ReleaseMutex(Mutex* mutex) {
|
||||
* Releases a mutex
|
||||
* @param handle Handle to mutex to release
|
||||
*/
|
||||
Result ReleaseMutex(Handle handle) {
|
||||
Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
|
||||
|
||||
_assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
|
||||
ResultCode ReleaseMutex(Handle handle) {
|
||||
Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle);
|
||||
if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
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
|
||||
* @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
|
||||
|
@ -16,15 +16,10 @@ public:
|
||||
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; }
|
||||
Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; }
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
// TODO(bunnei): ImplementMe
|
||||
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
|
||||
return 0;
|
||||
return UnimplementedFunction(ErrorModule::OS);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 handle;
|
||||
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)
|
||||
* @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) {
|
||||
|
||||
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!",
|
||||
handle, address);
|
||||
return -1;
|
||||
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle);
|
||||
_assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle);
|
||||
SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
|
||||
if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
shared_memory->base_address = address;
|
||||
shared_memory->permissions = permissions;
|
||||
shared_memory->other_permissions = other_permissions;
|
||||
|
||||
return 0;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pointer to the shared memory block
|
||||
* @param handle Shared memory block handle
|
||||
* @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);
|
||||
ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) {
|
||||
SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
|
||||
if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
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);
|
||||
return nullptr;
|
||||
// TODO(yuriks): Verify error code.
|
||||
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
} // 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 permissions Memory block map 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);
|
||||
|
||||
/**
|
||||
@ -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
|
||||
* @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
|
||||
|
@ -11,10 +11,11 @@
|
||||
#include "common/thread_queue_list.h"
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/mem_map.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/mem_map.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@ -33,21 +34,17 @@ public:
|
||||
inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
|
||||
inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
if (status != THREADSTATUS_DORMANT) {
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
const bool wait = status != THREADSTATUS_DORMANT;
|
||||
if (wait) {
|
||||
Handle thread = GetCurrentThreadHandle();
|
||||
if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
|
||||
waiting_threads.push_back(thread);
|
||||
}
|
||||
WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
|
||||
*wait = true;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return MakeResult<bool>(wait);
|
||||
}
|
||||
|
||||
ThreadContext context;
|
||||
@ -144,27 +141,22 @@ void ChangeReadyState(Thread* t, bool ready) {
|
||||
}
|
||||
|
||||
/// Verify that a thread has not been released from waiting
|
||||
inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) {
|
||||
Thread* thread = g_object_pool.GetFast<Thread>(handle);
|
||||
_assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
|
||||
|
||||
if (type != thread->wait_type || wait_handle != thread->wait_handle)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
|
||||
_dbg_assert_(KERNEL, thread != nullptr);
|
||||
return type == thread->wait_type && wait_handle == thread->wait_handle;
|
||||
}
|
||||
|
||||
/// Stops the current thread
|
||||
void StopThread(Handle handle, const char* reason) {
|
||||
Thread* thread = g_object_pool.GetFast<Thread>(handle);
|
||||
_assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
|
||||
ResultCode StopThread(Handle handle, const char* reason) {
|
||||
Thread* thread = g_object_pool.Get<Thread>(handle);
|
||||
if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
ChangeReadyState(thread, false);
|
||||
thread->status = THREADSTATUS_DORMANT;
|
||||
for (size_t i = 0; i < thread->waiting_threads.size(); ++i) {
|
||||
const Handle waiting_thread = thread->waiting_threads[i];
|
||||
for (Handle waiting_handle : thread->waiting_threads) {
|
||||
Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle);
|
||||
if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
|
||||
ResumeThreadFromWait(waiting_thread);
|
||||
ResumeThreadFromWait(waiting_handle);
|
||||
}
|
||||
}
|
||||
thread->waiting_threads.clear();
|
||||
@ -172,6 +164,8 @@ void StopThread(Handle handle, const char* reason) {
|
||||
// Stopped threads are never waiting.
|
||||
thread->wait_type = WAITTYPE_NONE;
|
||||
thread->wait_handle = 0;
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/// Changes a threads state
|
||||
@ -195,13 +189,15 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
|
||||
s32 priority = THREADPRIO_LOWEST;
|
||||
|
||||
// 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...
|
||||
if (!VerifyWait(handle, WAITTYPE_ARB, arbiter))
|
||||
if (!VerifyWait(thread, WAITTYPE_ARB, arbiter))
|
||||
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) {
|
||||
highest_priority_thread = handle;
|
||||
priority = thread->current_priority;
|
||||
@ -218,10 +214,11 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
|
||||
void ArbitrateAllThreads(u32 arbiter, u32 address) {
|
||||
|
||||
// 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...
|
||||
if (VerifyWait(handle, WAITTYPE_ARB, arbiter))
|
||||
if (VerifyWait(thread, WAITTYPE_ARB, arbiter))
|
||||
ResumeThreadFromWait(handle);
|
||||
}
|
||||
}
|
||||
@ -272,7 +269,7 @@ Thread* NextThread() {
|
||||
if (next == 0) {
|
||||
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"
|
||||
void ResumeThreadFromWait(Handle handle) {
|
||||
u32 error;
|
||||
Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
|
||||
Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
|
||||
if (thread) {
|
||||
thread->status &= ~THREADSTATUS_WAIT;
|
||||
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
|
||||
u32 GetThreadPriority(const Handle handle) {
|
||||
Thread* thread = g_object_pool.GetFast<Thread>(handle);
|
||||
_assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
|
||||
return thread->current_priority;
|
||||
ResultVal<u32> GetThreadPriority(const Handle handle) {
|
||||
Thread* thread = g_object_pool.Get<Thread>(handle);
|
||||
if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
|
||||
|
||||
return MakeResult<u32>(thread->current_priority);
|
||||
}
|
||||
|
||||
/// Set the priority of the thread specified by handle
|
||||
Result SetThreadPriority(Handle handle, s32 priority) {
|
||||
ResultCode SetThreadPriority(Handle handle, s32 priority) {
|
||||
Thread* thread = nullptr;
|
||||
if (!handle) {
|
||||
thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
|
||||
} 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!");
|
||||
|
||||
@ -417,7 +417,7 @@ Result SetThreadPriority(Handle handle, s32 priority) {
|
||||
thread_ready_queue.push_back(thread->current_priority, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/// Sets up the primary application thread
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
enum ThreadPriority {
|
||||
THREADPRIO_HIGHEST = 0, ///< Highest thread priority
|
||||
@ -55,7 +56,7 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
|
||||
void Reschedule();
|
||||
|
||||
/// 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"
|
||||
void ResumeThreadFromWait(Handle handle);
|
||||
@ -80,10 +81,10 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHa
|
||||
void WaitThread_Synchronization();
|
||||
|
||||
/// 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
|
||||
Result SetThreadPriority(Handle handle, s32 priority);
|
||||
ResultCode SetThreadPriority(Handle handle, s32 priority);
|
||||
|
||||
/// Initialize threading
|
||||
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 "fs_user.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/result.h"
|
||||
#include "core/hle/service/fs_user.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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) {
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
// TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
|
||||
// http://3dbrew.org/wiki/FS:Initialize#Request
|
||||
cmd_buff[1] = 0;
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
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);
|
||||
|
||||
Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode);
|
||||
if (handle) {
|
||||
cmd_buff[1] = 0;
|
||||
cmd_buff[3] = handle;
|
||||
ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode);
|
||||
cmd_buff[1] = handle.Code().raw;
|
||||
if (handle.Succeeded()) {
|
||||
cmd_buff[3] = *handle;
|
||||
} else {
|
||||
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");
|
||||
@ -111,27 +107,27 @@ static void OpenFileDirectly(Service::Interface* self) {
|
||||
|
||||
if (archive_path.GetType() != FileSys::Empty) {
|
||||
ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
|
||||
cmd_buff[1] = -1;
|
||||
cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (!archive_handle) {
|
||||
// TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here?
|
||||
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");
|
||||
// TODO(Link Mauve): Check for the actual error values, this one was just chosen arbitrarily
|
||||
cmd_buff[1] = -1;
|
||||
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);
|
||||
if (handle) {
|
||||
cmd_buff[1] = 0;
|
||||
cmd_buff[3] = handle;
|
||||
ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode);
|
||||
cmd_buff[1] = handle.Code().raw;
|
||||
if (handle.Succeeded()) {
|
||||
cmd_buff[3] = *handle;
|
||||
} else {
|
||||
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");
|
||||
@ -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());
|
||||
|
||||
Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path);
|
||||
if (handle) {
|
||||
cmd_buff[1] = 0;
|
||||
cmd_buff[3] = handle;
|
||||
ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path);
|
||||
cmd_buff[1] = handle.Code().raw;
|
||||
if (handle.Succeeded()) {
|
||||
cmd_buff[3] = *handle;
|
||||
} else {
|
||||
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");
|
||||
@ -282,19 +276,17 @@ static void OpenArchive(Service::Interface* self) {
|
||||
|
||||
if (archive_path.GetType() != FileSys::Empty) {
|
||||
ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
|
||||
cmd_buff[1] = -1;
|
||||
cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
|
||||
return;
|
||||
}
|
||||
|
||||
Handle handle = Kernel::OpenArchive(archive_id);
|
||||
if (handle) {
|
||||
cmd_buff[1] = 0;
|
||||
ResultVal<Handle> handle = Kernel::OpenArchive(archive_id);
|
||||
cmd_buff[1] = handle.Code().raw;
|
||||
if (handle.Succeeded()) {
|
||||
// cmd_buff[2] isn't used according to 3dmoo's implementation.
|
||||
cmd_buff[3] = handle;
|
||||
cmd_buff[3] = *handle;
|
||||
} else {
|
||||
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");
|
||||
|
@ -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
|
||||
static inline u8* GetCommandBuffer(u32 thread_id) {
|
||||
if (0 == g_shared_memory)
|
||||
return nullptr;
|
||||
|
||||
return Kernel::GetSharedMemoryPointer(g_shared_memory,
|
||||
0x800 + (thread_id * sizeof(CommandBuffer)));
|
||||
ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer)));
|
||||
return ptr.ValueOr(nullptr);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
// For each thread there are two FrameBufferUpdate fields
|
||||
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
|
||||
static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
|
||||
return (InterruptRelayQueue*)Kernel::GetSharedMemoryPointer(g_shared_memory,
|
||||
sizeof(InterruptRelayQueue) * thread_id);
|
||||
ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id);
|
||||
return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
static inline PadData* GetPadData() {
|
||||
if (0 == shared_mem)
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0));
|
||||
return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0).ValueOr(nullptr));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,7 +62,7 @@ void Manager::DeleteService(const std::string& port_name) {
|
||||
|
||||
/// Get a Service Interface from its 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
|
||||
|
@ -75,12 +75,7 @@ public:
|
||||
m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> SyncRequest() override {
|
||||
u32* cmd_buff = GetCommandBuffer();
|
||||
auto itr = m_functions.find(cmd_buff[0]);
|
||||
|
||||
@ -91,7 +86,7 @@ public:
|
||||
// TODO(bunnei): Hack - ignore error
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
cmd_buff[1] = 0;
|
||||
return 0;
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
if (itr->second.func == nullptr) {
|
||||
ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
|
||||
@ -100,23 +95,18 @@ public:
|
||||
// TODO(bunnei): Hack - ignore error
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
cmd_buff[1] = 0;
|
||||
return 0;
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
itr->second.func(this);
|
||||
|
||||
return 0; // TODO: Implement return from actual function
|
||||
return MakeResult<bool>(false); // TODO: Implement return from actual function
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
ResultVal<bool> WaitSynchronization() override {
|
||||
// TODO(bunnei): ImplementMe
|
||||
ERROR_LOG(OSHLE, "unimplemented function");
|
||||
return 0;
|
||||
return UnimplementedFunction(ErrorModule::OS);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -35,7 +35,7 @@ static void GetProcSemaphore(Service::Interface* self) {
|
||||
}
|
||||
|
||||
static void GetServiceHandle(Service::Interface* self) {
|
||||
Result res = 0;
|
||||
ResultCode res = RESULT_SUCCESS;
|
||||
u32* cmd_buff = Service::GetCommandBuffer();
|
||||
|
||||
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]);
|
||||
} else {
|
||||
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[] = {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
#include "core/hle/function_wrappers.h"
|
||||
#include "core/hle/result.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
|
||||
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);
|
||||
|
||||
_assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
|
||||
DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str());
|
||||
|
||||
bool wait = false;
|
||||
Result res = object->SyncRequest(&wait);
|
||||
if (wait) {
|
||||
ResultVal<bool> wait = object->SyncRequest();
|
||||
if (wait.Succeeded() && *wait) {
|
||||
Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
|
||||
}
|
||||
|
||||
return res;
|
||||
return wait.Code().raw;
|
||||
}
|
||||
|
||||
/// Close a handle
|
||||
@ -110,25 +115,25 @@ static Result CloseHandle(Handle handle) {
|
||||
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
|
||||
static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
|
||||
// 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
|
||||
|
||||
if (!Kernel::g_object_pool.IsValid(handle)) {
|
||||
return InvalidHandle(ErrorModule::Kernel).raw;
|
||||
}
|
||||
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(),
|
||||
object->GetName().c_str(), nano_seconds);
|
||||
|
||||
_assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
|
||||
|
||||
Result res = object->WaitSynchronization(&wait);
|
||||
ResultVal<bool> wait = object->WaitSynchronization();
|
||||
|
||||
// Check for next thread to schedule
|
||||
if (wait) {
|
||||
if (wait.Succeeded() && *wait) {
|
||||
HLE::Reschedule(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
return wait.Code().raw;
|
||||
}
|
||||
|
||||
/// 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
|
||||
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]);
|
||||
|
||||
_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(),
|
||||
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) {
|
||||
*out = i;
|
||||
return 0;
|
||||
return RESULT_SUCCESS.raw;
|
||||
} else {
|
||||
unlock_all = false;
|
||||
}
|
||||
@ -164,13 +170,13 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
|
||||
|
||||
if (wait_all && unlock_all) {
|
||||
*out = handle_count;
|
||||
return 0;
|
||||
return RESULT_SUCCESS.raw;
|
||||
}
|
||||
|
||||
// Check for next thread to schedule
|
||||
HLE::Reschedule(__func__);
|
||||
|
||||
return 0;
|
||||
return RESULT_SUCCESS.raw;
|
||||
}
|
||||
|
||||
/// Create an address arbiter (to allocate access to shared resources)
|
||||
@ -183,8 +189,8 @@ static Result CreateAddressArbiter(u32* arbiter) {
|
||||
|
||||
/// Arbitrate address
|
||||
static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) {
|
||||
return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), address,
|
||||
value);
|
||||
return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type),
|
||||
address, value).raw;
|
||||
}
|
||||
|
||||
/// 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
|
||||
static Result GetThreadPriority(s32* priority, Handle handle) {
|
||||
*priority = Kernel::GetThreadPriority(handle);
|
||||
return 0;
|
||||
ResultVal<u32> priority_result = Kernel::GetThreadPriority(handle);
|
||||
if (priority_result.Succeeded()) {
|
||||
*priority = *priority_result;
|
||||
}
|
||||
return priority_result.Code().raw;
|
||||
}
|
||||
|
||||
/// Sets the priority for the specified thread
|
||||
static Result SetThreadPriority(Handle handle, s32 priority) {
|
||||
return Kernel::SetThreadPriority(handle, priority);
|
||||
return Kernel::SetThreadPriority(handle, priority).raw;
|
||||
}
|
||||
|
||||
/// Create a mutex
|
||||
@ -266,9 +275,8 @@ static Result CreateMutex(Handle* mutex, u32 initial_locked) {
|
||||
/// Release a mutex
|
||||
static Result ReleaseMutex(Handle handle) {
|
||||
DEBUG_LOG(SVC, "called handle=0x%08X", handle);
|
||||
_assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!");
|
||||
Kernel::ReleaseMutex(handle);
|
||||
return 0;
|
||||
ResultCode res = Kernel::ReleaseMutex(handle);
|
||||
return res.raw;
|
||||
}
|
||||
|
||||
/// Get current thread ID
|
||||
@ -310,16 +318,14 @@ static Result DuplicateHandle(Handle* out, Handle handle) {
|
||||
|
||||
/// Signals an event
|
||||
static Result SignalEvent(Handle evt) {
|
||||
Result res = Kernel::SignalEvent(evt);
|
||||
DEBUG_LOG(SVC, "called event=0x%08X", evt);
|
||||
return res;
|
||||
return Kernel::SignalEvent(evt).raw;
|
||||
}
|
||||
|
||||
/// Clears an event
|
||||
static Result ClearEvent(Handle evt) {
|
||||
Result res = Kernel::ClearEvent(evt);
|
||||
DEBUG_LOG(SVC, "called event=0x%08X", evt);
|
||||
return res;
|
||||
return Kernel::ClearEvent(evt).raw;
|
||||
}
|
||||
|
||||
/// Sleep the current thread
|
||||
|
Loading…
Reference in New Issue
Block a user