@@ -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);
 | 
			
		||||
 | 
			
		||||
    return archive;
 | 
			
		||||
    ResultCode result = MountArchive(archive);
 | 
			
		||||
    if (result.IsError()) {
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user