diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 4f410ad03..bb035805f 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -175,6 +175,8 @@ namespace ams::kern { const ThreadList &GetThreadList() const { return this->thread_list; } KProcess::State SetDebugObject(void *debug_object); + void ClearDebugObject(KProcess::State state); + KEventInfo *GetJitDebugInfo(); bool EnterUserException(); diff --git a/libraries/libmesosphere/source/kern_k_debug_base.cpp b/libraries/libmesosphere/source/kern_k_debug_base.cpp index 59b527013..f63b2955e 100644 --- a/libraries/libmesosphere/source/kern_k_debug_base.cpp +++ b/libraries/libmesosphere/source/kern_k_debug_base.cpp @@ -358,7 +358,65 @@ namespace ams::kern { } void KDebugBase::OnFinalizeSynchronizationObject() { - MESOSPHERE_UNIMPLEMENTED(); + /* Detach from our process, if we have one. */ + { + /* Get the attached process. */ + KScopedAutoObject process = this->GetProcess(); + + /* If the process isn't null, detach. */ + if (process.IsNotNull()) { + /* When we're done detaching, clear the reference we opened when we attached. */ + ON_SCOPE_EXIT { process->Close(); }; + + /* Detach. */ + { + /* Lock both ourselves and the target process. */ + KScopedLightLock state_lk(process->GetStateLock()); + KScopedLightLock list_lk(process->GetListLock()); + KScopedLightLock this_lk(this->lock); + + /* Ensure we finalize exactly once. */ + if (this->process != nullptr) { + MESOSPHERE_ASSERT(this->process == process.GetPointerUnsafe()); + { + KScopedSchedulerLock sl; + + /* Detach ourselves from the process. */ + process->ClearDebugObject(this->old_process_state); + + /* Release all threads. */ + const bool resume = (process->GetState() != KProcess::State_Crashed); + { + auto end = process->GetThreadList().end(); + for (auto it = process->GetThreadList().begin(); it != end; ++it) { + if (resume) { + /* If the process isn't crashed, resume threads. */ + it->Resume(KThread::SuspendType_Debug); + } else { + /* Otherwise, suspend them. */ + it->RequestSuspend(KThread::SuspendType_Debug); + } + } + } + + /* Clear our process. */ + this->process = nullptr; + } + } + } + } + } + + /* Free any pending events. */ + { + KScopedSchedulerLock sl; + + while (!this->event_info_list.empty()) { + KEventInfo *info = std::addressof(this->event_info_list.front()); + this->event_info_list.pop_front(); + KEventInfo::Free(info); + } + } } bool KDebugBase::IsSignaled() const { diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 9725478e2..b2424ec70 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -452,24 +452,53 @@ namespace ams::kern { } KProcess::State KProcess::SetDebugObject(void *debug_object) { + /* Attaching should only happen to non-null objects while the scheduler is locked. */ + MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); + MESOSPHERE_ASSERT(debug_object != nullptr); + /* Cache our state to return it to the debug object. */ const auto old_state = this->state; /* Set the object. */ this->attached_object = debug_object; + /* Check that our state is valid for attach. */ + MESOSPHERE_ASSERT(this->state == State_Created || this->state == State_Running || this->state == State_Crashed); + /* Update our state. */ if (this->state != State_DebugBreak) { - this->state = (this->state != State_Created) ? State_DebugBreak : State_CreatedAttached; - - /* Signal. */ - this->is_signaled = true; - this->NotifyAvailable(); + if (this->state == State_Created) { + this->ChangeState(State_CreatedAttached); + } else { + this->ChangeState(State_DebugBreak); + } } return old_state; } + void KProcess::ClearDebugObject(KProcess::State old_state) { + /* Detaching from process should only happen while the scheduler is locked. */ + MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); + + /* Clear the attached object. */ + this->attached_object = nullptr; + + /* Validate that the process is in an attached state. */ + MESOSPHERE_ASSERT(this->state == State_CreatedAttached || this->state == State_RunningAttached || this->state == State_DebugBreak || this->state == State_Terminating || this->state == State_Terminated); + + /* Change the state appropriately. */ + if (this->state == State_CreatedAttached) { + this->ChangeState(State_Created); + } else if (this->state == State_RunningAttached || this->state == State_DebugBreak) { + /* Disallow transition back to created from running. */ + if (old_state == State_Created) { + old_state = State_Running; + } + this->ChangeState(old_state); + } + } + KEventInfo *KProcess::GetJitDebugInfo() { if (this->is_jit_debug) { return KDebugBase::CreateDebugEvent(this->jit_debug_event_type, this->jit_debug_exception_type, this->jit_debug_params[0], this->jit_debug_params[1], this->jit_debug_params[2], this->jit_debug_params[3], this->jit_debug_thread_id); diff --git a/libraries/libmesosphere/source/svc/kern_svc_event.cpp b/libraries/libmesosphere/source/svc/kern_svc_event.cpp index 2abd7cea7..4a2f68eff 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_event.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_event.cpp @@ -71,6 +71,9 @@ namespace ams::kern::svc { /* Initialize the event. */ event->Initialize(); + /* Commit the event reservation. */ + event_reservation.Commit(); + /* Ensure that we clean up the event (and its only references are handle table) on function end. */ ON_SCOPE_EXIT { event->GetWritableEvent().Close(); diff --git a/libraries/libmesosphere/source/svc/kern_svc_session.cpp b/libraries/libmesosphere/source/svc/kern_svc_session.cpp index 55ab32647..8b70dd29c 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_session.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_session.cpp @@ -21,6 +21,57 @@ namespace ams::kern::svc { namespace { + template + Result CreateSession(ams::svc::Handle *out_server, ams::svc::Handle *out_client, uintptr_t name) { + /* Get the current process and handle table. */ + auto &process = GetCurrentProcess(); + auto &handle_table = process.GetHandleTable(); + + /* Reserve a new session from the process resource limit. */ + KScopedResourceReservation session_reservation(std::addressof(process), ams::svc::LimitableResource_SessionCountMax); + R_UNLESS(session_reservation.Succeeded(), svc::ResultLimitReached()); + + /* Create a new session. */ + T *session = T::Create(); + R_UNLESS(session != nullptr, svc::ResultOutOfResource()); + + /* Initialize the session. */ + session->Initialize(nullptr, name); + + /* Commit the session reservation. */ + session_reservation.Commit(); + + /* Ensure that we clean up the session (and its only references are handle table) on function end. */ + ON_SCOPE_EXIT { + session->GetServerSession().Close(); + session->GetClientSession().Close(); + }; + + /* Register the session. */ + R_TRY(T::Register(session)); + + /* Add the server session to the handle table. */ + R_TRY(handle_table.Add(out_server, std::addressof(session->GetServerSession()))); + + /* Ensure that we maintaing a clean handle state on exit. */ + auto handle_guard = SCOPE_GUARD { handle_table.Remove(*out_server); }; + + /* Add the client session to the handle table. */ + R_TRY(handle_table.Add(out_client, std::addressof(session->GetClientSession()))); + + /* We succeeded! */ + handle_guard.Cancel(); + return ResultSuccess(); + } + + Result CreateSession(ams::svc::Handle *out_server, ams::svc::Handle *out_client, bool is_light, uintptr_t name) { + if (is_light) { + return CreateSession(out_server, out_client, name); + } else { + return CreateSession(out_server, out_client, name); + } + } + Result AcceptSession(ams::svc::Handle *out, ams::svc::Handle port_handle) { /* Get the current handle table. */ auto &handle_table = GetCurrentProcess().GetHandleTable(); @@ -57,7 +108,7 @@ namespace ams::kern::svc { /* ============================= 64 ABI ============================= */ Result CreateSession64(ams::svc::Handle *out_server_session_handle, ams::svc::Handle *out_client_session_handle, bool is_light, ams::svc::Address name) { - MESOSPHERE_PANIC("Stubbed SvcCreateSession64 was called."); + return CreateSession(out_server_session_handle, out_client_session_handle, is_light, name); } Result AcceptSession64(ams::svc::Handle *out_handle, ams::svc::Handle port) { @@ -67,7 +118,7 @@ namespace ams::kern::svc { /* ============================= 64From32 ABI ============================= */ Result CreateSession64From32(ams::svc::Handle *out_server_session_handle, ams::svc::Handle *out_client_session_handle, bool is_light, ams::svc::Address name) { - MESOSPHERE_PANIC("Stubbed SvcCreateSession64From32 was called."); + return CreateSession(out_server_session_handle, out_client_session_handle, is_light, name); } Result AcceptSession64From32(ams::svc::Handle *out_handle, ams::svc::Handle port) {