aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp68
1 files changed, 63 insertions, 5 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index ec3601e8b..1a36e0d02 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"
@@ -316,6 +317,11 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
*result = 0;
break;
+ case GetInfoType::UserExceptionContextAddr:
+ NGLOG_WARNING(Kernel_SVC,
+ "(STUBBED) Attempted to query user exception context address, returned 0");
+ *result = 0;
+ break;
default:
UNIMPLEMENTED();
}
@@ -575,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(
@@ -684,6 +690,58 @@ 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) {
+ NGLOG_WARNING(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}",
+ address, type, value, timeout);
+ // If the passed address is a kernel virtual address, return invalid memory state.
+ if (Memory::IsKernelVirtualAddress(address)) {
+ 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 (static_cast<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) {
+ NGLOG_WARNING(Kernel_SVC,
+ "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", address,
+ type, value, num_to_wake);
+ // If the passed address is a kernel virtual address, return invalid memory state.
+ if (Memory::IsKernelVirtualAddress(address)) {
+ 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 (static_cast<AddressArbiter::SignalType>(type)) {
+ case AddressArbiter::SignalType::Signal:
+ return AddressArbiter::SignalToAddress(address, 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()};
@@ -744,7 +802,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT);
// Set the target CPU to the one specified in the process' exheader.
core = thread->owner_process->ideal_processor;
- mask = 1 << core;
+ mask = 1ull << core;
}
if (mask == 0) {
@@ -761,7 +819,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
}
// Error out if the input core isn't enabled in the input mask.
- if (core < Core::NUM_CPU_CORES && (mask & (1 << core)) == 0) {
+ if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) {
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
}
@@ -856,8 +914,8 @@ static const FunctionDef SVC_Table[] = {
{0x31, nullptr, "GetResourceLimitCurrentValue"},
{0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
{0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
- {0x34, nullptr, "WaitForAddress"},
- {0x35, nullptr, "SignalToAddress"},
+ {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
+ {0x35, SvcWrap<SignalToAddress>, "SignalToAddress"},
{0x36, nullptr, "Unknown"},
{0x37, nullptr, "Unknown"},
{0x38, nullptr, "Unknown"},