From 7e191dccc184ae85ce5ade2bca913ab331002481 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 21 Jun 2018 00:49:43 -0600 Subject: Kernel/Arbiters: Add stubs for 4.x SignalToAddress/WaitForAddres SVCs. --- src/core/hle/kernel/address_arbiter.cpp | 46 ++++++++++++++++++++++++++++ src/core/hle/kernel/address_arbiter.h | 32 ++++++++++++++++++++ src/core/hle/kernel/errors.h | 10 ++++--- src/core/hle/kernel/mutex.cpp | 4 +-- src/core/hle/kernel/svc.cpp | 53 +++++++++++++++++++++++++++++++-- src/core/hle/kernel/svc_wrap.h | 10 +++++++ src/core/hle/kernel/thread.h | 1 + 7 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 src/core/hle/kernel/address_arbiter.cpp create mode 100644 src/core/hle/kernel/address_arbiter.h (limited to 'src/core') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp new file mode 100644 index 000000000..cfd2c1590 --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -0,0 +1,46 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/thread.h" +#include "core/memory.h" + +namespace Kernel { + namespace AddressArbiter { + + // Signals an address being waited on. + ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake) { + // TODO + return RESULT_SUCCESS; + } + + // Signals an address being waited on and increments its value if equal to the value argument. + ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + // TODO + return RESULT_SUCCESS; + } + + // Signals an address being waited on and modifies its value based on waiting thread count if equal to the value argument. + ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + // TODO + return RESULT_SUCCESS; + } + + // Waits on an address if the value passed is less than the argument value, optionally decrementing. + ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { + // TODO + return RESULT_SUCCESS; + } + + // Waits on an address if the value passed is equal to the argument value. + ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { + // TODO + return RESULT_SUCCESS; + } + } // namespace AddressArbiter +} // namespace Kernel \ No newline at end of file diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h new file mode 100644 index 000000000..3eba103dd --- /dev/null +++ b/src/core/hle/kernel/address_arbiter.h @@ -0,0 +1,32 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" + +namespace Kernel { + + namespace AddressArbiter { + enum class ArbitrationType { + WaitIfLessThan = 0, + DecrementAndWaitIfLessThan = 1, + WaitIfEqual = 2, + }; + + enum class SignalType { + Signal = 0, + IncrementAndSignalIfEqual = 1, + ModifyByWaitingCountAndSignalIfEqual = 2, + }; + + ResultCode SignalToAddress(VAddr address, s32 value, s32 num_to_wake); + ResultCode IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); + ResultCode ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake); + + ResultCode WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement); + ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); + } // namespace AddressArbiter + +} // namespace Kernel \ No newline at end of file diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index e1b5430bf..7ac960042 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -20,13 +20,15 @@ enum { MaxConnectionsReached = 52, // Confirmed Switch OS error codes - MisalignedAddress = 102, + InvalidAddress = 102, + InvalidMemoryState = 106, InvalidProcessorId = 113, InvalidHandle = 114, InvalidCombination = 116, Timeout = 117, SynchronizationCanceled = 118, TooLarge = 119, + InvalidEnumValue = 120, }; } @@ -39,13 +41,13 @@ constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(-1); constexpr ResultCode ERR_PORT_NAME_TOO_LONG(-1); constexpr ResultCode ERR_WRONG_PERMISSION(-1); constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-1); -constexpr ResultCode ERR_INVALID_ENUM_VALUE(-1); +constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue); constexpr ResultCode ERR_INVALID_ENUM_VALUE_FND(-1); constexpr ResultCode ERR_INVALID_COMBINATION(-1); constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1); constexpr ResultCode ERR_OUT_OF_MEMORY(-1); -constexpr ResultCode ERR_INVALID_ADDRESS(-1); -constexpr ResultCode ERR_INVALID_ADDRESS_STATE(-1); +constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress); +constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); constexpr ResultCode ERR_INVALID_POINTER(-1); constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index bc144f3de..65560226d 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -59,7 +59,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, Handle requesting_thread_handle) { // The mutex address must be 4-byte aligned if ((address % sizeof(u32)) != 0) { - return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); + return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); } SharedPtr holding_thread = g_handle_table.Get(holding_thread_handle); @@ -97,7 +97,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, ResultCode Mutex::Release(VAddr address) { // The mutex address must be 4-byte aligned if ((address % sizeof(u32)) != 0) { - return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress); + return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress); } auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 69ba7b777..4b4831c08 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -11,6 +11,7 @@ #include "common/string_util.h" #include "core/core.h" #include "core/core_timing.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/event.h" @@ -580,7 +581,7 @@ static void SleepThread(s64 nanoseconds) { Core::System::GetInstance().PrepareReschedule(); } -/// Signal process wide key atomic +/// Wait process wide key atomic static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr, Handle thread_handle, s64 nano_seconds) { NGLOG_TRACE( @@ -689,6 +690,52 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target return RESULT_SUCCESS; } +// Wait for an address (via Address Arbiter) +static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout) { + // If the passed address is a kernel virtual address, return invalid memory state. + if ((address + 0x8000000000LL) < 0x7FFFE00000LL) { + return ERR_INVALID_ADDRESS_STATE; + } + // If the address is not properly aligned to 4 bytes, return invalid address. + if (address % sizeof(u32) != 0) { + return ERR_INVALID_ADDRESS; + } + + switch ((AddressArbiter::ArbitrationType)type) { + case AddressArbiter::ArbitrationType::WaitIfLessThan: + return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, false); + case AddressArbiter::ArbitrationType::DecrementAndWaitIfLessThan: + return AddressArbiter::WaitForAddressIfLessThan(address, value, timeout, true); + case AddressArbiter::ArbitrationType::WaitIfEqual: + return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); + default: + return ERR_INVALID_ENUM_VALUE; + } +} + +// Signals to an address (via Address Arbiter) +static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to_wake) { + // If the passed address is a kernel virtual address, return invalid memory state. + if ((address + 0x8000000000LL) < 0x7FFFE00000LL) { + return ERR_INVALID_ADDRESS_STATE; + } + // If the address is not properly aligned to 4 bytes, return invalid address. + if (address % sizeof(u32) != 0) { + return ERR_INVALID_ADDRESS; + } + + switch ((AddressArbiter::SignalType)type) { + case AddressArbiter::SignalType::Signal: + return AddressArbiter::SignalToAddress(address, value, num_to_wake); + case AddressArbiter::SignalType::IncrementAndSignalIfEqual: + return AddressArbiter::IncrementAndSignalToAddressIfEqual(address, value, num_to_wake); + case AddressArbiter::SignalType::ModifyByWaitingCountAndSignalIfEqual: + return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, num_to_wake); + default: + return ERR_INVALID_ENUM_VALUE; + } +} + /// This returns the total CPU ticks elapsed since the CPU was powered-on static u64 GetSystemTick() { const u64 result{CoreTiming::GetTicks()}; @@ -861,8 +908,8 @@ static const FunctionDef SVC_Table[] = { {0x31, nullptr, "GetResourceLimitCurrentValue"}, {0x32, SvcWrap, "SetThreadActivity"}, {0x33, SvcWrap, "GetThreadContext"}, - {0x34, nullptr, "WaitForAddress"}, - {0x35, nullptr, "SignalToAddress"}, + {0x34, SvcWrap, "WaitForAddress"}, + {0x35, SvcWrap, "SignalToAddress"}, {0x36, nullptr, "Unknown"}, {0x37, nullptr, "Unknown"}, {0x38, nullptr, "Unknown"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 40aa88cc1..efae4fdfe 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -179,6 +179,16 @@ void SvcWrap() { FuncReturn(retval); } +template +void SvcWrap() { + FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)).raw); +} + +template +void SvcWrap() { + FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s32)(PARAM(3) & 0xFFFFFFFF)).raw); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Function wrappers that return type u32 diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 1d2da6d50..023c9dbe9 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -45,6 +45,7 @@ enum ThreadStatus { THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc + THREADSTATUS_WAIT_ARB, ///< Waiting due to a SignalToAddress/WaitForAddress svc THREADSTATUS_DORMANT, ///< Created but not yet made ready THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated }; -- cgit v1.2.3