summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2023-12-06 19:54:52 -0500
committerGravatar Liam2023-12-07 09:13:43 -0500
commit9268f265a1207f0cddb97a908a1cc349f9b6410b (patch)
tree5da6aea714523b3504b78362c5d8abd53689d72f /src
parentMerge pull request #12236 from liamwhite/cpu-refactor (diff)
downloadyuzu-9268f265a1207f0cddb97a908a1cc349f9b6410b.tar.gz
yuzu-9268f265a1207f0cddb97a908a1cc349f9b6410b.tar.xz
yuzu-9268f265a1207f0cddb97a908a1cc349f9b6410b.zip
kernel: implement light IPC
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/hle/kernel/k_client_port.cpp69
-rw-r--r--src/core/hle/kernel/k_client_port.h2
-rw-r--r--src/core/hle/kernel/k_light_client_session.cpp31
-rw-r--r--src/core/hle/kernel/k_light_client_session.h39
-rw-r--r--src/core/hle/kernel/k_light_server_session.cpp247
-rw-r--r--src/core/hle/kernel/k_light_server_session.h49
-rw-r--r--src/core/hle/kernel/k_light_session.cpp81
-rw-r--r--src/core/hle/kernel/k_light_session.h86
-rw-r--r--src/core/hle/kernel/k_port.cpp9
-rw-r--r--src/core/hle/kernel/k_port.h2
-rw-r--r--src/core/hle/kernel/k_server_port.cpp56
-rw-r--r--src/core/hle/kernel/k_server_port.h5
-rw-r--r--src/core/hle/kernel/k_thread.h7
-rw-r--r--src/core/hle/kernel/kernel.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_light_ipc.cpp29
-rw-r--r--src/core/hle/kernel/svc/svc_port.cpp71
-rw-r--r--src/core/hle/kernel/svc/svc_session.cpp40
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
124Result 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
12namespace Kernel { 12namespace Kernel {
13 13
14class KLightClientSession;
14class KClientSession; 15class KClientSession;
15class KernelCore; 16class KernelCore;
16class KPort; 17class 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
55private: 57private:
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
8namespace Kernel {
9
10KLightClientSession::KLightClientSession(KernelCore& kernel) : KAutoObject(kernel) {}
11
12KLightClientSession::~KLightClientSession() = default;
13
14void KLightClientSession::Destroy() {
15 m_parent->OnClientClosed();
16}
17
18void KLightClientSession::OnServerClosed() {}
19
20Result 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
9namespace Kernel {
10
11class KLightSession;
12
13class KLightClientSession final : public KAutoObject {
14 KERNEL_AUTOOBJECT_TRAITS(KLightClientSession, KAutoObject);
15
16public:
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
35private:
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
10namespace Kernel {
11
12namespace {
13
14constexpr u64 InvalidThreadId = std::numeric_limits<u64>::max();
15
16class ThreadQueueImplForKLightServerSessionRequest final : public KThreadQueue {
17private:
18 KThread::WaiterList* m_wait_list;
19
20public:
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
42class ThreadQueueImplForKLightServerSessionReceive final : public KThreadQueue {
43private:
44 KThread** m_server_thread;
45
46public:
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
76KLightServerSession::KLightServerSession(KernelCore& kernel) : KAutoObject(kernel) {}
77KLightServerSession::~KLightServerSession() = default;
78
79void KLightServerSession::Destroy() {
80 this->CleanupRequests();
81
82 m_parent->OnServerClosed();
83}
84
85void KLightServerSession::OnClientClosed() {
86 this->CleanupRequests();
87}
88
89Result 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
123Result 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
217void 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
10namespace Kernel {
11
12class KLightSession;
13
14class KLightServerSession final : public KAutoObject,
15 public Common::IntrusiveListBaseNode<KLightServerSession> {
16 KERNEL_AUTOOBJECT_TRAITS(KLightServerSession, KAutoObject);
17
18private:
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
25public:
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
45private:
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
10namespace Kernel {
11
12KLightSession::KLightSession(KernelCore& kernel)
13 : KAutoObjectWithSlabHeapAndContainer(kernel), m_server(kernel), m_client(kernel) {}
14KLightSession::~KLightSession() = default;
15
16void 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
49void KLightSession::Finalize() {
50 if (m_port != nullptr) {
51 m_port->OnSessionFinalized();
52 m_port->Close();
53 }
54}
55
56void KLightSession::OnServerClosed() {
57 if (m_state == State::Normal) {
58 m_state = State::ServerClosed;
59 m_client.OnServerClosed();
60 }
61
62 this->Close();
63}
64
65void KLightSession::OnClientClosed() {
66 if (m_state == State::Normal) {
67 m_state = State::ClientClosed;
68 m_server.OnClientClosed();
69 }
70
71 this->Close();
72}
73
74void 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
11namespace Kernel {
12
13class KClientPort;
14class KProcess;
15
16// TODO: SupportDynamicExpansion for SlabHeap
17class KLightSession final
18 : public KAutoObjectWithSlabHeapAndContainer<KLightSession, KAutoObjectWithList> {
19 KERNEL_AUTOOBJECT_TRAITS(KLightSession, KAutoObject);
20
21private:
22 enum class State : u8 {
23 Invalid = 0,
24 Normal = 1,
25 ClientClosed = 2,
26 ServerClosed = 3,
27 };
28
29public:
30 static constexpr size_t DataSize = sizeof(u32) * 7;
31 static constexpr u32 ReplyFlag = (1U << 31);
32
33private:
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
42public:
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
61Result 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
14namespace Kernel { 14namespace Kernel {
15 15
16class KLightServerSession;
16class KServerSession; 17class KServerSession;
17 18
18class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> { 19class 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 {
27void KServerPort::CleanupSessions() { 27void 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
54void KServerPort::Destroy() { 76void KServerPort::Destroy() {
@@ -64,8 +86,7 @@ void KServerPort::Destroy() {
64 86
65bool KServerPort::IsSignaled() const { 87bool 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
107void 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
86KServerSession* KServerPort::AcceptSession() { 119KServerSession* 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
134KLightServerSession* 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
44private: 47private:
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();
1407template KSlabHeap<KProcess>& KernelCore::SlabHeap(); 1410template KSlabHeap<KProcess>& KernelCore::SlabHeap();
1408template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap(); 1411template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap();
1409template KSlabHeap<KSession>& KernelCore::SlabHeap(); 1412template KSlabHeap<KSession>& KernelCore::SlabHeap();
1413template KSlabHeap<KLightSession>& KernelCore::SlabHeap();
1410template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap(); 1414template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap();
1411template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap(); 1415template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap();
1412template KSlabHeap<KThread>& KernelCore::SlabHeap(); 1416template 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
9namespace Kernel::Svc { 12namespace Kernel::Svc {
10 13
11Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) { 14Result 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
16Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) { 27Result 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
21Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) { 40Result 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
52Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, 53Result 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
58Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) { 91Result 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
63Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, 124Result 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
92Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light, 94Result 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
102Result AcceptSession(Core::System& system, Handle* out_handle, Handle port_handle) { 103Result 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
107Result CreateSession64(Core::System& system, Handle* out_server_session_handle, 135Result CreateSession64(Core::System& system, Handle* out_server_session_handle,