mirror of
https://github.com/yuzu-mirror/yuzu
synced 2024-11-30 04:20:22 +00:00
Kernel/Arbiters: Add stubs for 4.x SignalToAddress/WaitForAddres SVCs.
This commit is contained in:
parent
c3e95086b6
commit
7e191dccc1
7 changed files with 147 additions and 9 deletions
46
src/core/hle/kernel/address_arbiter.cpp
Normal file
46
src/core/hle/kernel/address_arbiter.cpp
Normal file
|
@ -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
|
32
src/core/hle/kernel/address_arbiter.h
Normal file
32
src/core/hle/kernel/address_arbiter.h
Normal file
|
@ -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
|
|
@ -20,13 +20,15 @@ enum {
|
||||||
MaxConnectionsReached = 52,
|
MaxConnectionsReached = 52,
|
||||||
|
|
||||||
// Confirmed Switch OS error codes
|
// Confirmed Switch OS error codes
|
||||||
MisalignedAddress = 102,
|
InvalidAddress = 102,
|
||||||
|
InvalidMemoryState = 106,
|
||||||
InvalidProcessorId = 113,
|
InvalidProcessorId = 113,
|
||||||
InvalidHandle = 114,
|
InvalidHandle = 114,
|
||||||
InvalidCombination = 116,
|
InvalidCombination = 116,
|
||||||
Timeout = 117,
|
Timeout = 117,
|
||||||
SynchronizationCanceled = 118,
|
SynchronizationCanceled = 118,
|
||||||
TooLarge = 119,
|
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_PORT_NAME_TOO_LONG(-1);
|
||||||
constexpr ResultCode ERR_WRONG_PERMISSION(-1);
|
constexpr ResultCode ERR_WRONG_PERMISSION(-1);
|
||||||
constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(-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_ENUM_VALUE_FND(-1);
|
||||||
constexpr ResultCode ERR_INVALID_COMBINATION(-1);
|
constexpr ResultCode ERR_INVALID_COMBINATION(-1);
|
||||||
constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1);
|
constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(-1);
|
||||||
constexpr ResultCode ERR_OUT_OF_MEMORY(-1);
|
constexpr ResultCode ERR_OUT_OF_MEMORY(-1);
|
||||||
constexpr ResultCode ERR_INVALID_ADDRESS(-1);
|
constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||||
constexpr ResultCode ERR_INVALID_ADDRESS_STATE(-1);
|
constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
|
||||||
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
||||||
constexpr ResultCode ERR_INVALID_POINTER(-1);
|
constexpr ResultCode ERR_INVALID_POINTER(-1);
|
||||||
constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
|
constexpr ResultCode ERR_INVALID_OBJECT_ADDR(-1);
|
||||||
|
|
|
@ -59,7 +59,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
|
||||||
Handle requesting_thread_handle) {
|
Handle requesting_thread_handle) {
|
||||||
// The mutex address must be 4-byte aligned
|
// The mutex address must be 4-byte aligned
|
||||||
if ((address % sizeof(u32)) != 0) {
|
if ((address % sizeof(u32)) != 0) {
|
||||||
return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress);
|
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle);
|
SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle);
|
||||||
|
@ -97,7 +97,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
|
||||||
ResultCode Mutex::Release(VAddr address) {
|
ResultCode Mutex::Release(VAddr address) {
|
||||||
// The mutex address must be 4-byte aligned
|
// The mutex address must be 4-byte aligned
|
||||||
if ((address % sizeof(u32)) != 0) {
|
if ((address % sizeof(u32)) != 0) {
|
||||||
return ResultCode(ErrorModule::Kernel, ErrCodes::MisalignedAddress);
|
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address);
|
auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.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_port.h"
|
||||||
#include "core/hle/kernel/client_session.h"
|
#include "core/hle/kernel/client_session.h"
|
||||||
#include "core/hle/kernel/event.h"
|
#include "core/hle/kernel/event.h"
|
||||||
|
@ -580,7 +581,7 @@ static void SleepThread(s64 nanoseconds) {
|
||||||
Core::System::GetInstance().PrepareReschedule();
|
Core::System::GetInstance().PrepareReschedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signal process wide key atomic
|
/// Wait process wide key atomic
|
||||||
static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr,
|
static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_variable_addr,
|
||||||
Handle thread_handle, s64 nano_seconds) {
|
Handle thread_handle, s64 nano_seconds) {
|
||||||
NGLOG_TRACE(
|
NGLOG_TRACE(
|
||||||
|
@ -689,6 +690,52 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
|
||||||
return RESULT_SUCCESS;
|
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
|
/// This returns the total CPU ticks elapsed since the CPU was powered-on
|
||||||
static u64 GetSystemTick() {
|
static u64 GetSystemTick() {
|
||||||
const u64 result{CoreTiming::GetTicks()};
|
const u64 result{CoreTiming::GetTicks()};
|
||||||
|
@ -861,8 +908,8 @@ static const FunctionDef SVC_Table[] = {
|
||||||
{0x31, nullptr, "GetResourceLimitCurrentValue"},
|
{0x31, nullptr, "GetResourceLimitCurrentValue"},
|
||||||
{0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
|
{0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
|
||||||
{0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
|
{0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
|
||||||
{0x34, nullptr, "WaitForAddress"},
|
{0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
|
||||||
{0x35, nullptr, "SignalToAddress"},
|
{0x35, SvcWrap<SignalToAddress>, "SignalToAddress"},
|
||||||
{0x36, nullptr, "Unknown"},
|
{0x36, nullptr, "Unknown"},
|
||||||
{0x37, nullptr, "Unknown"},
|
{0x37, nullptr, "Unknown"},
|
||||||
{0x38, nullptr, "Unknown"},
|
{0x38, nullptr, "Unknown"},
|
||||||
|
|
|
@ -179,6 +179,16 @@ void SvcWrap() {
|
||||||
FuncReturn(retval);
|
FuncReturn(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <ResultCode func(u64, u32, s32, s64)>
|
||||||
|
void SvcWrap() {
|
||||||
|
FuncReturn(func(PARAM(0), (u32)(PARAM(1) & 0xFFFFFFFF), (s32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3)).raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <ResultCode func(u64, u32, s32, s32)>
|
||||||
|
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
|
// Function wrappers that return type u32
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ enum ThreadStatus {
|
||||||
THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
|
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_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
|
||||||
THREADSTATUS_WAIT_MUTEX, ///< Waiting due to an ArbitrateLock/WaitProcessWideKey svc
|
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_DORMANT, ///< Created but not yet made ready
|
||||||
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
|
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue