diff options
| author | 2023-12-06 19:54:52 -0500 | |
|---|---|---|
| committer | 2023-12-07 09:13:43 -0500 | |
| commit | 9268f265a1207f0cddb97a908a1cc349f9b6410b (patch) | |
| tree | 5da6aea714523b3504b78362c5d8abd53689d72f /src | |
| parent | Merge pull request #12236 from liamwhite/cpu-refactor (diff) | |
| download | yuzu-9268f265a1207f0cddb97a908a1cc349f9b6410b.tar.gz yuzu-9268f265a1207f0cddb97a908a1cc349f9b6410b.tar.xz yuzu-9268f265a1207f0cddb97a908a1cc349f9b6410b.zip | |
kernel: implement light IPC
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_port.cpp | 69 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_port.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_light_client_session.cpp | 31 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_light_client_session.h | 39 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_light_server_session.cpp | 247 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_light_server_session.h | 49 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_light_session.cpp | 81 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_light_session.h | 86 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_port.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_port.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_port.cpp | 56 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_port.h | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 7 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc/svc_light_ipc.cpp | 29 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc/svc_port.cpp | 71 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc/svc_session.cpp | 40 |
18 files changed, 813 insertions, 20 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e2120bdfe..05c103f51 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -251,10 +251,16 @@ add_library(core STATIC | |||
| 251 | hle/kernel/k_hardware_timer.h | 251 | hle/kernel/k_hardware_timer.h |
| 252 | hle/kernel/k_interrupt_manager.cpp | 252 | hle/kernel/k_interrupt_manager.cpp |
| 253 | hle/kernel/k_interrupt_manager.h | 253 | hle/kernel/k_interrupt_manager.h |
| 254 | hle/kernel/k_light_client_session.cpp | ||
| 255 | hle/kernel/k_light_client_session.h | ||
| 254 | hle/kernel/k_light_condition_variable.cpp | 256 | hle/kernel/k_light_condition_variable.cpp |
| 255 | hle/kernel/k_light_condition_variable.h | 257 | hle/kernel/k_light_condition_variable.h |
| 256 | hle/kernel/k_light_lock.cpp | 258 | hle/kernel/k_light_lock.cpp |
| 257 | hle/kernel/k_light_lock.h | 259 | hle/kernel/k_light_lock.h |
| 260 | hle/kernel/k_light_server_session.cpp | ||
| 261 | hle/kernel/k_light_server_session.h | ||
| 262 | hle/kernel/k_light_session.cpp | ||
| 263 | hle/kernel/k_light_session.h | ||
| 258 | hle/kernel/k_memory_block.h | 264 | hle/kernel/k_memory_block.h |
| 259 | hle/kernel/k_memory_block_manager.cpp | 265 | hle/kernel/k_memory_block_manager.cpp |
| 260 | hle/kernel/k_memory_block_manager.h | 266 | hle/kernel/k_memory_block_manager.h |
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index 40e09e532..11b1b977e 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/scope_exit.h" | 4 | #include "common/scope_exit.h" |
| 5 | #include "core/hle/kernel/k_client_port.h" | 5 | #include "core/hle/kernel/k_client_port.h" |
| 6 | #include "core/hle/kernel/k_light_session.h" | ||
| 6 | #include "core/hle/kernel/k_port.h" | 7 | #include "core/hle/kernel/k_port.h" |
| 7 | #include "core/hle/kernel/k_scheduler.h" | 8 | #include "core/hle/kernel/k_scheduler.h" |
| 8 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | 9 | #include "core/hle/kernel/k_scoped_resource_reservation.h" |
| @@ -63,6 +64,7 @@ Result KClientPort::CreateSession(KClientSession** out) { | |||
| 63 | R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); | 64 | R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); |
| 64 | 65 | ||
| 65 | // Allocate a session normally. | 66 | // Allocate a session normally. |
| 67 | // TODO: Dynamic resource limits | ||
| 66 | session = KSession::Create(m_kernel); | 68 | session = KSession::Create(m_kernel); |
| 67 | 69 | ||
| 68 | // Check that we successfully created a session. | 70 | // Check that we successfully created a session. |
| @@ -119,4 +121,71 @@ Result KClientPort::CreateSession(KClientSession** out) { | |||
| 119 | R_SUCCEED(); | 121 | R_SUCCEED(); |
| 120 | } | 122 | } |
| 121 | 123 | ||
| 124 | Result KClientPort::CreateLightSession(KLightClientSession** out) { | ||
| 125 | // Declare the session we're going to allocate. | ||
| 126 | KLightSession* session{}; | ||
| 127 | |||
| 128 | // Reserve a new session from the resource limit. | ||
| 129 | KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel), | ||
| 130 | Svc::LimitableResource::SessionCountMax); | ||
| 131 | R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); | ||
| 132 | |||
| 133 | // Allocate a session normally. | ||
| 134 | // TODO: Dynamic resource limits | ||
| 135 | session = KLightSession::Create(m_kernel); | ||
| 136 | |||
| 137 | // Check that we successfully created a session. | ||
| 138 | R_UNLESS(session != nullptr, ResultOutOfResource); | ||
| 139 | |||
| 140 | // Update the session counts. | ||
| 141 | { | ||
| 142 | ON_RESULT_FAILURE { | ||
| 143 | session->Close(); | ||
| 144 | }; | ||
| 145 | |||
| 146 | // Atomically increment the number of sessions. | ||
| 147 | s32 new_sessions; | ||
| 148 | { | ||
| 149 | const auto max = m_max_sessions; | ||
| 150 | auto cur_sessions = m_num_sessions.load(std::memory_order_acquire); | ||
| 151 | do { | ||
| 152 | R_UNLESS(cur_sessions < max, ResultOutOfSessions); | ||
| 153 | new_sessions = cur_sessions + 1; | ||
| 154 | } while (!m_num_sessions.compare_exchange_weak(cur_sessions, new_sessions, | ||
| 155 | std::memory_order_relaxed)); | ||
| 156 | } | ||
| 157 | |||
| 158 | // Atomically update the peak session tracking. | ||
| 159 | { | ||
| 160 | auto peak = m_peak_sessions.load(std::memory_order_acquire); | ||
| 161 | do { | ||
| 162 | if (peak >= new_sessions) { | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | } while (!m_peak_sessions.compare_exchange_weak(peak, new_sessions, | ||
| 166 | std::memory_order_relaxed)); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | // Initialize the session. | ||
| 171 | session->Initialize(this, m_parent->GetName()); | ||
| 172 | |||
| 173 | // Commit the session reservation. | ||
| 174 | session_reservation.Commit(); | ||
| 175 | |||
| 176 | // Register the session. | ||
| 177 | KLightSession::Register(m_kernel, session); | ||
| 178 | ON_RESULT_FAILURE { | ||
| 179 | session->GetClientSession().Close(); | ||
| 180 | session->GetServerSession().Close(); | ||
| 181 | }; | ||
| 182 | |||
| 183 | // Enqueue the session with our parent. | ||
| 184 | R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession()))); | ||
| 185 | |||
| 186 | // We succeeded, so set the output. | ||
| 187 | *out = std::addressof(session->GetClientSession()); | ||
| 188 | R_SUCCEED(); | ||
| 189 | } | ||
| 190 | |||
| 122 | } // namespace Kernel | 191 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index 23db06ddf..28b332608 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| 14 | class KLightClientSession; | ||
| 14 | class KClientSession; | 15 | class KClientSession; |
| 15 | class KernelCore; | 16 | class KernelCore; |
| 16 | class KPort; | 17 | class KPort; |
| @@ -51,6 +52,7 @@ public: | |||
| 51 | bool IsSignaled() const override; | 52 | bool IsSignaled() const override; |
| 52 | 53 | ||
| 53 | Result CreateSession(KClientSession** out); | 54 | Result CreateSession(KClientSession** out); |
| 55 | Result CreateLightSession(KLightClientSession** out); | ||
| 54 | 56 | ||
| 55 | private: | 57 | private: |
| 56 | std::atomic<s32> m_num_sessions{}; | 58 | std::atomic<s32> m_num_sessions{}; |
diff --git a/src/core/hle/kernel/k_light_client_session.cpp b/src/core/hle/kernel/k_light_client_session.cpp new file mode 100644 index 000000000..8ce3e1ae4 --- /dev/null +++ b/src/core/hle/kernel/k_light_client_session.cpp | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_light_client_session.h" | ||
| 5 | #include "core/hle/kernel/k_light_session.h" | ||
| 6 | #include "core/hle/kernel/k_thread.h" | ||
| 7 | |||
| 8 | namespace Kernel { | ||
| 9 | |||
| 10 | KLightClientSession::KLightClientSession(KernelCore& kernel) : KAutoObject(kernel) {} | ||
| 11 | |||
| 12 | KLightClientSession::~KLightClientSession() = default; | ||
| 13 | |||
| 14 | void KLightClientSession::Destroy() { | ||
| 15 | m_parent->OnClientClosed(); | ||
| 16 | } | ||
| 17 | |||
| 18 | void KLightClientSession::OnServerClosed() {} | ||
| 19 | |||
| 20 | Result KLightClientSession::SendSyncRequest(u32* data) { | ||
| 21 | // Get the request thread. | ||
| 22 | KThread* cur_thread = GetCurrentThreadPointer(m_kernel); | ||
| 23 | |||
| 24 | // Set the light data. | ||
| 25 | cur_thread->SetLightSessionData(data); | ||
| 26 | |||
| 27 | // Send the request. | ||
| 28 | R_RETURN(m_parent->OnRequest(cur_thread)); | ||
| 29 | } | ||
| 30 | |||
| 31 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_client_session.h b/src/core/hle/kernel/k_light_client_session.h new file mode 100644 index 000000000..881a15cbd --- /dev/null +++ b/src/core/hle/kernel/k_light_client_session.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/kernel/k_auto_object.h" | ||
| 7 | #include "core/hle/result.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | class KLightSession; | ||
| 12 | |||
| 13 | class KLightClientSession final : public KAutoObject { | ||
| 14 | KERNEL_AUTOOBJECT_TRAITS(KLightClientSession, KAutoObject); | ||
| 15 | |||
| 16 | public: | ||
| 17 | explicit KLightClientSession(KernelCore& kernel); | ||
| 18 | ~KLightClientSession(); | ||
| 19 | |||
| 20 | void Initialize(KLightSession* parent) { | ||
| 21 | // Set member variables. | ||
| 22 | m_parent = parent; | ||
| 23 | } | ||
| 24 | |||
| 25 | virtual void Destroy() override; | ||
| 26 | |||
| 27 | const KLightSession* GetParent() const { | ||
| 28 | return m_parent; | ||
| 29 | } | ||
| 30 | |||
| 31 | Result SendSyncRequest(u32* data); | ||
| 32 | |||
| 33 | void OnServerClosed(); | ||
| 34 | |||
| 35 | private: | ||
| 36 | KLightSession* m_parent; | ||
| 37 | }; | ||
| 38 | |||
| 39 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_server_session.cpp b/src/core/hle/kernel/k_light_server_session.cpp new file mode 100644 index 000000000..e5ceb01f2 --- /dev/null +++ b/src/core/hle/kernel/k_light_server_session.cpp | |||
| @@ -0,0 +1,247 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_light_server_session.h" | ||
| 5 | #include "core/hle/kernel/k_light_session.h" | ||
| 6 | #include "core/hle/kernel/k_thread.h" | ||
| 7 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 8 | #include "core/hle/kernel/svc_results.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | |||
| 14 | constexpr u64 InvalidThreadId = std::numeric_limits<u64>::max(); | ||
| 15 | |||
| 16 | class ThreadQueueImplForKLightServerSessionRequest final : public KThreadQueue { | ||
| 17 | private: | ||
| 18 | KThread::WaiterList* m_wait_list; | ||
| 19 | |||
| 20 | public: | ||
| 21 | ThreadQueueImplForKLightServerSessionRequest(KernelCore& kernel, KThread::WaiterList* wl) | ||
| 22 | : KThreadQueue(kernel), m_wait_list(wl) {} | ||
| 23 | |||
| 24 | virtual void EndWait(KThread* waiting_thread, Result wait_result) override { | ||
| 25 | // Remove the thread from our wait list. | ||
| 26 | m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); | ||
| 27 | |||
| 28 | // Invoke the base end wait handler. | ||
| 29 | KThreadQueue::EndWait(waiting_thread, wait_result); | ||
| 30 | } | ||
| 31 | |||
| 32 | virtual void CancelWait(KThread* waiting_thread, Result wait_result, | ||
| 33 | bool cancel_timer_task) override { | ||
| 34 | // Remove the thread from our wait list. | ||
| 35 | m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); | ||
| 36 | |||
| 37 | // Invoke the base cancel wait handler. | ||
| 38 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 39 | } | ||
| 40 | }; | ||
| 41 | |||
| 42 | class ThreadQueueImplForKLightServerSessionReceive final : public KThreadQueue { | ||
| 43 | private: | ||
| 44 | KThread** m_server_thread; | ||
| 45 | |||
| 46 | public: | ||
| 47 | ThreadQueueImplForKLightServerSessionReceive(KernelCore& kernel, KThread** st) | ||
| 48 | : KThreadQueue(kernel), m_server_thread(st) {} | ||
| 49 | |||
| 50 | virtual void EndWait(KThread* waiting_thread, Result wait_result) override { | ||
| 51 | // Clear the server thread. | ||
| 52 | *m_server_thread = nullptr; | ||
| 53 | |||
| 54 | // Set the waiting thread as not cancelable. | ||
| 55 | waiting_thread->ClearCancellable(); | ||
| 56 | |||
| 57 | // Invoke the base end wait handler. | ||
| 58 | KThreadQueue::EndWait(waiting_thread, wait_result); | ||
| 59 | } | ||
| 60 | |||
| 61 | virtual void CancelWait(KThread* waiting_thread, Result wait_result, | ||
| 62 | bool cancel_timer_task) override { | ||
| 63 | // Clear the server thread. | ||
| 64 | *m_server_thread = nullptr; | ||
| 65 | |||
| 66 | // Set the waiting thread as not cancelable. | ||
| 67 | waiting_thread->ClearCancellable(); | ||
| 68 | |||
| 69 | // Invoke the base cancel wait handler. | ||
| 70 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 71 | } | ||
| 72 | }; | ||
| 73 | |||
| 74 | } // namespace | ||
| 75 | |||
| 76 | KLightServerSession::KLightServerSession(KernelCore& kernel) : KAutoObject(kernel) {} | ||
| 77 | KLightServerSession::~KLightServerSession() = default; | ||
| 78 | |||
| 79 | void KLightServerSession::Destroy() { | ||
| 80 | this->CleanupRequests(); | ||
| 81 | |||
| 82 | m_parent->OnServerClosed(); | ||
| 83 | } | ||
| 84 | |||
| 85 | void KLightServerSession::OnClientClosed() { | ||
| 86 | this->CleanupRequests(); | ||
| 87 | } | ||
| 88 | |||
| 89 | Result KLightServerSession::OnRequest(KThread* request_thread) { | ||
| 90 | ThreadQueueImplForKLightServerSessionRequest wait_queue(m_kernel, | ||
| 91 | std::addressof(m_request_list)); | ||
| 92 | |||
| 93 | // Send the request. | ||
| 94 | { | ||
| 95 | // Lock the scheduler. | ||
| 96 | KScopedSchedulerLock sl(m_kernel); | ||
| 97 | |||
| 98 | // Check that the server isn't closed. | ||
| 99 | R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed); | ||
| 100 | |||
| 101 | // Check that the request thread isn't terminating. | ||
| 102 | R_UNLESS(!request_thread->IsTerminationRequested(), ResultTerminationRequested); | ||
| 103 | |||
| 104 | // Add the request thread to our list. | ||
| 105 | m_request_list.push_back(*request_thread); | ||
| 106 | |||
| 107 | // Begin waiting on the request. | ||
| 108 | request_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); | ||
| 109 | request_thread->BeginWait(std::addressof(wait_queue)); | ||
| 110 | |||
| 111 | // If we have a server thread, end its wait. | ||
| 112 | if (m_server_thread != nullptr) { | ||
| 113 | m_server_thread->EndWait(ResultSuccess); | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | // NOTE: Nintendo returns GetCurrentThread().GetWaitResult() here. | ||
| 118 | // This is technically incorrect, although it doesn't cause problems in practice | ||
| 119 | // because this is only ever called with request_thread = GetCurrentThreadPointer(). | ||
| 120 | R_RETURN(request_thread->GetWaitResult()); | ||
| 121 | } | ||
| 122 | |||
| 123 | Result KLightServerSession::ReplyAndReceive(u32* data) { | ||
| 124 | // Set the server context. | ||
| 125 | GetCurrentThread(m_kernel).SetLightSessionData(data); | ||
| 126 | |||
| 127 | // Reply, if we need to. | ||
| 128 | if (data[0] & KLightSession::ReplyFlag) { | ||
| 129 | KScopedSchedulerLock sl(m_kernel); | ||
| 130 | |||
| 131 | // Check that we're open. | ||
| 132 | R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed); | ||
| 133 | R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed); | ||
| 134 | |||
| 135 | // Check that we have a request to reply to. | ||
| 136 | R_UNLESS(m_current_request != nullptr, ResultInvalidState); | ||
| 137 | |||
| 138 | // Check that the server thread id is correct. | ||
| 139 | R_UNLESS(m_server_thread_id == GetCurrentThread(m_kernel).GetId(), ResultInvalidState); | ||
| 140 | |||
| 141 | // If we can reply, do so. | ||
| 142 | if (!m_current_request->IsTerminationRequested()) { | ||
| 143 | std::memcpy(m_current_request->GetLightSessionData(), | ||
| 144 | GetCurrentThread(m_kernel).GetLightSessionData(), KLightSession::DataSize); | ||
| 145 | m_current_request->EndWait(ResultSuccess); | ||
| 146 | } | ||
| 147 | |||
| 148 | // Close our current request. | ||
| 149 | m_current_request->Close(); | ||
| 150 | |||
| 151 | // Clear our current request. | ||
| 152 | m_current_request = nullptr; | ||
| 153 | m_server_thread_id = InvalidThreadId; | ||
| 154 | } | ||
| 155 | |||
| 156 | // Create the wait queue for our receive. | ||
| 157 | ThreadQueueImplForKLightServerSessionReceive wait_queue(m_kernel, | ||
| 158 | std::addressof(m_server_thread)); | ||
| 159 | |||
| 160 | // Receive. | ||
| 161 | while (true) { | ||
| 162 | // Try to receive a request. | ||
| 163 | { | ||
| 164 | KScopedSchedulerLock sl(m_kernel); | ||
| 165 | |||
| 166 | // Check that we aren't already receiving. | ||
| 167 | R_UNLESS(m_server_thread == nullptr, ResultInvalidState); | ||
| 168 | R_UNLESS(m_server_thread_id == InvalidThreadId, ResultInvalidState); | ||
| 169 | |||
| 170 | // Check that we're open. | ||
| 171 | R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed); | ||
| 172 | R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed); | ||
| 173 | |||
| 174 | // Check that we're not terminating. | ||
| 175 | R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(), | ||
| 176 | ResultTerminationRequested); | ||
| 177 | |||
| 178 | // If we have a request available, use it. | ||
| 179 | if (auto head = m_request_list.begin(); head != m_request_list.end()) { | ||
| 180 | // Set our current request. | ||
| 181 | m_current_request = std::addressof(*head); | ||
| 182 | m_current_request->Open(); | ||
| 183 | |||
| 184 | // Set our server thread id. | ||
| 185 | m_server_thread_id = GetCurrentThread(m_kernel).GetId(); | ||
| 186 | |||
| 187 | // Copy the client request data. | ||
| 188 | std::memcpy(GetCurrentThread(m_kernel).GetLightSessionData(), | ||
| 189 | m_current_request->GetLightSessionData(), KLightSession::DataSize); | ||
| 190 | |||
| 191 | // We successfully received. | ||
| 192 | R_SUCCEED(); | ||
| 193 | } | ||
| 194 | |||
| 195 | // We need to wait for a request to come in. | ||
| 196 | |||
| 197 | // Check if we were cancelled. | ||
| 198 | if (GetCurrentThread(m_kernel).IsWaitCancelled()) { | ||
| 199 | GetCurrentThread(m_kernel).ClearWaitCancelled(); | ||
| 200 | R_THROW(ResultCancelled); | ||
| 201 | } | ||
| 202 | |||
| 203 | // Mark ourselves as cancellable. | ||
| 204 | GetCurrentThread(m_kernel).SetCancellable(); | ||
| 205 | |||
| 206 | // Wait for a request to come in. | ||
| 207 | m_server_thread = GetCurrentThreadPointer(m_kernel); | ||
| 208 | GetCurrentThread(m_kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); | ||
| 209 | GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue)); | ||
| 210 | } | ||
| 211 | |||
| 212 | // We waited to receive a request; if our wait failed, return the failing result. | ||
| 213 | R_TRY(GetCurrentThread(m_kernel).GetWaitResult()); | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | void KLightServerSession::CleanupRequests() { | ||
| 218 | // Cleanup all pending requests. | ||
| 219 | { | ||
| 220 | KScopedSchedulerLock sl(m_kernel); | ||
| 221 | |||
| 222 | // Handle the current request. | ||
| 223 | if (m_current_request != nullptr) { | ||
| 224 | // Reply to the current request. | ||
| 225 | if (!m_current_request->IsTerminationRequested()) { | ||
| 226 | m_current_request->EndWait(ResultSessionClosed); | ||
| 227 | } | ||
| 228 | |||
| 229 | // Clear our current request. | ||
| 230 | m_current_request->Close(); | ||
| 231 | m_current_request = nullptr; | ||
| 232 | m_server_thread_id = InvalidThreadId; | ||
| 233 | } | ||
| 234 | |||
| 235 | // Reply to all other requests. | ||
| 236 | for (auto& thread : m_request_list) { | ||
| 237 | thread.EndWait(ResultSessionClosed); | ||
| 238 | } | ||
| 239 | |||
| 240 | // Wait up our server thread, if we have one. | ||
| 241 | if (m_server_thread != nullptr) { | ||
| 242 | m_server_thread->EndWait(ResultSessionClosed); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_server_session.h b/src/core/hle/kernel/k_light_server_session.h new file mode 100644 index 000000000..8eca3eab6 --- /dev/null +++ b/src/core/hle/kernel/k_light_server_session.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/kernel/k_auto_object.h" | ||
| 7 | #include "core/hle/kernel/k_thread.h" | ||
| 8 | #include "core/hle/result.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | class KLightSession; | ||
| 13 | |||
| 14 | class KLightServerSession final : public KAutoObject, | ||
| 15 | public Common::IntrusiveListBaseNode<KLightServerSession> { | ||
| 16 | KERNEL_AUTOOBJECT_TRAITS(KLightServerSession, KAutoObject); | ||
| 17 | |||
| 18 | private: | ||
| 19 | KLightSession* m_parent{}; | ||
| 20 | KThread::WaiterList m_request_list{}; | ||
| 21 | KThread* m_current_request{}; | ||
| 22 | u64 m_server_thread_id{std::numeric_limits<u64>::max()}; | ||
| 23 | KThread* m_server_thread{}; | ||
| 24 | |||
| 25 | public: | ||
| 26 | explicit KLightServerSession(KernelCore& kernel); | ||
| 27 | ~KLightServerSession(); | ||
| 28 | |||
| 29 | void Initialize(KLightSession* parent) { | ||
| 30 | // Set member variables. */ | ||
| 31 | m_parent = parent; | ||
| 32 | } | ||
| 33 | |||
| 34 | virtual void Destroy() override; | ||
| 35 | |||
| 36 | constexpr const KLightSession* GetParent() const { | ||
| 37 | return m_parent; | ||
| 38 | } | ||
| 39 | |||
| 40 | Result OnRequest(KThread* request_thread); | ||
| 41 | Result ReplyAndReceive(u32* data); | ||
| 42 | |||
| 43 | void OnClientClosed(); | ||
| 44 | |||
| 45 | private: | ||
| 46 | void CleanupRequests(); | ||
| 47 | }; | ||
| 48 | |||
| 49 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_session.cpp b/src/core/hle/kernel/k_light_session.cpp new file mode 100644 index 000000000..d8b1e6958 --- /dev/null +++ b/src/core/hle/kernel/k_light_session.cpp | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/kernel/k_client_port.h" | ||
| 5 | #include "core/hle/kernel/k_light_client_session.h" | ||
| 6 | #include "core/hle/kernel/k_light_server_session.h" | ||
| 7 | #include "core/hle/kernel/k_light_session.h" | ||
| 8 | #include "core/hle/kernel/k_process.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | KLightSession::KLightSession(KernelCore& kernel) | ||
| 13 | : KAutoObjectWithSlabHeapAndContainer(kernel), m_server(kernel), m_client(kernel) {} | ||
| 14 | KLightSession::~KLightSession() = default; | ||
| 15 | |||
| 16 | void KLightSession::Initialize(KClientPort* client_port, uintptr_t name) { | ||
| 17 | // Increment reference count. | ||
| 18 | // Because reference count is one on creation, this will result | ||
| 19 | // in a reference count of two. Thus, when both server and client are closed | ||
| 20 | // this object will be destroyed. | ||
| 21 | this->Open(); | ||
| 22 | |||
| 23 | // Create our sub sessions. | ||
| 24 | KAutoObject::Create(std::addressof(m_server)); | ||
| 25 | KAutoObject::Create(std::addressof(m_client)); | ||
| 26 | |||
| 27 | // Initialize our sub sessions. | ||
| 28 | m_server.Initialize(this); | ||
| 29 | m_client.Initialize(this); | ||
| 30 | |||
| 31 | // Set state and name. | ||
| 32 | m_state = State::Normal; | ||
| 33 | m_name = name; | ||
| 34 | |||
| 35 | // Set our owner process. | ||
| 36 | m_process = GetCurrentProcessPointer(m_kernel); | ||
| 37 | m_process->Open(); | ||
| 38 | |||
| 39 | // Set our port. | ||
| 40 | m_port = client_port; | ||
| 41 | if (m_port != nullptr) { | ||
| 42 | m_port->Open(); | ||
| 43 | } | ||
| 44 | |||
| 45 | // Mark initialized. | ||
| 46 | m_initialized = true; | ||
| 47 | } | ||
| 48 | |||
| 49 | void KLightSession::Finalize() { | ||
| 50 | if (m_port != nullptr) { | ||
| 51 | m_port->OnSessionFinalized(); | ||
| 52 | m_port->Close(); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | void KLightSession::OnServerClosed() { | ||
| 57 | if (m_state == State::Normal) { | ||
| 58 | m_state = State::ServerClosed; | ||
| 59 | m_client.OnServerClosed(); | ||
| 60 | } | ||
| 61 | |||
| 62 | this->Close(); | ||
| 63 | } | ||
| 64 | |||
| 65 | void KLightSession::OnClientClosed() { | ||
| 66 | if (m_state == State::Normal) { | ||
| 67 | m_state = State::ClientClosed; | ||
| 68 | m_server.OnClientClosed(); | ||
| 69 | } | ||
| 70 | |||
| 71 | this->Close(); | ||
| 72 | } | ||
| 73 | |||
| 74 | void KLightSession::PostDestroy(uintptr_t arg) { | ||
| 75 | // Release the session count resource the owner process holds. | ||
| 76 | KProcess* owner = reinterpret_cast<KProcess*>(arg); | ||
| 77 | owner->ReleaseResource(Svc::LimitableResource::SessionCountMax, 1); | ||
| 78 | owner->Close(); | ||
| 79 | } | ||
| 80 | |||
| 81 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_session.h b/src/core/hle/kernel/k_light_session.h new file mode 100644 index 000000000..f78d8e689 --- /dev/null +++ b/src/core/hle/kernel/k_light_session.h | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/kernel/k_light_client_session.h" | ||
| 7 | #include "core/hle/kernel/k_light_server_session.h" | ||
| 8 | #include "core/hle/kernel/slab_helpers.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | class KClientPort; | ||
| 14 | class KProcess; | ||
| 15 | |||
| 16 | // TODO: SupportDynamicExpansion for SlabHeap | ||
| 17 | class KLightSession final | ||
| 18 | : public KAutoObjectWithSlabHeapAndContainer<KLightSession, KAutoObjectWithList> { | ||
| 19 | KERNEL_AUTOOBJECT_TRAITS(KLightSession, KAutoObject); | ||
| 20 | |||
| 21 | private: | ||
| 22 | enum class State : u8 { | ||
| 23 | Invalid = 0, | ||
| 24 | Normal = 1, | ||
| 25 | ClientClosed = 2, | ||
| 26 | ServerClosed = 3, | ||
| 27 | }; | ||
| 28 | |||
| 29 | public: | ||
| 30 | static constexpr size_t DataSize = sizeof(u32) * 7; | ||
| 31 | static constexpr u32 ReplyFlag = (1U << 31); | ||
| 32 | |||
| 33 | private: | ||
| 34 | KLightServerSession m_server; | ||
| 35 | KLightClientSession m_client; | ||
| 36 | State m_state{State::Invalid}; | ||
| 37 | KClientPort* m_port{}; | ||
| 38 | uintptr_t m_name{}; | ||
| 39 | KProcess* m_process{}; | ||
| 40 | bool m_initialized{}; | ||
| 41 | |||
| 42 | public: | ||
| 43 | explicit KLightSession(KernelCore& kernel); | ||
| 44 | ~KLightSession(); | ||
| 45 | |||
| 46 | void Initialize(KClientPort* client_port, uintptr_t name); | ||
| 47 | void Finalize() override; | ||
| 48 | |||
| 49 | bool IsInitialized() const override { | ||
| 50 | return m_initialized; | ||
| 51 | } | ||
| 52 | uintptr_t GetPostDestroyArgument() const override { | ||
| 53 | return reinterpret_cast<uintptr_t>(m_process); | ||
| 54 | } | ||
| 55 | |||
| 56 | static void PostDestroy(uintptr_t arg); | ||
| 57 | |||
| 58 | void OnServerClosed(); | ||
| 59 | void OnClientClosed(); | ||
| 60 | |||
| 61 | bool IsServerClosed() const { | ||
| 62 | return m_state != State::Normal; | ||
| 63 | } | ||
| 64 | bool IsClientClosed() const { | ||
| 65 | return m_state != State::Normal; | ||
| 66 | } | ||
| 67 | |||
| 68 | Result OnRequest(KThread* request_thread) { | ||
| 69 | R_RETURN(m_server.OnRequest(request_thread)); | ||
| 70 | } | ||
| 71 | |||
| 72 | KLightClientSession& GetClientSession() { | ||
| 73 | return m_client; | ||
| 74 | } | ||
| 75 | KLightServerSession& GetServerSession() { | ||
| 76 | return m_server; | ||
| 77 | } | ||
| 78 | const KLightClientSession& GetClientSession() const { | ||
| 79 | return m_client; | ||
| 80 | } | ||
| 81 | const KLightServerSession& GetServerSession() const { | ||
| 82 | return m_server; | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | |||
| 86 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index 1621ca1d3..e5f5d8028 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp | |||
| @@ -58,4 +58,13 @@ Result KPort::EnqueueSession(KServerSession* session) { | |||
| 58 | R_SUCCEED(); | 58 | R_SUCCEED(); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | Result KPort::EnqueueSession(KLightServerSession* session) { | ||
| 62 | KScopedSchedulerLock sl{m_kernel}; | ||
| 63 | |||
| 64 | R_UNLESS(m_state == State::Normal, ResultPortClosed); | ||
| 65 | |||
| 66 | m_server.EnqueueSession(session); | ||
| 67 | R_SUCCEED(); | ||
| 68 | } | ||
| 69 | |||
| 61 | } // namespace Kernel | 70 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h index 991be27ab..26f5f14ef 100644 --- a/src/core/hle/kernel/k_port.h +++ b/src/core/hle/kernel/k_port.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class KLightServerSession; | ||
| 16 | class KServerSession; | 17 | class KServerSession; |
| 17 | 18 | ||
| 18 | class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> { | 19 | class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> { |
| @@ -38,6 +39,7 @@ public: | |||
| 38 | bool IsServerClosed() const; | 39 | bool IsServerClosed() const; |
| 39 | 40 | ||
| 40 | Result EnqueueSession(KServerSession* session); | 41 | Result EnqueueSession(KServerSession* session); |
| 42 | Result EnqueueSession(KLightServerSession* session); | ||
| 41 | 43 | ||
| 42 | KClientPort& GetClientPort() { | 44 | KClientPort& GetClientPort() { |
| 43 | return m_client; | 45 | return m_client; |
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp index a29d34bc1..bb6632f58 100644 --- a/src/core/hle/kernel/k_server_port.cpp +++ b/src/core/hle/kernel/k_server_port.cpp | |||
| @@ -27,12 +27,14 @@ bool KServerPort::IsLight() const { | |||
| 27 | void KServerPort::CleanupSessions() { | 27 | void KServerPort::CleanupSessions() { |
| 28 | // Ensure our preconditions are met. | 28 | // Ensure our preconditions are met. |
| 29 | if (this->IsLight()) { | 29 | if (this->IsLight()) { |
| 30 | UNIMPLEMENTED(); | 30 | ASSERT(m_session_list.empty()); |
| 31 | } else { | ||
| 32 | ASSERT(m_light_session_list.empty()); | ||
| 31 | } | 33 | } |
| 32 | 34 | ||
| 33 | // Cleanup the session list. | 35 | // Cleanup the session list. |
| 34 | while (true) { | 36 | while (true) { |
| 35 | // Get the last session in the list | 37 | // Get the last session in the list. |
| 36 | KServerSession* session = nullptr; | 38 | KServerSession* session = nullptr; |
| 37 | { | 39 | { |
| 38 | KScopedSchedulerLock sl{m_kernel}; | 40 | KScopedSchedulerLock sl{m_kernel}; |
| @@ -49,6 +51,26 @@ void KServerPort::CleanupSessions() { | |||
| 49 | break; | 51 | break; |
| 50 | } | 52 | } |
| 51 | } | 53 | } |
| 54 | |||
| 55 | // Cleanup the light session list. | ||
| 56 | while (true) { | ||
| 57 | // Get the last session in the list. | ||
| 58 | KLightServerSession* session = nullptr; | ||
| 59 | { | ||
| 60 | KScopedSchedulerLock sl{m_kernel}; | ||
| 61 | if (!m_light_session_list.empty()) { | ||
| 62 | session = std::addressof(m_light_session_list.front()); | ||
| 63 | m_light_session_list.pop_front(); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | // Close the session. | ||
| 68 | if (session != nullptr) { | ||
| 69 | session->Close(); | ||
| 70 | } else { | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | } | ||
| 52 | } | 74 | } |
| 53 | 75 | ||
| 54 | void KServerPort::Destroy() { | 76 | void KServerPort::Destroy() { |
| @@ -64,8 +86,7 @@ void KServerPort::Destroy() { | |||
| 64 | 86 | ||
| 65 | bool KServerPort::IsSignaled() const { | 87 | bool KServerPort::IsSignaled() const { |
| 66 | if (this->IsLight()) { | 88 | if (this->IsLight()) { |
| 67 | UNIMPLEMENTED(); | 89 | return !m_light_session_list.empty(); |
| 68 | return false; | ||
| 69 | } else { | 90 | } else { |
| 70 | return !m_session_list.empty(); | 91 | return !m_session_list.empty(); |
| 71 | } | 92 | } |
| @@ -83,6 +104,18 @@ void KServerPort::EnqueueSession(KServerSession* session) { | |||
| 83 | } | 104 | } |
| 84 | } | 105 | } |
| 85 | 106 | ||
| 107 | void KServerPort::EnqueueSession(KLightServerSession* session) { | ||
| 108 | ASSERT(this->IsLight()); | ||
| 109 | |||
| 110 | KScopedSchedulerLock sl{m_kernel}; | ||
| 111 | |||
| 112 | // Add the session to our queue. | ||
| 113 | m_light_session_list.push_back(*session); | ||
| 114 | if (m_light_session_list.size() == 1) { | ||
| 115 | this->NotifyAvailable(); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 86 | KServerSession* KServerPort::AcceptSession() { | 119 | KServerSession* KServerPort::AcceptSession() { |
| 87 | ASSERT(!this->IsLight()); | 120 | ASSERT(!this->IsLight()); |
| 88 | 121 | ||
| @@ -98,4 +131,19 @@ KServerSession* KServerPort::AcceptSession() { | |||
| 98 | return session; | 131 | return session; |
| 99 | } | 132 | } |
| 100 | 133 | ||
| 134 | KLightServerSession* KServerPort::AcceptLightSession() { | ||
| 135 | ASSERT(this->IsLight()); | ||
| 136 | |||
| 137 | KScopedSchedulerLock sl{m_kernel}; | ||
| 138 | |||
| 139 | // Return the first session in the list. | ||
| 140 | if (m_light_session_list.empty()) { | ||
| 141 | return nullptr; | ||
| 142 | } | ||
| 143 | |||
| 144 | KLightServerSession* session = std::addressof(m_light_session_list.front()); | ||
| 145 | m_light_session_list.pop_front(); | ||
| 146 | return session; | ||
| 147 | } | ||
| 148 | |||
| 101 | } // namespace Kernel | 149 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index 625280290..72fdb6734 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/intrusive_list.h" | 10 | #include "common/intrusive_list.h" |
| 11 | 11 | ||
| 12 | #include "core/hle/kernel/k_light_server_session.h" | ||
| 12 | #include "core/hle/kernel/k_server_session.h" | 13 | #include "core/hle/kernel/k_server_session.h" |
| 13 | #include "core/hle/kernel/k_synchronization_object.h" | 14 | #include "core/hle/kernel/k_synchronization_object.h" |
| 14 | 15 | ||
| @@ -28,8 +29,10 @@ public: | |||
| 28 | void Initialize(KPort* parent); | 29 | void Initialize(KPort* parent); |
| 29 | 30 | ||
| 30 | void EnqueueSession(KServerSession* session); | 31 | void EnqueueSession(KServerSession* session); |
| 32 | void EnqueueSession(KLightServerSession* session); | ||
| 31 | 33 | ||
| 32 | KServerSession* AcceptSession(); | 34 | KServerSession* AcceptSession(); |
| 35 | KLightServerSession* AcceptLightSession(); | ||
| 33 | 36 | ||
| 34 | const KPort* GetParent() const { | 37 | const KPort* GetParent() const { |
| 35 | return m_parent; | 38 | return m_parent; |
| @@ -43,10 +46,12 @@ public: | |||
| 43 | 46 | ||
| 44 | private: | 47 | private: |
| 45 | using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType; | 48 | using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType; |
| 49 | using LightSessionList = Common::IntrusiveListBaseTraits<KLightServerSession>::ListType; | ||
| 46 | 50 | ||
| 47 | void CleanupSessions(); | 51 | void CleanupSessions(); |
| 48 | 52 | ||
| 49 | SessionList m_session_list{}; | 53 | SessionList m_session_list{}; |
| 54 | LightSessionList m_light_session_list{}; | ||
| 50 | KPort* m_parent{}; | 55 | KPort* m_parent{}; |
| 51 | }; | 56 | }; |
| 52 | 57 | ||
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 390db2409..e9925d231 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -385,6 +385,13 @@ public: | |||
| 385 | m_cancellable = false; | 385 | m_cancellable = false; |
| 386 | } | 386 | } |
| 387 | 387 | ||
| 388 | u32* GetLightSessionData() const { | ||
| 389 | return m_light_ipc_data; | ||
| 390 | } | ||
| 391 | void SetLightSessionData(u32* data) { | ||
| 392 | m_light_ipc_data = data; | ||
| 393 | } | ||
| 394 | |||
| 388 | bool IsTerminationRequested() const { | 395 | bool IsTerminationRequested() const { |
| 389 | return m_termination_requested || GetRawState() == ThreadState::Terminated; | 396 | return m_termination_requested || GetRawState() == ThreadState::Terminated; |
| 390 | } | 397 | } |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 032c4e093..8cb05ca0b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -1340,6 +1340,7 @@ struct KernelCore::SlabHeapContainer { | |||
| 1340 | KSlabHeap<KProcess> process; | 1340 | KSlabHeap<KProcess> process; |
| 1341 | KSlabHeap<KResourceLimit> resource_limit; | 1341 | KSlabHeap<KResourceLimit> resource_limit; |
| 1342 | KSlabHeap<KSession> session; | 1342 | KSlabHeap<KSession> session; |
| 1343 | KSlabHeap<KLightSession> light_session; | ||
| 1343 | KSlabHeap<KSharedMemory> shared_memory; | 1344 | KSlabHeap<KSharedMemory> shared_memory; |
| 1344 | KSlabHeap<KSharedMemoryInfo> shared_memory_info; | 1345 | KSlabHeap<KSharedMemoryInfo> shared_memory_info; |
| 1345 | KSlabHeap<KThread> thread; | 1346 | KSlabHeap<KThread> thread; |
| @@ -1370,6 +1371,8 @@ KSlabHeap<T>& KernelCore::SlabHeap() { | |||
| 1370 | return slab_heap_container->resource_limit; | 1371 | return slab_heap_container->resource_limit; |
| 1371 | } else if constexpr (std::is_same_v<T, KSession>) { | 1372 | } else if constexpr (std::is_same_v<T, KSession>) { |
| 1372 | return slab_heap_container->session; | 1373 | return slab_heap_container->session; |
| 1374 | } else if constexpr (std::is_same_v<T, KLightSession>) { | ||
| 1375 | return slab_heap_container->light_session; | ||
| 1373 | } else if constexpr (std::is_same_v<T, KSharedMemory>) { | 1376 | } else if constexpr (std::is_same_v<T, KSharedMemory>) { |
| 1374 | return slab_heap_container->shared_memory; | 1377 | return slab_heap_container->shared_memory; |
| 1375 | } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) { | 1378 | } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) { |
| @@ -1407,6 +1410,7 @@ template KSlabHeap<KPort>& KernelCore::SlabHeap(); | |||
| 1407 | template KSlabHeap<KProcess>& KernelCore::SlabHeap(); | 1410 | template KSlabHeap<KProcess>& KernelCore::SlabHeap(); |
| 1408 | template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap(); | 1411 | template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap(); |
| 1409 | template KSlabHeap<KSession>& KernelCore::SlabHeap(); | 1412 | template KSlabHeap<KSession>& KernelCore::SlabHeap(); |
| 1413 | template KSlabHeap<KLightSession>& KernelCore::SlabHeap(); | ||
| 1410 | template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap(); | 1414 | template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap(); |
| 1411 | template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap(); | 1415 | template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap(); |
| 1412 | template KSlabHeap<KThread>& KernelCore::SlabHeap(); | 1416 | template KSlabHeap<KThread>& KernelCore::SlabHeap(); |
diff --git a/src/core/hle/kernel/svc/svc_light_ipc.cpp b/src/core/hle/kernel/svc/svc_light_ipc.cpp index d757d5af2..4772cbda1 100644 --- a/src/core/hle/kernel/svc/svc_light_ipc.cpp +++ b/src/core/hle/kernel/svc/svc_light_ipc.cpp | |||
| @@ -1,21 +1,40 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/arm/arm_interface.h" | ||
| 5 | #include "core/core.h" | 4 | #include "core/core.h" |
| 5 | #include "core/hle/kernel/k_light_client_session.h" | ||
| 6 | #include "core/hle/kernel/k_light_server_session.h" | ||
| 7 | #include "core/hle/kernel/k_process.h" | ||
| 8 | #include "core/hle/kernel/k_thread.h" | ||
| 6 | #include "core/hle/kernel/svc.h" | 9 | #include "core/hle/kernel/svc.h" |
| 7 | #include "core/hle/kernel/svc_results.h" | 10 | #include "core/hle/kernel/svc_results.h" |
| 8 | 11 | ||
| 9 | namespace Kernel::Svc { | 12 | namespace Kernel::Svc { |
| 10 | 13 | ||
| 11 | Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) { | 14 | Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) { |
| 12 | UNIMPLEMENTED(); | 15 | // Get the light client session from its handle. |
| 13 | R_THROW(ResultNotImplemented); | 16 | KScopedAutoObject session = GetCurrentProcess(system.Kernel()) |
| 17 | .GetHandleTable() | ||
| 18 | .GetObject<KLightClientSession>(session_handle); | ||
| 19 | R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||
| 20 | |||
| 21 | // Send the request. | ||
| 22 | R_TRY(session->SendSyncRequest(args)); | ||
| 23 | |||
| 24 | R_SUCCEED(); | ||
| 14 | } | 25 | } |
| 15 | 26 | ||
| 16 | Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) { | 27 | Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) { |
| 17 | UNIMPLEMENTED(); | 28 | // Get the light server session from its handle. |
| 18 | R_THROW(ResultNotImplemented); | 29 | KScopedAutoObject session = GetCurrentProcess(system.Kernel()) |
| 30 | .GetHandleTable() | ||
| 31 | .GetObject<KLightServerSession>(session_handle); | ||
| 32 | R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||
| 33 | |||
| 34 | // Handle the request. | ||
| 35 | R_TRY(session->ReplyAndReceive(args)); | ||
| 36 | |||
| 37 | R_SUCCEED(); | ||
| 19 | } | 38 | } |
| 20 | 39 | ||
| 21 | Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) { | 40 | Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) { |
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp index abba757c7..737749f7d 100644 --- a/src/core/hle/kernel/svc/svc_port.cpp +++ b/src/core/hle/kernel/svc/svc_port.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/hle/kernel/k_client_port.h" | 6 | #include "core/hle/kernel/k_client_port.h" |
| 7 | #include "core/hle/kernel/k_client_session.h" | 7 | #include "core/hle/kernel/k_client_session.h" |
| 8 | #include "core/hle/kernel/k_light_client_session.h" | ||
| 8 | #include "core/hle/kernel/k_object_name.h" | 9 | #include "core/hle/kernel/k_object_name.h" |
| 9 | #include "core/hle/kernel/k_port.h" | 10 | #include "core/hle/kernel/k_port.h" |
| 10 | #include "core/hle/kernel/k_process.h" | 11 | #include "core/hle/kernel/k_process.h" |
| @@ -51,13 +52,73 @@ Result ConnectToNamedPort(Core::System& system, Handle* out, u64 user_name) { | |||
| 51 | 52 | ||
| 52 | Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, | 53 | Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, |
| 53 | int32_t max_sessions, bool is_light, uint64_t name) { | 54 | int32_t max_sessions, bool is_light, uint64_t name) { |
| 54 | UNIMPLEMENTED(); | 55 | auto& kernel = system.Kernel(); |
| 55 | R_THROW(ResultNotImplemented); | 56 | |
| 57 | // Ensure max sessions is valid. | ||
| 58 | R_UNLESS(max_sessions > 0, ResultOutOfRange); | ||
| 59 | |||
| 60 | // Get the current handle table. | ||
| 61 | auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); | ||
| 62 | |||
| 63 | // Create a new port. | ||
| 64 | KPort* port = KPort::Create(kernel); | ||
| 65 | R_UNLESS(port != nullptr, ResultOutOfResource); | ||
| 66 | |||
| 67 | // Initialize the port. | ||
| 68 | port->Initialize(max_sessions, is_light, name); | ||
| 69 | |||
| 70 | // Ensure that we clean up the port (and its only references are handle table) on function end. | ||
| 71 | SCOPE_EXIT({ | ||
| 72 | port->GetServerPort().Close(); | ||
| 73 | port->GetClientPort().Close(); | ||
| 74 | }); | ||
| 75 | |||
| 76 | // Register the port. | ||
| 77 | KPort::Register(kernel, port); | ||
| 78 | |||
| 79 | // Add the client to the handle table. | ||
| 80 | R_TRY(handle_table.Add(out_client, std::addressof(port->GetClientPort()))); | ||
| 81 | |||
| 82 | // Ensure that we maintain a clean handle state on exit. | ||
| 83 | ON_RESULT_FAILURE { | ||
| 84 | handle_table.Remove(*out_client); | ||
| 85 | }; | ||
| 86 | |||
| 87 | // Add the server to the handle table. | ||
| 88 | R_RETURN(handle_table.Add(out_server, std::addressof(port->GetServerPort()))); | ||
| 56 | } | 89 | } |
| 57 | 90 | ||
| 58 | Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) { | 91 | Result ConnectToPort(Core::System& system, Handle* out, Handle port) { |
| 59 | UNIMPLEMENTED(); | 92 | // Get the current handle table. |
| 60 | R_THROW(ResultNotImplemented); | 93 | auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); |
| 94 | |||
| 95 | // Get the client port. | ||
| 96 | KScopedAutoObject client_port = handle_table.GetObject<KClientPort>(port); | ||
| 97 | R_UNLESS(client_port.IsNotNull(), ResultInvalidHandle); | ||
| 98 | |||
| 99 | // Reserve a handle for the port. | ||
| 100 | // NOTE: Nintendo really does write directly to the output handle here. | ||
| 101 | R_TRY(handle_table.Reserve(out)); | ||
| 102 | ON_RESULT_FAILURE { | ||
| 103 | handle_table.Unreserve(*out); | ||
| 104 | }; | ||
| 105 | |||
| 106 | // Create the session. | ||
| 107 | KAutoObject* session; | ||
| 108 | if (client_port->IsLight()) { | ||
| 109 | R_TRY(client_port->CreateLightSession( | ||
| 110 | reinterpret_cast<KLightClientSession**>(std::addressof(session)))); | ||
| 111 | } else { | ||
| 112 | R_TRY(client_port->CreateSession( | ||
| 113 | reinterpret_cast<KClientSession**>(std::addressof(session)))); | ||
| 114 | } | ||
| 115 | |||
| 116 | // Register the session. | ||
| 117 | handle_table.Register(*out, session); | ||
| 118 | session->Close(); | ||
| 119 | |||
| 120 | // We succeeded. | ||
| 121 | R_SUCCEED(); | ||
| 61 | } | 122 | } |
| 62 | 123 | ||
| 63 | Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, | 124 | Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, |
diff --git a/src/core/hle/kernel/svc/svc_session.cpp b/src/core/hle/kernel/svc/svc_session.cpp index 01b8a52ad..2f5905f32 100644 --- a/src/core/hle/kernel/svc/svc_session.cpp +++ b/src/core/hle/kernel/svc/svc_session.cpp | |||
| @@ -3,8 +3,10 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/scope_exit.h" | 4 | #include "common/scope_exit.h" |
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/hle/kernel/k_light_session.h" | ||
| 6 | #include "core/hle/kernel/k_process.h" | 7 | #include "core/hle/kernel/k_process.h" |
| 7 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | 8 | #include "core/hle/kernel/k_scoped_resource_reservation.h" |
| 9 | #include "core/hle/kernel/k_server_port.h" | ||
| 8 | #include "core/hle/kernel/k_session.h" | 10 | #include "core/hle/kernel/k_session.h" |
| 9 | #include "core/hle/kernel/svc.h" | 11 | #include "core/hle/kernel/svc.h" |
| 10 | 12 | ||
| @@ -20,7 +22,7 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien | |||
| 20 | T* session; | 22 | T* session; |
| 21 | 23 | ||
| 22 | // Reserve a new session from the process resource limit. | 24 | // Reserve a new session from the process resource limit. |
| 23 | // FIXME: LimitableResource_SessionCountMax | 25 | // TODO: Dynamic resource limits |
| 24 | KScopedResourceReservation session_reservation(std::addressof(process), | 26 | KScopedResourceReservation session_reservation(std::addressof(process), |
| 25 | LimitableResource::SessionCountMax); | 27 | LimitableResource::SessionCountMax); |
| 26 | if (session_reservation.Succeeded()) { | 28 | if (session_reservation.Succeeded()) { |
| @@ -92,16 +94,42 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien | |||
| 92 | Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light, | 94 | Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light, |
| 93 | u64 name) { | 95 | u64 name) { |
| 94 | if (is_light) { | 96 | if (is_light) { |
| 95 | // return CreateSession<KLightSession>(system, out_server, out_client, name); | 97 | R_RETURN(CreateSession<KLightSession>(system, out_server, out_client, name)); |
| 96 | R_THROW(ResultNotImplemented); | ||
| 97 | } else { | 98 | } else { |
| 98 | R_RETURN(CreateSession<KSession>(system, out_server, out_client, name)); | 99 | R_RETURN(CreateSession<KSession>(system, out_server, out_client, name)); |
| 99 | } | 100 | } |
| 100 | } | 101 | } |
| 101 | 102 | ||
| 102 | Result AcceptSession(Core::System& system, Handle* out_handle, Handle port_handle) { | 103 | Result AcceptSession(Core::System& system, Handle* out, Handle port_handle) { |
| 103 | UNIMPLEMENTED(); | 104 | // Get the current handle table. |
| 104 | R_THROW(ResultNotImplemented); | 105 | auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); |
| 106 | |||
| 107 | // Get the server port. | ||
| 108 | KScopedAutoObject port = handle_table.GetObject<KServerPort>(port_handle); | ||
| 109 | R_UNLESS(port.IsNotNull(), ResultInvalidHandle); | ||
| 110 | |||
| 111 | // Reserve an entry for the new session. | ||
| 112 | R_TRY(handle_table.Reserve(out)); | ||
| 113 | ON_RESULT_FAILURE { | ||
| 114 | handle_table.Unreserve(*out); | ||
| 115 | }; | ||
| 116 | |||
| 117 | // Accept the session. | ||
| 118 | KAutoObject* session; | ||
| 119 | if (port->IsLight()) { | ||
| 120 | session = port->AcceptLightSession(); | ||
| 121 | } else { | ||
| 122 | session = port->AcceptSession(); | ||
| 123 | } | ||
| 124 | |||
| 125 | // Ensure we accepted successfully. | ||
| 126 | R_UNLESS(session != nullptr, ResultNotFound); | ||
| 127 | |||
| 128 | // Register the session. | ||
| 129 | handle_table.Register(*out, session); | ||
| 130 | session->Close(); | ||
| 131 | |||
| 132 | R_SUCCEED(); | ||
| 105 | } | 133 | } |
| 106 | 134 | ||
| 107 | Result CreateSession64(Core::System& system, Handle* out_server_session_handle, | 135 | Result CreateSession64(Core::System& system, Handle* out_server_session_handle, |