diff options
| -rw-r--r-- | src/core/hle/svc.cpp | 1370 | 
1 files changed, 185 insertions, 1185 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index e4b803046..c0481ea6f 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -2,35 +2,15 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. -#include <algorithm> -#include <cinttypes> -#include <map>  #include "common/logging/log.h"  #include "common/microprofile.h" -#include "common/scope_exit.h" -#include "common/string_util.h" -#include "core/arm/arm_interface.h"  #include "core/core_timing.h"  #include "core/hle/function_wrappers.h" -#include "core/hle/kernel/address_arbiter.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/errors.h" -#include "core/hle/kernel/event.h"  #include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/memory.h" -#include "core/hle/kernel/mutex.h"  #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" -#include "core/hle/kernel/semaphore.h" -#include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" -#include "core/hle/kernel/shared_memory.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/kernel/timer.h" -#include "core/hle/kernel/vm_manager.h" -#include "core/hle/kernel/wait_object.h" +#include "core/hle/lock.h"  #include "core/hle/result.h"  #include "core/hle/service/service.h" @@ -43,174 +23,22 @@ using Kernel::SharedPtr;  namespace SVC { -enum ControlMemoryOperation { -    MEMOP_FREE = 1, -    MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel -    MEMOP_COMMIT = 3, -    MEMOP_MAP = 4, -    MEMOP_UNMAP = 5, -    MEMOP_PROTECT = 6, -    MEMOP_OPERATION_MASK = 0xFF, - -    MEMOP_REGION_APP = 0x100, -    MEMOP_REGION_SYSTEM = 0x200, -    MEMOP_REGION_BASE = 0x300, -    MEMOP_REGION_MASK = 0xF00, - -    MEMOP_LINEAR = 0x10000, -}; - -/// Map application or GSP heap memory -static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, -                                u32 permissions) { -    using namespace Kernel; - -    LOG_DEBUG(Kernel_SVC, -              "called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X", -              operation, addr0, addr1, size, permissions); - -    if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) { -        return ERR_MISALIGNED_ADDRESS; -    } -    if ((size & Memory::PAGE_MASK) != 0) { -        return ERR_MISALIGNED_SIZE; -    } - -    u32 region = operation & MEMOP_REGION_MASK; -    operation &= ~MEMOP_REGION_MASK; - -    if (region != 0) { -        LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X", -                    region); -    } - -    if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) { -        return ERR_INVALID_COMBINATION; -    } -    VMAPermission vma_permissions = (VMAPermission)permissions; - -    auto& process = *g_current_process; - -    switch (operation & MEMOP_OPERATION_MASK) { -    case MEMOP_FREE: { -        // TODO(Subv): What happens if an application tries to FREE a block of memory that has a -        // SharedMemory pointing to it? -        if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { -            ResultCode result = process.HeapFree(addr0, size); -            if (result.IsError()) -                return result; -        } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) { -            ResultCode result = process.LinearFree(addr0, size); -            if (result.IsError()) -                return result; -        } else { -            return ERR_INVALID_ADDRESS; -        } -        *out_addr = addr0; -        break; -    } - -    case MEMOP_COMMIT: { -        if (operation & MEMOP_LINEAR) { -            CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions)); -        } else { -            CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); -        } -        break; -    } - -    case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is -                    // implemented -        { -            CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); -            break; -        } - -    case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is -                      // implemented -        { -            ResultCode result = process.HeapFree(addr0, size); -            if (result.IsError()) -                return result; -            break; -        } - -    case MEMOP_PROTECT: { -        ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions); -        if (result.IsError()) -            return result; -        break; -    } - -    default: -        LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); -        return ERR_INVALID_COMBINATION; -    } - -    process.vm_manager.LogLayout(Log::Level::Trace); - -    return RESULT_SUCCESS; -} - -/// Maps a memory block to specified address -static ResultCode MapMemoryBlock(Kernel::Handle handle, u32 addr, u32 permissions, -                                 u32 other_permissions) { -    using Kernel::SharedMemory; -    using Kernel::MemoryPermission; - -    LOG_TRACE(Kernel_SVC, -              "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", -              handle, addr, permissions, other_permissions); - -    SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); -    if (shared_memory == nullptr) -        return ERR_INVALID_HANDLE; - -    MemoryPermission permissions_type = static_cast<MemoryPermission>(permissions); -    switch (permissions_type) { -    case MemoryPermission::Read: -    case MemoryPermission::Write: -    case MemoryPermission::ReadWrite: -    case MemoryPermission::Execute: -    case MemoryPermission::ReadExecute: -    case MemoryPermission::WriteExecute: -    case MemoryPermission::ReadWriteExecute: -    case MemoryPermission::DontCare: -        return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type, -                                  static_cast<MemoryPermission>(other_permissions)); -    default: -        LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); -    } - -    return Kernel::ERR_INVALID_COMBINATION; -} - -static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) { -    using Kernel::SharedMemory; - -    LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X", handle, addr); - -    // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap - -    SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); -    if (shared_memory == nullptr) -        return ERR_INVALID_HANDLE; - -    return shared_memory->Unmap(Kernel::g_current_process.get(), addr); -} -  /// Connect to an OS service given the port name, returns the handle to the port to out -static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) { -    if (port_name == nullptr) +static ResultCode ConnectToPort(Kernel::Handle* out_handle, VAddr port_name_address) { +    if (!Memory::IsValidVirtualAddress(port_name_address))          return Kernel::ERR_NOT_FOUND; -    if (std::strlen(port_name) > 11) + +    static constexpr std::size_t PortNameMaxLength = 11; +    // Read 1 char beyond the max allowed port name to detect names that are too long. +    std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); +    if (port_name.size() > PortNameMaxLength)          return Kernel::ERR_PORT_NAME_TOO_LONG; -    LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name); +    LOG_INFO(Kernel_SVC, "called port_name=%s", port_name.c_str());      auto it = Service::g_kernel_named_ports.find(port_name);      if (it == Service::g_kernel_named_ports.end()) { -        LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name); +        LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: %s", port_name.c_str());          return Kernel::ERR_NOT_FOUND;      } @@ -229,6 +57,7 @@ static ResultCode SendSyncRequest(Kernel::Handle handle) {      SharedPtr<Kernel::ClientSession> session =          Kernel::g_handle_table.Get<Kernel::ClientSession>(handle);      if (session == nullptr) { +        LOG_ERROR(Kernel_SVC, "called with invalid handle=0x%08X", handle);          return ERR_INVALID_HANDLE;      } @@ -241,586 +70,43 @@ static ResultCode SendSyncRequest(Kernel::Handle handle) {      return session->SendSyncRequest(Kernel::GetCurrentThread());  } -/// Close a handle -static ResultCode CloseHandle(Kernel::Handle handle) { -    LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle); -    return Kernel::g_handle_table.Close(handle); +/// Break program execution +static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { +    LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); +    ASSERT(false);  } -/// Wait for a handle to synchronize, timeout after the specified nanoseconds -static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) { -    auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handle); -    Kernel::Thread* thread = Kernel::GetCurrentThread(); - -    if (object == nullptr) -        return ERR_INVALID_HANDLE; - -    LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, -              object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); - -    if (object->ShouldWait(thread)) { - -        if (nano_seconds == 0) -            return Kernel::RESULT_TIMEOUT; - -        thread->wait_objects = {object}; -        object->AddWaitingThread(thread); -        thread->status = THREADSTATUS_WAIT_SYNCH_ANY; - -        // Create an event to wake the thread up after the specified nanosecond delay has passed -        thread->WakeAfterDelay(nano_seconds); - -        Core::System::GetInstance().PrepareReschedule(); - -        // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread -        // resumes due to a signal in its wait objects. -        // Otherwise we retain the default value of timeout. -        return Kernel::RESULT_TIMEOUT; -    } - -    object->Acquire(thread); - -    return RESULT_SUCCESS; +/// Used to output a message on a debug hardware unit - does nothing on a retail unit +static void OutputDebugString(VAddr address, int len) { +    std::vector<char> string(len); +    Memory::ReadBlock(address, string.data(), len); +    LOG_DEBUG(Debug_Emulated, "%.*s", len, string.data());  } -/// Wait for the given handles to synchronize, timeout after the specified nanoseconds -static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 handle_count, -                                       bool wait_all, s64 nano_seconds) { -    Kernel::Thread* thread = Kernel::GetCurrentThread(); - -    // Check if 'handles' is invalid -    if (handles == nullptr) -        return Kernel::ERR_INVALID_POINTER; - -    // NOTE: on real hardware, there is no nullptr check for 'out' (tested with firmware 4.4). If -    // this happens, the running application will crash. -    ASSERT_MSG(out != nullptr, "invalid output pointer specified!"); +static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) { +    LOG_INFO(Kernel_SVC, "called, info_id=0x%X, info_sub_id=0x%X, handle=0x%08X", info_id, info_sub_id, handle); -    // Check if 'handle_count' is invalid -    if (handle_count < 0) -        return Kernel::ERR_OUT_OF_RANGE; - -    using ObjectPtr = Kernel::SharedPtr<Kernel::WaitObject>; -    std::vector<ObjectPtr> objects(handle_count); - -    for (int i = 0; i < handle_count; ++i) { -        auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]); -        if (object == nullptr) -            return ERR_INVALID_HANDLE; -        objects[i] = object; -    } - -    if (wait_all) { -        bool all_available = -            std::all_of(objects.begin(), objects.end(), -                        [thread](const ObjectPtr& object) { return !object->ShouldWait(thread); }); -        if (all_available) { -            // We can acquire all objects right now, do so. -            for (auto& object : objects) -                object->Acquire(thread); -            // Note: In this case, the `out` parameter is not set, -            // and retains whatever value it had before. -            return RESULT_SUCCESS; -        } - -        // Not all objects were available right now, prepare to suspend the thread. - -        // If a timeout value of 0 was provided, just return the Timeout error code instead of -        // suspending the thread. -        if (nano_seconds == 0) -            return Kernel::RESULT_TIMEOUT; - -        // Put the thread to sleep -        thread->status = THREADSTATUS_WAIT_SYNCH_ALL; - -        // Add the thread to each of the objects' waiting threads. -        for (auto& object : objects) { -            object->AddWaitingThread(thread); -        } - -        thread->wait_objects = std::move(objects); - -        // Create an event to wake the thread up after the specified nanosecond delay has passed -        thread->WakeAfterDelay(nano_seconds); - -        Core::System::GetInstance().PrepareReschedule(); - -        // This value gets set to -1 by default in this case, it is not modified after this. -        *out = -1; -        // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to -        // a signal in one of its wait objects. -        return Kernel::RESULT_TIMEOUT; -    } else { -        // Find the first object that is acquirable in the provided list of objects -        auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { -            return !object->ShouldWait(thread); -        }); - -        if (itr != objects.end()) { -            // We found a ready object, acquire it and set the result value -            Kernel::WaitObject* object = itr->get(); -            object->Acquire(thread); -            *out = std::distance(objects.begin(), itr); +    if (!handle) { +        switch (info_id) { +        case 0xB: +            *result = 0; // Used for PRNG seed              return RESULT_SUCCESS;          } - -        // No objects were ready to be acquired, prepare to suspend the thread. - -        // If a timeout value of 0 was provided, just return the Timeout error code instead of -        // suspending the thread. -        if (nano_seconds == 0) -            return Kernel::RESULT_TIMEOUT; - -        // Put the thread to sleep -        thread->status = THREADSTATUS_WAIT_SYNCH_ANY; - -        // Add the thread to each of the objects' waiting threads. -        for (size_t i = 0; i < objects.size(); ++i) { -            Kernel::WaitObject* object = objects[i].get(); -            object->AddWaitingThread(thread); -        } - -        thread->wait_objects = std::move(objects); - -        // Note: If no handles and no timeout were given, then the thread will deadlock, this is -        // consistent with hardware behavior. - -        // Create an event to wake the thread up after the specified nanosecond delay has passed -        thread->WakeAfterDelay(nano_seconds); - -        Core::System::GetInstance().PrepareReschedule(); - -        // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a -        // signal in one of its wait objects. -        // Otherwise we retain the default value of timeout, and -1 in the out parameter -        thread->wait_set_output = true; -        *out = -1; -        return Kernel::RESULT_TIMEOUT; -    } -} - -/// In a single operation, sends a IPC reply and waits for a new request. -static ResultCode ReplyAndReceive(s32* index, Kernel::Handle* handles, s32 handle_count, -                                  Kernel::Handle reply_target) { -    // 'handles' has to be a valid pointer even if 'handle_count' is 0. -    if (handles == nullptr) -        return Kernel::ERR_INVALID_POINTER; - -    // Check if 'handle_count' is invalid -    if (handle_count < 0) -        return Kernel::ERR_OUT_OF_RANGE; - -    using ObjectPtr = SharedPtr<Kernel::WaitObject>; -    std::vector<ObjectPtr> objects(handle_count); - -    for (int i = 0; i < handle_count; ++i) { -        auto object = Kernel::g_handle_table.Get<Kernel::WaitObject>(handles[i]); -        if (object == nullptr) -            return ERR_INVALID_HANDLE; -        objects[i] = object; -    } - -    // We are also sending a command reply. -    // Do not send a reply if the command id in the command buffer is 0xFFFF. -    u32* cmd_buff = Kernel::GetCommandBuffer(); -    IPC::Header header{cmd_buff[0]}; -    if (reply_target != 0 && header.command_id != 0xFFFF) { -        auto session = Kernel::g_handle_table.Get<Kernel::ServerSession>(reply_target); -        if (session == nullptr) -            return ERR_INVALID_HANDLE; - -        auto request_thread = std::move(session->currently_handling); - -        // Mark the request as "handled". -        session->currently_handling = nullptr; - -        // Error out if there's no request thread or the session was closed. -        // TODO(Subv): Is the same error code (ClosedByRemote) returned for both of these cases? -        if (request_thread == nullptr || session->parent->client == nullptr) { -            *index = -1; -            return Kernel::ERR_SESSION_CLOSED_BY_REMOTE; -        } - -        // TODO(Subv): Perform IPC translation from the current thread to request_thread. - -        // Note: The scheduler is not invoked here. -        request_thread->ResumeFromWait(); -    } - -    if (handle_count == 0) { -        *index = 0; -        // The kernel uses this value as a placeholder for the real error, and returns it when we -        // pass no handles and do not perform any reply. -        if (reply_target == 0 || header.command_id == 0xFFFF) -            return ResultCode(0xE7E3FFFF); - -        return RESULT_SUCCESS; -    } - -    auto thread = Kernel::GetCurrentThread(); - -    // Find the first object that is acquirable in the provided list of objects -    auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { -        return !object->ShouldWait(thread); -    }); - -    if (itr != objects.end()) { -        // We found a ready object, acquire it and set the result value -        Kernel::WaitObject* object = itr->get(); -        object->Acquire(thread); -        *index = std::distance(objects.begin(), itr); - -        if (object->GetHandleType() == Kernel::HandleType::ServerSession) { -            auto server_session = static_cast<Kernel::ServerSession*>(object); -            if (server_session->parent->client == nullptr) -                return Kernel::ERR_SESSION_CLOSED_BY_REMOTE; - -            // TODO(Subv): Perform IPC translation from the ServerSession to the current thread. -        } -        return RESULT_SUCCESS; -    } - -    // No objects were ready to be acquired, prepare to suspend the thread. - -    // TODO(Subv): Perform IPC translation upon wakeup. - -    // Put the thread to sleep -    thread->status = THREADSTATUS_WAIT_SYNCH_ANY; - -    // Add the thread to each of the objects' waiting threads. -    for (size_t i = 0; i < objects.size(); ++i) { -        Kernel::WaitObject* object = objects[i].get(); -        object->AddWaitingThread(thread); -    } - -    thread->wait_objects = std::move(objects); - -    Core::System::GetInstance().PrepareReschedule(); - -    // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a -    // signal in one of its wait objects, or to 0xC8A01836 if there was a translation error. -    // By default the index is set to -1. -    thread->wait_set_output = true; -    *index = -1; -    return RESULT_SUCCESS; -} - -/// Create an address arbiter (to allocate access to shared resources) -static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) { -    using Kernel::AddressArbiter; - -    SharedPtr<AddressArbiter> arbiter = AddressArbiter::Create(); -    CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(arbiter))); -    LOG_TRACE(Kernel_SVC, "returned handle=0x%08X", *out_handle); -    return RESULT_SUCCESS; -} - -/// Arbitrate address -static ResultCode ArbitrateAddress(Kernel::Handle handle, u32 address, u32 type, u32 value, -                                   s64 nanoseconds) { -    using Kernel::AddressArbiter; - -    LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", handle, -              address, type, value); - -    SharedPtr<AddressArbiter> arbiter = Kernel::g_handle_table.Get<AddressArbiter>(handle); -    if (arbiter == nullptr) -        return ERR_INVALID_HANDLE; - -    auto res = arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type), address, value, -                                         nanoseconds); - -    // TODO(Subv): Identify in which specific cases this call should cause a reschedule. -    Core::System::GetInstance().PrepareReschedule(); - -    return res; -} - -static void Break(u8 break_reason) { -    LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); -    std::string reason_str; -    switch (break_reason) { -    case 0: -        reason_str = "PANIC"; -        break; -    case 1: -        reason_str = "ASSERT"; -        break; -    case 2: -        reason_str = "USER"; -        break; -    default: -        reason_str = "UNKNOWN"; -        break;      } -    LOG_CRITICAL(Debug_Emulated, "Break reason: %s", reason_str.c_str()); -} - -/// Used to output a message on a debug hardware unit - does nothing on a retail unit -static void OutputDebugString(const char* string, int len) { -    LOG_DEBUG(Debug_Emulated, "%.*s", len, string); -} - -/// Get resource limit -static ResultCode GetResourceLimit(Kernel::Handle* resource_limit, Kernel::Handle process_handle) { -    LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); - -    SharedPtr<Kernel::Process> process = -        Kernel::g_handle_table.Get<Kernel::Process>(process_handle); -    if (process == nullptr) -        return ERR_INVALID_HANDLE; - -    CASCADE_RESULT(*resource_limit, Kernel::g_handle_table.Create(process->resource_limit)); - -    return RESULT_SUCCESS; -} - -/// Get resource limit current values -static ResultCode GetResourceLimitCurrentValues(s64* values, Kernel::Handle resource_limit_handle, -                                                u32* names, u32 name_count) { -    LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", -              resource_limit_handle, names, name_count); - -    SharedPtr<Kernel::ResourceLimit> resource_limit = -        Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle); -    if (resource_limit == nullptr) -        return ERR_INVALID_HANDLE; - -    for (unsigned int i = 0; i < name_count; ++i) -        values[i] = resource_limit->GetCurrentResourceValue(names[i]); - -    return RESULT_SUCCESS; -} - -/// Get resource limit max values -static ResultCode GetResourceLimitLimitValues(s64* values, Kernel::Handle resource_limit_handle, -                                              u32* names, u32 name_count) { -    LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", -              resource_limit_handle, names, name_count); - -    SharedPtr<Kernel::ResourceLimit> resource_limit = -        Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle); -    if (resource_limit == nullptr) -        return ERR_INVALID_HANDLE; - -    for (unsigned int i = 0; i < name_count; ++i) -        values[i] = resource_limit->GetMaxResourceValue(names[i]); -      return RESULT_SUCCESS;  } -/// Creates a new thread -static ResultCode CreateThread(Kernel::Handle* out_handle, u32 priority, u32 entry_point, u32 arg, -                               u32 stack_top, s32 processor_id) { -    using Kernel::Thread; - -    std::string name = Common::StringFromFormat("unknown-%08" PRIX32, entry_point); - -    if (priority > THREADPRIO_LOWEST) { -        return Kernel::ERR_OUT_OF_RANGE; -    } - -    using Kernel::ResourceLimit; -    Kernel::SharedPtr<ResourceLimit>& resource_limit = Kernel::g_current_process->resource_limit; -    if (resource_limit->GetMaxResourceValue(Kernel::ResourceTypes::PRIORITY) > priority) { -        return Kernel::ERR_NOT_AUTHORIZED; -    } - -    switch (processor_id) { -    case THREADPROCESSORID_ALL: -    case THREADPROCESSORID_DEFAULT: -    case THREADPROCESSORID_0: -    case THREADPROCESSORID_1: -        break; -    default: -        // TODO(bunnei): Implement support for other processor IDs -        ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id); -        break; -    } - -    if (processor_id == THREADPROCESSORID_ALL) { -        LOG_INFO(Kernel_SVC, -                 "Newly created thread is allowed to be run in any Core, unimplemented."); -    } - -    if (processor_id == THREADPROCESSORID_DEFAULT && -        Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1) { -        LOG_WARNING( -            Kernel_SVC, -            "Newly created thread is allowed to be run in the SysCore (Core1), unimplemented."); -    } - -    if (processor_id == THREADPROCESSORID_1) { -        LOG_ERROR(Kernel_SVC, -                  "Newly created thread must run in the SysCore (Core1), unimplemented."); -    } - -    CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(name, entry_point, priority, -                                                                    arg, processor_id, stack_top)); - -    thread->context.fpscr = -        FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 - -    CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread))); - -    Core::System::GetInstance().PrepareReschedule(); - -    LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " -                          "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", -              entry_point, name.c_str(), arg, stack_top, priority, processor_id, *out_handle); - -    return RESULT_SUCCESS; -} - -/// Called when a thread exits -static void ExitThread() { -    LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::CPU().GetPC()); - -    Kernel::ExitCurrentThread(); -    Core::System::GetInstance().PrepareReschedule(); -} -  /// Gets the priority for the specified thread  static ResultCode GetThreadPriority(s32* priority, Kernel::Handle handle) { +    LOG_INFO(Kernel_SVC, "called, handle=0x%08X", handle);      const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); -    if (thread == nullptr) -        return ERR_INVALID_HANDLE; - -    *priority = thread->GetPriority(); -    return RESULT_SUCCESS; -} - -/// Sets the priority for the specified thread -static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) { -    if (priority > THREADPRIO_LOWEST) { -        return Kernel::ERR_OUT_OF_RANGE; -    } - -    SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); -    if (thread == nullptr) -        return ERR_INVALID_HANDLE; - -    using Kernel::ResourceLimit; -    // Note: The kernel uses the current process's resource limit instead of -    // the one from the thread owner's resource limit. -    Kernel::SharedPtr<ResourceLimit>& resource_limit = Kernel::g_current_process->resource_limit; -    if (resource_limit->GetMaxResourceValue(Kernel::ResourceTypes::PRIORITY) > priority) { -        return Kernel::ERR_NOT_AUTHORIZED; -    } - -    thread->SetPriority(priority); -    thread->UpdatePriority(); - -    // Update the mutexes that this thread is waiting for -    for (auto& mutex : thread->pending_mutexes) -        mutex->UpdatePriority(); - -    Core::System::GetInstance().PrepareReschedule(); -    return RESULT_SUCCESS; -} - -/// Create a mutex -static ResultCode CreateMutex(Kernel::Handle* out_handle, u32 initial_locked) { -    using Kernel::Mutex; - -    SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0); -    mutex->name = Common::StringFromFormat("mutex-%08x", Core::CPU().GetReg(14)); -    CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex))); - -    LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", -              initial_locked ? "true" : "false", *out_handle); - -    return RESULT_SUCCESS; -} - -/// Release a mutex -static ResultCode ReleaseMutex(Kernel::Handle handle) { -    using Kernel::Mutex; - -    LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); - -    SharedPtr<Mutex> mutex = Kernel::g_handle_table.Get<Mutex>(handle); -    if (mutex == nullptr) -        return ERR_INVALID_HANDLE; - -    mutex->Release(); - -    return RESULT_SUCCESS; -} - -/// Get the ID of the specified process -static ResultCode GetProcessId(u32* process_id, Kernel::Handle process_handle) { -    LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); - -    const SharedPtr<Kernel::Process> process = -        Kernel::g_handle_table.Get<Kernel::Process>(process_handle); -    if (process == nullptr) -        return ERR_INVALID_HANDLE; - -    *process_id = process->process_id; -    return RESULT_SUCCESS; -} - -/// Get the ID of the process that owns the specified thread -static ResultCode GetProcessIdOfThread(u32* process_id, Kernel::Handle thread_handle) { -    LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); - -    const SharedPtr<Kernel::Thread> thread = -        Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle); -    if (thread == nullptr) -        return ERR_INVALID_HANDLE; - -    const SharedPtr<Kernel::Process> process = thread->owner_process; - -    ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle); - -    *process_id = process->process_id; -    return RESULT_SUCCESS; -} - -/// Get the ID for the specified thread. -static ResultCode GetThreadId(u32* thread_id, Kernel::Handle handle) { -    LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); - -    const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); -    if (thread == nullptr) -        return ERR_INVALID_HANDLE; - -    *thread_id = thread->GetThreadId(); -    return RESULT_SUCCESS; -} - -/// Creates a semaphore -static ResultCode CreateSemaphore(Kernel::Handle* out_handle, s32 initial_count, s32 max_count) { -    using Kernel::Semaphore; - -    CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count)); -    semaphore->name = Common::StringFromFormat("semaphore-%08x", Core::CPU().GetReg(14)); -    CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore))); - -    LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X", -              initial_count, max_count, *out_handle); -    return RESULT_SUCCESS; -} - -/// Releases a certain number of slots in a semaphore -static ResultCode ReleaseSemaphore(s32* count, Kernel::Handle handle, s32 release_count) { -    using Kernel::Semaphore; - -    LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle); - -    SharedPtr<Semaphore> semaphore = Kernel::g_handle_table.Get<Semaphore>(handle); -    if (semaphore == nullptr) -        return ERR_INVALID_HANDLE; - -    CASCADE_RESULT(*count, semaphore->Release(release_count)); - +    *priority = thread ? thread->GetPriority() : 0;      return RESULT_SUCCESS;  }  /// Query process memory -static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, -                                     Kernel::Handle process_handle, u32 addr) { +static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, +                                     Kernel::Handle process_handle, u64 addr) {      using Kernel::Process;      Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);      if (process == nullptr) @@ -829,131 +115,32 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf      auto vma = process->vm_manager.FindVMA(addr);      if (vma == Kernel::g_current_process->vm_manager.vma_map.end()) -        return Kernel::ERR_INVALID_ADDRESS; +    { +        //return Kernel::ERR_INVALID_ADDRESS; + +        memory_info->base_address = 0; +        memory_info->permission = static_cast<u64>(Kernel::VMAPermission::None); +        memory_info->size = 0; +        memory_info->state = static_cast<u64>(Kernel::MemoryState::Free); + +        return RESULT_SUCCESS; +    }      memory_info->base_address = vma->second.base; -    memory_info->permission = static_cast<u32>(vma->second.permissions); +    memory_info->permission = static_cast<u64>(vma->second.permissions);      memory_info->size = vma->second.size; -    memory_info->state = static_cast<u32>(vma->second.meminfo_state); +    memory_info->state = static_cast<u64>(vma->second.meminfo_state); -    page_info->flags = 0; -    LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=0x%08X", process_handle, addr); +    LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=%llx", process_handle, addr);      return RESULT_SUCCESS;  }  /// Query memory -static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) { +static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAddr addr) { +    LOG_INFO(Kernel_SVC, "called, addr=%llx", addr);      return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr);  } -/// Create an event -static ResultCode CreateEvent(Kernel::Handle* out_handle, u32 reset_type) { -    using Kernel::Event; - -    SharedPtr<Event> evt = Event::Create(static_cast<Kernel::ResetType>(reset_type)); -    evt->name = Common::StringFromFormat("event-%08x", Core::CPU().GetReg(14)); -    CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt))); - -    LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type, -              *out_handle); -    return RESULT_SUCCESS; -} - -/// Duplicates a kernel handle -static ResultCode DuplicateHandle(Kernel::Handle* out, Kernel::Handle handle) { -    CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle)); -    LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); -    return RESULT_SUCCESS; -} - -/// Signals an event -static ResultCode SignalEvent(Kernel::Handle handle) { -    using Kernel::Event; -    LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); - -    SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); -    if (evt == nullptr) -        return ERR_INVALID_HANDLE; - -    evt->Signal(); - -    return RESULT_SUCCESS; -} - -/// Clears an event -static ResultCode ClearEvent(Kernel::Handle handle) { -    using Kernel::Event; -    LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle); - -    SharedPtr<Event> evt = Kernel::g_handle_table.Get<Kernel::Event>(handle); -    if (evt == nullptr) -        return ERR_INVALID_HANDLE; - -    evt->Clear(); -    return RESULT_SUCCESS; -} - -/// Creates a timer -static ResultCode CreateTimer(Kernel::Handle* out_handle, u32 reset_type) { -    using Kernel::Timer; - -    SharedPtr<Timer> timer = Timer::Create(static_cast<Kernel::ResetType>(reset_type)); -    timer->name = Common::StringFromFormat("timer-%08x", Core::CPU().GetReg(14)); -    CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer))); - -    LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type, -              *out_handle); -    return RESULT_SUCCESS; -} - -/// Clears a timer -static ResultCode ClearTimer(Kernel::Handle handle) { -    using Kernel::Timer; - -    LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); - -    SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); -    if (timer == nullptr) -        return ERR_INVALID_HANDLE; - -    timer->Clear(); -    return RESULT_SUCCESS; -} - -/// Starts a timer -static ResultCode SetTimer(Kernel::Handle handle, s64 initial, s64 interval) { -    using Kernel::Timer; - -    LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); - -    if (initial < 0 || interval < 0) { -        return Kernel::ERR_OUT_OF_RANGE_KERNEL; -    } - -    SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); -    if (timer == nullptr) -        return ERR_INVALID_HANDLE; - -    timer->Set(initial, interval); - -    return RESULT_SUCCESS; -} - -/// Cancels a timer -static ResultCode CancelTimer(Kernel::Handle handle) { -    using Kernel::Timer; - -    LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle); - -    SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle); -    if (timer == nullptr) -        return ERR_INVALID_HANDLE; - -    timer->Cancel(); - -    return RESULT_SUCCESS; -} -  /// Sleep the current thread  static void SleepThread(s64 nanoseconds) {      LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); @@ -972,212 +159,16 @@ static void SleepThread(s64 nanoseconds) {      Core::System::GetInstance().PrepareReschedule();  } -/// This returns the total CPU ticks elapsed since the CPU was powered-on -static s64 GetSystemTick() { -    s64 result = CoreTiming::GetTicks(); -    // Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end. -    Core::CPU().AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b -    return result; -} - -/// Creates a memory block at the specified address with the specified permissions and size -static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 size, -                                    u32 my_permission, u32 other_permission) { -    using Kernel::SharedMemory; - -    if (size % Memory::PAGE_SIZE != 0) -        return Kernel::ERR_MISALIGNED_SIZE; - -    SharedPtr<SharedMemory> shared_memory = nullptr; - -    using Kernel::MemoryPermission; -    auto VerifyPermissions = [](MemoryPermission permission) { -        // SharedMemory blocks can not be created with Execute permissions -        switch (permission) { -        case MemoryPermission::None: -        case MemoryPermission::Read: -        case MemoryPermission::Write: -        case MemoryPermission::ReadWrite: -        case MemoryPermission::DontCare: -            return true; -        default: -            return false; -        } -    }; - -    if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) || -        !VerifyPermissions(static_cast<MemoryPermission>(other_permission))) -        return Kernel::ERR_INVALID_COMBINATION; - -    // TODO(Subv): Processes with memory type APPLICATION are not allowed -    // to create memory blocks with addr = 0, any attempts to do so -    // should return error 0xD92007EA. -    if ((addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) && -        addr != 0) { -        return Kernel::ERR_INVALID_ADDRESS; -    } - -    // When trying to create a memory block with address = 0, -    // if the process has the Shared Device Memory flag in the exheader, -    // then we have to allocate from the same region as the caller process instead of the BASE -    // region. -    Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE; -    if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem) -        region = Kernel::g_current_process->flags.memory_region; - -    shared_memory = SharedMemory::Create( -        Kernel::g_current_process, size, static_cast<MemoryPermission>(my_permission), -        static_cast<MemoryPermission>(other_permission), addr, region); -    CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); - -    LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr); +/// Signal process wide key +static ResultCode SignalProcessWideKey(VAddr address, u32 target) { +    LOG_INFO(Kernel_SVC, "called, address=0x%llx, target=0x%08x", address, target);      return RESULT_SUCCESS;  } -static ResultCode CreatePort(Kernel::Handle* server_port, Kernel::Handle* client_port, -                             const char* name, u32 max_sessions) { -    // TODO(Subv): Implement named ports. -    ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented"); - -    using Kernel::ServerPort; -    using Kernel::ClientPort; - -    auto ports = ServerPort::CreatePortPair(max_sessions); -    CASCADE_RESULT(*client_port, Kernel::g_handle_table.Create( -                                     std::move(std::get<SharedPtr<ClientPort>>(ports)))); -    // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be -    // created. -    CASCADE_RESULT(*server_port, Kernel::g_handle_table.Create( -                                     std::move(std::get<SharedPtr<ServerPort>>(ports)))); - -    LOG_TRACE(Kernel_SVC, "called max_sessions=%u", max_sessions); -    return RESULT_SUCCESS; -} - -static ResultCode CreateSessionToPort(Handle* out_client_session, Handle client_port_handle) { -    using Kernel::ClientPort; -    SharedPtr<ClientPort> client_port = Kernel::g_handle_table.Get<ClientPort>(client_port_handle); -    if (client_port == nullptr) -        return ERR_INVALID_HANDLE; - -    CASCADE_RESULT(auto session, client_port->Connect()); -    CASCADE_RESULT(*out_client_session, Kernel::g_handle_table.Create(std::move(session))); -    return RESULT_SUCCESS; -} - -static ResultCode CreateSession(Handle* server_session, Handle* client_session) { -    auto sessions = Kernel::ServerSession::CreateSessionPair(); - -    auto& server = std::get<SharedPtr<Kernel::ServerSession>>(sessions); -    CASCADE_RESULT(*server_session, Kernel::g_handle_table.Create(std::move(server))); - -    auto& client = std::get<SharedPtr<Kernel::ClientSession>>(sessions); -    CASCADE_RESULT(*client_session, Kernel::g_handle_table.Create(std::move(client))); - -    LOG_TRACE(Kernel_SVC, "called"); -    return RESULT_SUCCESS; -} - -static ResultCode AcceptSession(Handle* out_server_session, Handle server_port_handle) { -    using Kernel::ServerPort; -    SharedPtr<ServerPort> server_port = Kernel::g_handle_table.Get<ServerPort>(server_port_handle); -    if (server_port == nullptr) -        return ERR_INVALID_HANDLE; - -    CASCADE_RESULT(auto session, server_port->Accept()); -    CASCADE_RESULT(*out_server_session, Kernel::g_handle_table.Create(std::move(session))); -    return RESULT_SUCCESS; -} - -static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { -    using Kernel::MemoryRegion; - -    LOG_TRACE(Kernel_SVC, "called type=%u param=%d", type, param); - -    switch ((SystemInfoType)type) { -    case SystemInfoType::REGION_MEMORY_USAGE: -        switch ((SystemInfoMemUsageRegion)param) { -        case SystemInfoMemUsageRegion::ALL: -            *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used + -                   Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used + -                   Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used; -            break; -        case SystemInfoMemUsageRegion::APPLICATION: -            *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used; -            break; -        case SystemInfoMemUsageRegion::SYSTEM: -            *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used; -            break; -        case SystemInfoMemUsageRegion::BASE: -            *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used; -            break; -        default: -            LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=0 region: param=%d", param); -            *out = 0; -            break; -        } -        break; -    case SystemInfoType::KERNEL_ALLOCATED_PAGES: -        LOG_ERROR(Kernel_SVC, "unimplemented GetSystemInfo type=2 param=%d", param); -        *out = 0; -        break; -    case SystemInfoType::KERNEL_SPAWNED_PIDS: -        *out = 5; -        break; -    default: -        LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=%u param=%d", type, param); -        *out = 0; -        break; -    } - -    // This function never returns an error, even if invalid parameters were passed. -    return RESULT_SUCCESS; -} - -static ResultCode GetProcessInfo(s64* out, Kernel::Handle process_handle, u32 type) { -    LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type); - -    using Kernel::Process; -    Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle); -    if (process == nullptr) -        return ERR_INVALID_HANDLE; - -    switch (type) { -    case 0: -    case 2: -        // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure -        // what's the difference between them. -        *out = process->heap_used + process->linear_heap_used + process->misc_memory_used; -        if (*out % Memory::PAGE_SIZE != 0) { -            LOG_ERROR(Kernel_SVC, "called, memory size not page-aligned"); -            return Kernel::ERR_MISALIGNED_SIZE; -        } -        break; -    case 1: -    case 3: -    case 4: -    case 5: -    case 6: -    case 7: -    case 8: -        // These are valid, but not implemented yet -        LOG_ERROR(Kernel_SVC, "unimplemented GetProcessInfo type=%u", type); -        break; -    case 20: -        *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase(); -        break; -    case 21: -    case 22: -    case 23: -        // These return a different error value than higher invalid values -        LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type); -        return Kernel::ERR_NOT_IMPLEMENTED; -    default: -        LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type); -        return Kernel::ERR_INVALID_ENUM_VALUE; -    } - -    return RESULT_SUCCESS; +/// Close a handle +static ResultCode CloseHandle(Kernel::Handle handle) { +    LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle); +    return Kernel::g_handle_table.Close(handle);  }  namespace { @@ -1188,135 +179,137 @@ struct FunctionDef {      Func* func;      const char* name;  }; -} +} // namespace  static const FunctionDef SVC_Table[] = {      {0x00, nullptr, "Unknown"}, -    {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"}, -    {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"}, -    {0x03, nullptr, "ExitProcess"}, -    {0x04, nullptr, "GetProcessAffinityMask"}, -    {0x05, nullptr, "SetProcessAffinityMask"}, -    {0x06, nullptr, "GetProcessIdealProcessor"}, -    {0x07, nullptr, "SetProcessIdealProcessor"}, -    {0x08, HLE::Wrap<CreateThread>, "CreateThread"}, -    {0x09, ExitThread, "ExitThread"}, -    {0x0A, HLE::Wrap<SleepThread>, "SleepThread"}, -    {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"}, -    {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"}, -    {0x0D, nullptr, "GetThreadAffinityMask"}, -    {0x0E, nullptr, "SetThreadAffinityMask"}, -    {0x0F, nullptr, "GetThreadIdealProcessor"}, -    {0x10, nullptr, "SetThreadIdealProcessor"}, -    {0x11, nullptr, "GetCurrentProcessorNumber"}, -    {0x12, nullptr, "Run"}, -    {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"}, -    {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"}, -    {0x15, HLE::Wrap<CreateSemaphore>, "CreateSemaphore"}, -    {0x16, HLE::Wrap<ReleaseSemaphore>, "ReleaseSemaphore"}, -    {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"}, -    {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"}, -    {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"}, -    {0x1A, HLE::Wrap<CreateTimer>, "CreateTimer"}, -    {0x1B, HLE::Wrap<SetTimer>, "SetTimer"}, -    {0x1C, HLE::Wrap<CancelTimer>, "CancelTimer"}, -    {0x1D, HLE::Wrap<ClearTimer>, "ClearTimer"}, -    {0x1E, HLE::Wrap<CreateMemoryBlock>, "CreateMemoryBlock"}, -    {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"}, -    {0x20, HLE::Wrap<UnmapMemoryBlock>, "UnmapMemoryBlock"}, -    {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"}, -    {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"}, -    {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"}, -    {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"}, -    {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"}, -    {0x26, nullptr, "SignalAndWait"}, -    {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"}, -    {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, -    {0x29, nullptr, "GetHandleInfo"}, -    {0x2A, HLE::Wrap<GetSystemInfo>, "GetSystemInfo"}, -    {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"}, -    {0x2C, nullptr, "GetThreadInfo"}, -    {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, -    {0x2E, nullptr, "SendSyncRequest1"}, -    {0x2F, nullptr, "SendSyncRequest2"}, -    {0x30, nullptr, "SendSyncRequest3"}, -    {0x31, nullptr, "SendSyncRequest4"}, -    {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"}, -    {0x33, nullptr, "OpenProcess"}, -    {0x34, nullptr, "OpenThread"}, -    {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"}, -    {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"}, -    {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"}, -    {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"}, -    {0x39, HLE::Wrap<GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"}, -    {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, -    {0x3B, nullptr, "GetThreadContext"}, -    {0x3C, HLE::Wrap<Break>, "Break"}, -    {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"}, -    {0x3E, nullptr, "ControlPerformanceCounter"}, +    {0x01, nullptr, "svcSetHeapSize"}, +    {0x02, nullptr, "svcSetMemoryPermission"}, +    {0x03, nullptr, "svcSetMemoryAttribute"}, +    {0x04, nullptr, "svcMapMemory"}, +    {0x05, nullptr, "svcUnmapMemory"}, +    {0x06, HLE::Wrap<QueryMemory>, "svcQueryMemory"}, +    {0x07, nullptr, "svcExitProcess"}, +    {0x08, nullptr, "svcCreateThread"}, +    {0x09, nullptr, "svcStartThread"}, +    {0x0A, nullptr, "svcExitThread"}, +    {0x0B, HLE::Wrap<SleepThread>, "svcSleepThread"}, +    {0x0C, HLE::Wrap<GetThreadPriority>, "svcGetThreadPriority"}, +    {0x0D, nullptr, "svcSetThreadPriority"}, +    {0x0E, nullptr, "svcGetThreadCoreMask"}, +    {0x0F, nullptr, "svcSetThreadCoreMask"}, +    {0x10, nullptr, "svcGetCurrentProcessorNumber"}, +    {0x11, nullptr, "svcSignalEvent"}, +    {0x12, nullptr, "svcClearEvent"}, +    {0x13, nullptr, "svcMapSharedMemory"}, +    {0x14, nullptr, "svcUnmapSharedMemory"}, +    {0x15, nullptr, "svcCreateTransferMemory"}, +    {0x16, HLE::Wrap<CloseHandle>, "svcCloseHandle"}, +    {0x17, nullptr, "svcResetSignal"}, +    {0x18, nullptr, "svcWaitSynchronization"}, +    {0x19, nullptr, "svcCancelSynchronization"}, +    {0x1A, nullptr, "svcLockMutex"}, +    {0x1B, nullptr, "svcUnlockMutex"}, +    {0x1C, nullptr, "svcWaitProcessWideKeyAtomic"}, +    {0x1D, HLE::Wrap<SignalProcessWideKey>, "svcSignalProcessWideKey"}, +    {0x1E, nullptr, "svcGetSystemTick"}, +    {0x1F, HLE::Wrap<ConnectToPort>, "svcConnectToPort"}, +    {0x20, nullptr, "svcSendSyncRequestLight"}, +    {0x21, HLE::Wrap<SendSyncRequest>, "svcSendSyncRequest"}, +    {0x22, nullptr, "svcSendSyncRequestWithUserBuffer"}, +    {0x23, nullptr, "svcSendAsyncRequestWithUserBuffer"}, +    {0x24, nullptr, "svcGetProcessId"}, +    {0x25, nullptr, "svcGetThreadId"}, +    {0x26, HLE::Wrap<Break>, "svcBreak"}, +    {0x27, HLE::Wrap<OutputDebugString>, "svcOutputDebugString"}, +    {0x28, nullptr, "svcReturnFromException"}, +    {0x29, HLE::Wrap<GetInfo>, "svcGetInfo"}, +    {0x2A, nullptr, "svcFlushEntireDataCache"}, +    {0x2B, nullptr, "svcFlushDataCache"}, +    {0x2C, nullptr, "svcMapPhysicalMemory"}, +    {0x2D, nullptr, "svcUnmapPhysicalMemory"}, +    {0x2E, nullptr, "Unknown"}, +    {0x2F, nullptr, "svcGetLastThreadInfo"}, +    {0x30, nullptr, "svcGetResourceLimitLimitValue"}, +    {0x31, nullptr, "svcGetResourceLimitCurrentValue"}, +    {0x32, nullptr, "svcSetThreadActivity"}, +    {0x33, nullptr, "svcGetThreadContext"}, +    {0x34, nullptr, "Unknown"}, +    {0x35, nullptr, "Unknown"}, +    {0x36, nullptr, "Unknown"}, +    {0x37, nullptr, "Unknown"}, +    {0x38, nullptr, "Unknown"}, +    {0x39, nullptr, "Unknown"}, +    {0x3A, nullptr, "Unknown"}, +    {0x3B, nullptr, "Unknown"}, +    {0x3C, nullptr, "svcDumpInfo"}, +    {0x3D, nullptr, "Unknown"}, +    {0x3E, nullptr, "Unknown"},      {0x3F, nullptr, "Unknown"}, -    {0x40, nullptr, "Unknown"}, -    {0x41, nullptr, "Unknown"}, -    {0x42, nullptr, "Unknown"}, -    {0x43, nullptr, "Unknown"}, -    {0x44, nullptr, "Unknown"}, -    {0x45, nullptr, "Unknown"}, +    {0x40, nullptr, "svcCreateSession"}, +    {0x41, nullptr, "svcAcceptSession"}, +    {0x42, nullptr, "svcReplyAndReceiveLight"}, +    {0x43, nullptr, "svcReplyAndReceive"}, +    {0x44, nullptr, "svcReplyAndReceiveWithUserBuffer"}, +    {0x45, nullptr, "svcCreateEvent"},      {0x46, nullptr, "Unknown"}, -    {0x47, HLE::Wrap<CreatePort>, "CreatePort"}, -    {0x48, HLE::Wrap<CreateSessionToPort>, "CreateSessionToPort"}, -    {0x49, HLE::Wrap<CreateSession>, "CreateSession"}, -    {0x4A, HLE::Wrap<AcceptSession>, "AcceptSession"}, -    {0x4B, nullptr, "ReplyAndReceive1"}, -    {0x4C, nullptr, "ReplyAndReceive2"}, -    {0x4D, nullptr, "ReplyAndReceive3"}, -    {0x4E, nullptr, "ReplyAndReceive4"}, -    {0x4F, HLE::Wrap<ReplyAndReceive>, "ReplyAndReceive"}, -    {0x50, nullptr, "BindInterrupt"}, -    {0x51, nullptr, "UnbindInterrupt"}, -    {0x52, nullptr, "InvalidateProcessDataCache"}, -    {0x53, nullptr, "StoreProcessDataCache"}, -    {0x54, nullptr, "FlushProcessDataCache"}, -    {0x55, nullptr, "StartInterProcessDma"}, -    {0x56, nullptr, "StopDma"}, -    {0x57, nullptr, "GetDmaState"}, -    {0x58, nullptr, "RestartDma"}, -    {0x59, nullptr, "Unknown"}, -    {0x5A, nullptr, "Unknown"}, -    {0x5B, nullptr, "Unknown"}, -    {0x5C, nullptr, "Unknown"}, -    {0x5D, nullptr, "Unknown"}, -    {0x5E, nullptr, "Unknown"}, -    {0x5F, nullptr, "Unknown"}, -    {0x60, nullptr, "DebugActiveProcess"}, -    {0x61, nullptr, "BreakDebugProcess"}, -    {0x62, nullptr, "TerminateDebugProcess"}, -    {0x63, nullptr, "GetProcessDebugEvent"}, -    {0x64, nullptr, "ContinueDebugEvent"}, -    {0x65, nullptr, "GetProcessList"}, -    {0x66, nullptr, "GetThreadList"}, -    {0x67, nullptr, "GetDebugThreadContext"}, -    {0x68, nullptr, "SetDebugThreadContext"}, -    {0x69, nullptr, "QueryDebugProcessMemory"}, -    {0x6A, nullptr, "ReadProcessMemory"}, -    {0x6B, nullptr, "WriteProcessMemory"}, -    {0x6C, nullptr, "SetHardwareBreakPoint"}, -    {0x6D, nullptr, "GetDebugThreadParam"}, +    {0x47, nullptr, "Unknown"}, +    {0x48, nullptr, "Unknown"}, +    {0x49, nullptr, "Unknown"}, +    {0x4A, nullptr, "Unknown"}, +    {0x4B, nullptr, "Unknown"}, +    {0x4C, nullptr, "Unknown"}, +    {0x4D, nullptr, "svcSleepSystem"}, +    {0x4E, nullptr, "svcReadWriteRegister"}, +    {0x4F, nullptr, "svcSetProcessActivity"}, +    {0x50, nullptr, "svcCreateSharedMemory"}, +    {0x51, nullptr, "svcMapTransferMemory"}, +    {0x52, nullptr, "svcUnmapTransferMemory"}, +    {0x53, nullptr, "svcCreateInterruptEvent"}, +    {0x54, nullptr, "svcQueryPhysicalAddress"}, +    {0x55, nullptr, "svcQueryIoMapping"}, +    {0x56, nullptr, "svcCreateDeviceAddressSpace"}, +    {0x57, nullptr, "svcAttachDeviceAddressSpace"}, +    {0x58, nullptr, "svcDetachDeviceAddressSpace"}, +    {0x59, nullptr, "svcMapDeviceAddressSpaceByForce"}, +    {0x5A, nullptr, "svcMapDeviceAddressSpaceAligned"}, +    {0x5B, nullptr, "svcMapDeviceAddressSpace"}, +    {0x5C, nullptr, "svcUnmapDeviceAddressSpace"}, +    {0x5D, nullptr, "svcInvalidateProcessDataCache"}, +    {0x5E, nullptr, "svcStoreProcessDataCache"}, +    {0x5F, nullptr, "svcFlushProcessDataCache"}, +    {0x60, nullptr, "svcDebugActiveProcess"}, +    {0x61, nullptr, "svcBreakDebugProcess"}, +    {0x62, nullptr, "svcTerminateDebugProcess"}, +    {0x63, nullptr, "svcGetDebugEvent"}, +    {0x64, nullptr, "svcContinueDebugEvent"}, +    {0x65, nullptr, "svcGetProcessList"}, +    {0x66, nullptr, "svcGetThreadList"}, +    {0x67, nullptr, "svcGetDebugThreadContext"}, +    {0x68, nullptr, "svcSetDebugThreadContext"}, +    {0x69, nullptr, "svcQueryDebugProcessMemory"}, +    {0x6A, nullptr, "svcReadDebugProcessMemory"}, +    {0x6B, nullptr, "svcWriteDebugProcessMemory"}, +    {0x6C, nullptr, "svcSetHardwareBreakPoint"}, +    {0x6D, nullptr, "svcGetDebugThreadParam"},      {0x6E, nullptr, "Unknown"},      {0x6F, nullptr, "Unknown"}, -    {0x70, nullptr, "ControlProcessMemory"}, -    {0x71, nullptr, "MapProcessMemory"}, -    {0x72, nullptr, "UnmapProcessMemory"}, -    {0x73, nullptr, "CreateCodeSet"}, -    {0x74, nullptr, "RandomStub"}, -    {0x75, nullptr, "CreateProcess"}, -    {0x76, nullptr, "TerminateProcess"}, -    {0x77, nullptr, "SetProcessResourceLimits"}, -    {0x78, nullptr, "CreateResourceLimit"}, -    {0x79, nullptr, "SetResourceLimitValues"}, -    {0x7A, nullptr, "AddCodeSegment"}, -    {0x7B, nullptr, "Backdoor"}, -    {0x7C, nullptr, "KernelSetState"}, -    {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"}, +    {0x70, nullptr, "svcCreatePort"}, +    {0x71, nullptr, "svcManageNamedPort"}, +    {0x72, nullptr, "svcConnectToPort"}, +    {0x73, nullptr, "svcSetProcessMemoryPermission"}, +    {0x74, nullptr, "svcMapProcessMemory"}, +    {0x75, nullptr, "svcUnmapProcessMemory"}, +    {0x76, nullptr, "svcQueryProcessMemory"}, +    {0x77, nullptr, "svcMapProcessCodeMemory"}, +    {0x78, nullptr, "svcUnmapProcessCodeMemory"}, +    {0x79, nullptr, "svcCreateProcess"}, +    {0x7A, nullptr, "svcStartProcess"}, +    {0x7B, nullptr, "svcTerminateProcess"}, +    {0x7C, nullptr, "svcGetProcessInfo"}, +    {0x7D, nullptr, "svcCreateResourceLimit"}, +    {0x7E, nullptr, "svcSetResourceLimitLimitValue"}, +    {0x7F, nullptr, "svcCallSecureMonitor"},  };  static const FunctionDef* GetSVCInfo(u32 func_num) { @@ -1332,14 +325,21 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));  void CallSVC(u32 immediate) {      MICROPROFILE_SCOPE(Kernel_SVC); +    // Lock the global kernel mutex when we enter the kernel HLE. +    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); +      const FunctionDef* info = GetSVCInfo(immediate);      if (info) {          if (info->func) {              info->func();          } else { -            LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name); +            LOG_CRITICAL(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);          } +    } else { +        LOG_CRITICAL(Kernel_SVC, "unknown SVC function 0x%x", immediate);      } + +    LOG_CRITICAL(Kernel_SVC, "PC = 0x%08X", Core::CPU().GetPC());  } -} // namespace +} // namespace SVC  | 
