From b35380a9425e9d8793dd327e3a8c82daa3659e30 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 14 Jul 2020 02:45:06 -0700 Subject: [PATCH] kern: implement SvcCreateEvent, SvcSignalEvent, SvcClearEvent, SvcResetSignal --- .../include/mesosphere/kern_k_process.hpp | 2 + .../libmesosphere/source/kern_k_process.cpp | 16 ++++ .../source/svc/kern_svc_event.cpp | 83 +++++++++++++++++-- .../source/svc/kern_svc_synchronization.cpp | 27 +++++- .../source/svc/kern_svc_thread.cpp | 2 +- 5 files changed, 121 insertions(+), 9 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index dec9af3fc..a730aef4d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -207,6 +207,8 @@ namespace ams::kern { Result Run(s32 priority, size_t stack_size); + Result Reset(); + void SetPreemptionState(); Result SignalToAddress(KProcessAddress address) { diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 4985fa0f9..1cad4f091 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -435,6 +435,22 @@ namespace ams::kern { return ResultSuccess(); } + Result KProcess::Reset() { + MESOSPHERE_ASSERT_THIS(); + + /* Lock the process and the scheduler. */ + KScopedLightLock lk(this->state_lock); + KScopedSchedulerLock sl; + + /* Validate that we're in a state that we can reset. */ + R_UNLESS(this->state != State_Terminated, svc::ResultInvalidState()); + R_UNLESS(this->is_signaled, svc::ResultInvalidState()); + + /* Clear signaled. */ + this->is_signaled = false; + return ResultSuccess(); + } + void KProcess::SetPreemptionState() { MESOSPHERE_UNIMPLEMENTED(); } diff --git a/libraries/libmesosphere/source/svc/kern_svc_event.cpp b/libraries/libmesosphere/source/svc/kern_svc_event.cpp index 77aead4d5..2abd7cea7 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_event.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_event.cpp @@ -21,36 +21,107 @@ namespace ams::kern::svc { namespace { + Result SignalEvent(ams::svc::Handle event_handle) { + /* Get the current handle table. */ + auto &handle_table = GetCurrentProcess().GetHandleTable(); + /* Get the writable event. */ + KScopedAutoObject writable_event = handle_table.GetObject(event_handle); + R_UNLESS(writable_event.IsNotNull(), svc::ResultInvalidHandle()); + + return writable_event->Signal(); + } + + Result ClearEvent(ams::svc::Handle event_handle) { + /* Get the current handle table. */ + auto &handle_table = GetCurrentProcess().GetHandleTable(); + + /* Try to clear the writable event. */ + { + KScopedAutoObject writable_event = handle_table.GetObject(event_handle); + if (writable_event.IsNotNull()) { + return writable_event->Clear(); + } + } + + /* Try to clear the readable event. */ + { + KScopedAutoObject readable_event = handle_table.GetObject(event_handle); + if (readable_event.IsNotNull()) { + return readable_event->Clear(); + } + } + + return svc::ResultInvalidHandle(); + } + + Result CreateEvent(ams::svc::Handle *out_write, ams::svc::Handle *out_read) { + /* Get the current process and handle table. */ + auto &process = GetCurrentProcess(); + auto &handle_table = process.GetHandleTable(); + + /* Reserve a new event from the process resource limit. */ + KScopedResourceReservation event_reservation(std::addressof(process), ams::svc::LimitableResource_EventCountMax); + R_UNLESS(event_reservation.Succeeded(), svc::ResultLimitReached()); + + /* Create a new event. */ + KEvent *event = KEvent::Create(); + R_UNLESS(event != nullptr, svc::ResultOutOfResource()); + + /* Initialize the event. */ + event->Initialize(); + + /* Ensure that we clean up the event (and its only references are handle table) on function end. */ + ON_SCOPE_EXIT { + event->GetWritableEvent().Close(); + event->GetReadableEvent().Close(); + }; + + /* Register the event. */ + R_TRY(KEvent::Register(event)); + + /* Add the writable event to the handle table. */ + R_TRY(handle_table.Add(out_write, std::addressof(event->GetWritableEvent()))); + + /* Ensure that we maintaing a clean handle state on exit. */ + auto handle_guard = SCOPE_GUARD { handle_table.Remove(*out_write); }; + + /* Add the readable event to the handle table. */ + R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent()))); + + /* We succeeded! */ + handle_guard.Cancel(); + return ResultSuccess(); + } } /* ============================= 64 ABI ============================= */ Result SignalEvent64(ams::svc::Handle event_handle) { - MESOSPHERE_PANIC("Stubbed SvcSignalEvent64 was called."); + return SignalEvent(event_handle); } Result ClearEvent64(ams::svc::Handle event_handle) { - MESOSPHERE_PANIC("Stubbed SvcClearEvent64 was called."); + return ClearEvent(event_handle); } Result CreateEvent64(ams::svc::Handle *out_write_handle, ams::svc::Handle *out_read_handle) { - MESOSPHERE_PANIC("Stubbed SvcCreateEvent64 was called."); + return CreateEvent(out_write_handle, out_read_handle); } /* ============================= 64From32 ABI ============================= */ Result SignalEvent64From32(ams::svc::Handle event_handle) { - MESOSPHERE_PANIC("Stubbed SvcSignalEvent64From32 was called."); + return SignalEvent(event_handle); } Result ClearEvent64From32(ams::svc::Handle event_handle) { - MESOSPHERE_PANIC("Stubbed SvcClearEvent64From32 was called."); + return ClearEvent(event_handle); } Result CreateEvent64From32(ams::svc::Handle *out_write_handle, ams::svc::Handle *out_read_handle) { - MESOSPHERE_PANIC("Stubbed SvcCreateEvent64From32 was called."); + return CreateEvent(out_write_handle, out_read_handle); } } diff --git a/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp b/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp index 8e2c1524e..755cd6064 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp @@ -27,6 +27,29 @@ namespace ams::kern::svc { return ResultSuccess(); } + Result ResetSignal(ams::svc::Handle handle) { + /* Get the current handle table. */ + auto &handle_table = GetCurrentProcess().GetHandleTable(); + + /* Try to reset as readable event. */ + { + KScopedAutoObject readable_event = handle_table.GetObject(handle); + if (readable_event.IsNotNull()) { + return readable_event->Reset(); + } + } + + /* Try to reset as process. */ + { + KScopedAutoObject process = handle_table.GetObject(handle); + if (process.IsNotNull()) { + return process->Reset(); + } + } + + return svc::ResultInvalidHandle(); + } + Result WaitSynchronizationImpl(int32_t *out_index, KSynchronizationObject **objs, int32_t num_handles, int64_t timeout_ns) { /* Convert the timeout from nanoseconds to ticks. */ s64 timeout; @@ -88,7 +111,7 @@ namespace ams::kern::svc { } Result ResetSignal64(ams::svc::Handle handle) { - MESOSPHERE_PANIC("Stubbed SvcResetSignal64 was called."); + return ResetSignal(handle); } Result WaitSynchronization64(int32_t *out_index, KUserPointer handles, int32_t num_handles, int64_t timeout_ns) { @@ -112,7 +135,7 @@ namespace ams::kern::svc { } Result ResetSignal64From32(ams::svc::Handle handle) { - MESOSPHERE_PANIC("Stubbed SvcResetSignal64From32 was called."); + return ResetSignal(handle); } Result WaitSynchronization64From32(int32_t *out_index, KUserPointer handles, int32_t num_handles, int64_t timeout_ns) { diff --git a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp index 19238f717..b74200471 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp @@ -39,7 +39,7 @@ namespace ams::kern::svc { R_UNLESS(ams::svc::HighestThreadPriority <= priority && priority <= ams::svc::LowestThreadPriority, svc::ResultInvalidPriority()); R_UNLESS(process.CheckThreadPriority(priority), svc::ResultInvalidPriority()); - /* Reserve a new session from the process resource limit (waiting up to 100ms). */ + /* Reserve a new thread from the process resource limit (waiting up to 100ms). */ KScopedResourceReservation thread_reservation(std::addressof(process), ams::svc::LimitableResource_ThreadCountMax, 1, KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromMilliSeconds(100))); R_UNLESS(thread_reservation.Succeeded(), svc::ResultLimitReached());