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.cpp381
1 files changed, 266 insertions, 115 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 74eb90100..26650a513 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -14,6 +14,7 @@
#include "common/fiber.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
+#include "common/scope_exit.h"
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
@@ -26,18 +27,20 @@
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_condition_variable.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory/memory_block.h"
#include "core/hle/kernel/memory/memory_layout.h"
#include "core/hle/kernel/memory/page_table.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
@@ -45,7 +48,6 @@
#include "core/hle/kernel/svc_wrap.h"
#include "core/hle/kernel/time_manager.h"
#include "core/hle/kernel/transfer_memory.h"
-#include "core/hle/kernel/writable_event.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@@ -366,7 +368,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t
// Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
+ return ResultInvalidHandle;
+ }
// Get the thread's id.
*out_thread_id = thread->GetThreadID();
@@ -476,7 +481,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
// Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
+ return ResultInvalidHandle;
+ }
// Cancel the thread's wait.
thread->WaitCancel();
@@ -494,8 +502,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd
thread_handle, address, tag);
// Validate the input address.
- R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
- R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress);
+ if (Memory::IsKernelAddress(address)) {
+ LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
+ address);
+ return ResultInvalidCurrentMemory;
+ }
+ if (!Common::IsAligned(address, sizeof(u32))) {
+ LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
+ return ResultInvalidAddress;
+ }
return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag);
}
@@ -510,8 +525,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) {
LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
// Validate the input address.
- R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
- R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress);
+ if (Memory::IsKernelAddress(address)) {
+ LOG_ERROR(Kernel_SVC,
+ "Attempting to arbitrate an unlock on a kernel address (address={:08X})",
+ address);
+ return ResultInvalidCurrentMemory;
+ }
+ if (!Common::IsAligned(address, sizeof(u32))) {
+ LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
+ return ResultInvalidAddress;
+ }
return system.Kernel().CurrentProcess()->SignalToAddress(address);
}
@@ -1023,37 +1046,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
return UnmapPhysicalMemory(system, addr, size);
}
-constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
- switch (thread_activity) {
- case Svc::ThreadActivity::Runnable:
- case Svc::ThreadActivity::Paused:
- return true;
- default:
- return false;
- }
-}
-
/// Sets the thread activity
static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
- Svc::ThreadActivity thread_activity) {
+ ThreadActivity thread_activity) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
thread_activity);
// Validate the activity.
- R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue);
+ constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
+ return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
+ };
+ if (!IsValidThreadActivity(thread_activity)) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
+ thread_activity);
+ return ResultInvalidEnumValue;
+ }
// Get the thread from its handle.
auto& kernel = system.Kernel();
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
+ return ResultInvalidHandle;
+ }
// Check that the activity is being set on a non-current thread for the current process.
- R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle);
- R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy);
+ if (thread->GetOwnerProcess() != kernel.CurrentProcess()) {
+ LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread.");
+ return ResultInvalidHandle;
+ }
+ if (thread.get() == GetCurrentThreadPointer(kernel)) {
+ LOG_ERROR(Kernel_SVC, "Thread is busy");
+ return ResultBusy;
+ }
// Set the activity.
- R_TRY(thread->SetActivity(thread_activity));
+ const auto set_result = thread->SetActivity(thread_activity);
+ if (set_result.IsError()) {
+ LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
+ return set_result;
+ }
return RESULT_SUCCESS;
}
@@ -1072,16 +1105,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
const auto* current_process = system.Kernel().CurrentProcess();
const std::shared_ptr<KThread> thread =
current_process->GetHandleTable().Get<KThread>(thread_handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
+ return ResultInvalidHandle;
+ }
// Require the handle be to a non-current thread in the current process.
- R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle);
- R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(),
- Svc::ResultBusy);
+ if (thread->GetOwnerProcess() != current_process) {
+ LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process.");
+ return ResultInvalidHandle;
+ }
+ if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
+ LOG_ERROR(Kernel_SVC, "Current thread is busy.");
+ return ResultBusy;
+ }
// Get the thread context.
std::vector<u8> context;
- R_TRY(thread->GetThreadContext3(context));
+ const auto context_result = thread->GetThreadContext3(context);
+ if (context_result.IsError()) {
+ LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})",
+ context_result.raw);
+ return context_result;
+ }
// Copy the thread context to user space.
system.Memory().WriteBlock(out_context, context.data(), context.size());
@@ -1100,7 +1146,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
// Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
+ return ResultInvalidHandle;
+ }
// Get the thread's priority.
*out_priority = thread->GetPriority();
@@ -1116,13 +1165,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
LOG_TRACE(Kernel_SVC, "called");
// Validate the priority.
- R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
- Svc::ResultInvalidPriority);
+ if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority);
+ return ResultInvalidPriority;
+ }
// Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
+ return ResultInvalidHandle;
+ }
// Set the thread priority.
thread->SetBasePriority(priority);
@@ -1438,17 +1492,28 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
// Adjust core id, if it's the default magic.
auto& kernel = system.Kernel();
auto& process = *kernel.CurrentProcess();
- if (core_id == Svc::IdealCoreUseProcessValue) {
+ if (core_id == IdealCoreUseProcessValue) {
core_id = process.GetIdealCoreId();
}
// Validate arguments.
- R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId);
- R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId);
+ if (!IsValidCoreId(core_id)) {
+ LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
+ return ResultInvalidCoreId;
+ }
+ if (((1ULL << core_id) & process.GetCoreMask()) == 0) {
+ LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id);
+ return ResultInvalidCoreId;
+ }
- R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
- Svc::ResultInvalidPriority);
- R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
+ if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
+ LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority);
+ return ResultInvalidPriority;
+ }
+ if (!process.CheckThreadPriority(priority)) {
+ LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority);
+ return ResultInvalidPriority;
+ }
ASSERT(process.GetResourceLimit()->Reserve(
LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000));
@@ -1487,10 +1552,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
// Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
+ return ResultInvalidHandle;
+ }
// Try to start the thread.
- R_TRY(thread->Run());
+ const auto run_result = thread->Run();
+ if (run_result.IsError()) {
+ LOG_ERROR(Kernel_SVC,
+ "Unable to successfuly start thread (thread handle={:08X}, result={})",
+ thread_handle, run_result.raw);
+ return run_result;
+ }
return RESULT_SUCCESS;
}
@@ -1551,8 +1625,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address,
cv_key, tag, timeout_ns);
// Validate input.
- R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
- R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress);
+ if (Memory::IsKernelAddress(address)) {
+ LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
+ return ResultInvalidCurrentMemory;
+ }
+ if (!Common::IsAligned(address, sizeof(s32))) {
+ LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address);
+ return ResultInvalidAddress;
+ }
// Convert timeout from nanoseconds to ticks.
s64 timeout{};
@@ -1627,9 +1707,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit
address, arb_type, value, timeout_ns);
// Validate input.
- R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
- R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress);
- R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue);
+ if (Memory::IsKernelAddress(address)) {
+ LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
+ return ResultInvalidCurrentMemory;
+ }
+ if (!Common::IsAligned(address, sizeof(s32))) {
+ LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address);
+ return ResultInvalidAddress;
+ }
+ if (!IsValidArbitrationType(arb_type)) {
+ LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type);
+ return ResultInvalidEnumValue;
+ }
// Convert timeout from nanoseconds to ticks.
s64 timeout{};
@@ -1663,9 +1752,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
address, signal_type, value, count);
// Validate input.
- R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory);
- R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress);
- R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue);
+ if (Memory::IsKernelAddress(address)) {
+ LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
+ return ResultInvalidCurrentMemory;
+ }
+ if (!Common::IsAligned(address, sizeof(s32))) {
+ LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address);
+ return ResultInvalidAddress;
+ }
+ if (!IsValidSignalType(signal_type)) {
+ LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type);
+ return ResultInvalidEnumValue;
+ }
return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value,
count);
@@ -1725,20 +1823,28 @@ static ResultCode CloseHandle32(Core::System& system, Handle handle) {
static ResultCode ResetSignal(Core::System& system, Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
+ // Get the current handle table.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- auto event = handle_table.Get<ReadableEvent>(handle);
- if (event) {
- return event->Reset();
+ // Try to reset as readable event.
+ {
+ auto readable_event = handle_table.Get<KReadableEvent>(handle);
+ if (readable_event) {
+ return readable_event->Reset();
+ }
}
- auto process = handle_table.Get<Process>(handle);
- if (process) {
- return process->ClearSignalState();
+ // Try to reset as process.
+ {
+ auto process = handle_table.Get<Process>(handle);
+ if (process) {
+ return process->Reset();
+ }
}
- LOG_ERROR(Kernel_SVC, "Invalid handle (0x{:08X})", handle);
- return ERR_INVALID_HANDLE;
+ LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle);
+
+ return Svc::ResultInvalidHandle;
}
static ResultCode ResetSignal32(Core::System& system, Handle handle) {
@@ -1805,10 +1911,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
// Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
+ return ResultInvalidHandle;
+ }
// Get the core mask.
- R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
+ const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask);
+ if (result.IsError()) {
+ LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
+ return result;
+ }
return RESULT_SUCCESS;
}
@@ -1836,26 +1949,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
} else {
// Validate the affinity mask.
const u64 process_core_mask = current_process.GetCoreMask();
- R_UNLESS((affinity_mask | process_core_mask) == process_core_mask,
- Svc::ResultInvalidCoreId);
- R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination);
+ if ((affinity_mask | process_core_mask) != process_core_mask) {
+ LOG_ERROR(Kernel_SVC,
+ "Affinity mask does match the process core mask (affinity mask={:016X}, core "
+ "mask={:016X})",
+ affinity_mask, process_core_mask);
+ return ResultInvalidCoreId;
+ }
+ if (affinity_mask == 0) {
+ LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
+ return ResultInvalidCombination;
+ }
// Validate the core id.
if (IsValidCoreId(core_id)) {
- R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination);
+ if (((1ULL << core_id) & affinity_mask) == 0) {
+ LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
+ return ResultInvalidCombination;
+ }
} else {
- R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare,
- Svc::ResultInvalidCoreId);
+ if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) {
+ LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
+ return ResultInvalidCoreId;
+ }
}
}
// Get the thread from its handle.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- R_UNLESS(thread, Svc::ResultInvalidHandle);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
+ return ResultInvalidHandle;
+ }
// Set the core mask.
- R_TRY(thread->SetCoreMask(core_id, affinity_mask));
+ const auto set_result = thread->SetCoreMask(core_id, affinity_mask);
+ if (set_result.IsError()) {
+ LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
+ return set_result;
+ }
return RESULT_SUCCESS;
}
@@ -1866,80 +1999,98 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle
return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask);
}
-static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) {
- LOG_DEBUG(Kernel_SVC, "called");
-
- auto& kernel = system.Kernel();
- const auto [readable_event, writable_event] =
- WritableEvent::CreateEventPair(kernel, "CreateEvent");
+static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
+ LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
- HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
-
- const auto write_create_result = handle_table.Create(writable_event);
- if (write_create_result.Failed()) {
- return write_create_result.Code();
- }
- *write_handle = *write_create_result;
+ // Get the current handle table.
+ const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const auto read_create_result = handle_table.Create(readable_event);
- if (read_create_result.Failed()) {
- handle_table.Close(*write_create_result);
- return read_create_result.Code();
+ // Get the writable event.
+ auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
+ if (!writable_event) {
+ LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
+ return ResultInvalidHandle;
}
- *read_handle = *read_create_result;
- LOG_DEBUG(Kernel_SVC,
- "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}",
- *write_create_result, *read_create_result);
- return RESULT_SUCCESS;
+ return writable_event->Signal();
}
-static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) {
- return CreateEvent(system, write_handle, read_handle);
+static ResultCode SignalEvent32(Core::System& system, Handle event_handle) {
+ return SignalEvent(system, event_handle);
}
-static ResultCode ClearEvent(Core::System& system, Handle handle) {
- LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
+static ResultCode ClearEvent(Core::System& system, Handle event_handle) {
+ LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
+ // Get the current handle table.
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- auto writable_event = handle_table.Get<WritableEvent>(handle);
- if (writable_event) {
- writable_event->Clear();
- return RESULT_SUCCESS;
+ // Try to clear the writable event.
+ {
+ auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
+ if (writable_event) {
+ return writable_event->Clear();
+ }
}
- auto readable_event = handle_table.Get<ReadableEvent>(handle);
- if (readable_event) {
- readable_event->Clear();
- return RESULT_SUCCESS;
+ // Try to clear the readable event.
+ {
+ auto readable_event = handle_table.Get<KReadableEvent>(event_handle);
+ if (readable_event) {
+ return readable_event->Clear();
+ }
}
- LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle);
- return ERR_INVALID_HANDLE;
+ LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle);
+
+ return Svc::ResultInvalidHandle;
}
-static ResultCode ClearEvent32(Core::System& system, Handle handle) {
- return ClearEvent(system, handle);
+static ResultCode ClearEvent32(Core::System& system, Handle event_handle) {
+ return ClearEvent(system, event_handle);
}
-static ResultCode SignalEvent(Core::System& system, Handle handle) {
- LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle);
+static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
+ LOG_DEBUG(Kernel_SVC, "called");
+
+ // Get the kernel reference and handle table.
+ auto& kernel = system.Kernel();
+ HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
+
+ // Create a new event.
+ const auto event = KEvent::Create(kernel, "CreateEvent");
+ if (!event) {
+ LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
+ return ResultOutOfResource;
+ }
- HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- auto writable_event = handle_table.Get<WritableEvent>(handle);
+ // Initialize the event.
+ event->Initialize();
- if (!writable_event) {
- LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle);
- return ERR_INVALID_HANDLE;
+ // Add the writable event to the handle table.
+ const auto write_create_result = handle_table.Create(event->GetWritableEvent());
+ if (write_create_result.Failed()) {
+ return write_create_result.Code();
+ }
+ *out_write = *write_create_result;
+
+ // Add the writable event to the handle table.
+ auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); });
+
+ // Add the readable event to the handle table.
+ const auto read_create_result = handle_table.Create(event->GetReadableEvent());
+ if (read_create_result.Failed()) {
+ return read_create_result.Code();
}
+ *out_read = *read_create_result;
- writable_event->Signal();
+ // We succeeded.
+ handle_guard.Cancel();
return RESULT_SUCCESS;
}
-static ResultCode SignalEvent32(Core::System& system, Handle handle) {
- return SignalEvent(system, handle);
+static ResultCode CreateEvent32(Core::System& system, Handle* out_write, Handle* out_read) {
+ return CreateEvent(system, out_write, out_read);
}
static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) {