summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Liam2022-10-11 18:16:56 -0400
committerGravatar Liam2022-10-11 18:40:40 -0400
commit61a8696510b3bca120f1f0289a3829e3db14834e (patch)
tree34239a299b7cd842e46df21626f6b190e9b40d14
parentAdd implementation of svcCreateSession (diff)
downloadyuzu-61a8696510b3bca120f1f0289a3829e3db14834e.tar.gz
yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.tar.xz
yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.zip
k_server_session: preliminary support for userspace server sessions
Diffstat (limited to '')
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp1
-rw-r--r--src/core/hle/ipc_helpers.h3
-rw-r--r--src/core/hle/kernel/k_client_session.cpp5
-rw-r--r--src/core/hle/kernel/k_client_session.h3
-rw-r--r--src/core/hle/kernel/k_server_session.cpp243
-rw-r--r--src/core/hle/kernel/k_server_session.h37
-rw-r--r--src/core/hle/kernel/svc.cpp82
-rw-r--r--src/core/hle/kernel/svc_wrap.h18
-rw-r--r--src/core/hle/service/sm/sm.cpp3
9 files changed, 346 insertions, 49 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 1d46f6d40..22b5d5656 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -111,6 +111,7 @@ public:
111 LOG_ERROR(Core_ARM, 111 LOG_ERROR(Core_ARM,
112 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, 112 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
113 num_instructions, memory.Read32(pc)); 113 num_instructions, memory.Read32(pc));
114 ReturnException(pc, ARM_Interface::no_execute);
114 } 115 }
115 116
116 void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, 117 void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index d631c0357..0cc26a211 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -152,7 +152,8 @@ public:
152 Kernel::LimitableResource::Sessions, 1); 152 Kernel::LimitableResource::Sessions, 1);
153 153
154 auto* session = Kernel::KSession::Create(kernel); 154 auto* session = Kernel::KSession::Create(kernel);
155 session->Initialize(nullptr, iface->GetServiceName()); 155 session->Initialize(nullptr, iface->GetServiceName(),
156 std::make_shared<Kernel::SessionRequestManager>(kernel));
156 157
157 context->AddMoveObject(&session->GetClientSession()); 158 context->AddMoveObject(&session->GetClientSession());
158 iface->ClientConnected(&session->GetServerSession()); 159 iface->ClientConnected(&session->GetServerSession());
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp
index b2a887b14..8892c5b7c 100644
--- a/src/core/hle/kernel/k_client_session.cpp
+++ b/src/core/hle/kernel/k_client_session.cpp
@@ -21,10 +21,9 @@ void KClientSession::Destroy() {
21 21
22void KClientSession::OnServerClosed() {} 22void KClientSession::OnServerClosed() {}
23 23
24Result KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, 24Result KClientSession::SendSyncRequest() {
25 Core::Timing::CoreTiming& core_timing) {
26 // Signal the server session that new data is available 25 // Signal the server session that new data is available
27 return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing); 26 return parent->GetServerSession().OnRequest();
28} 27}
29 28
30} // namespace Kernel 29} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h
index 0c750d756..b4a19c546 100644
--- a/src/core/hle/kernel/k_client_session.h
+++ b/src/core/hle/kernel/k_client_session.h
@@ -46,8 +46,7 @@ public:
46 return parent; 46 return parent;
47 } 47 }
48 48
49 Result SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, 49 Result SendSyncRequest();
50 Core::Timing::CoreTiming& core_timing);
51 50
52 void OnServerClosed(); 51 void OnServerClosed();
53 52
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 802c646a6..4252c9adb 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -7,6 +7,8 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/scope_exit.h"
11#include "core/core.h"
10#include "core/core_timing.h" 12#include "core/core_timing.h"
11#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/hle_ipc.h" 14#include "core/hle/kernel/hle_ipc.h"
@@ -18,13 +20,19 @@
18#include "core/hle/kernel/k_server_session.h" 20#include "core/hle/kernel/k_server_session.h"
19#include "core/hle/kernel/k_session.h" 21#include "core/hle/kernel/k_session.h"
20#include "core/hle/kernel/k_thread.h" 22#include "core/hle/kernel/k_thread.h"
23#include "core/hle/kernel/k_thread_queue.h"
21#include "core/hle/kernel/kernel.h" 24#include "core/hle/kernel/kernel.h"
22#include "core/hle/kernel/service_thread.h" 25#include "core/hle/kernel/service_thread.h"
23#include "core/memory.h" 26#include "core/memory.h"
24 27
25namespace Kernel { 28namespace Kernel {
26 29
27KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} 30using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
31
32static constexpr u32 MessageBufferSize = 0x100;
33
34KServerSession::KServerSession(KernelCore& kernel_)
35 : KSynchronizationObject{kernel_}, m_lock{kernel_} {}
28 36
29KServerSession::~KServerSession() = default; 37KServerSession::~KServerSession() = default;
30 38
@@ -33,17 +41,14 @@ void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
33 // Set member variables. 41 // Set member variables.
34 parent = parent_session_; 42 parent = parent_session_;
35 name = std::move(name_); 43 name = std::move(name_);
36 44 manager = manager_;
37 if (manager_) {
38 manager = manager_;
39 } else {
40 manager = std::make_shared<SessionRequestManager>(kernel);
41 }
42} 45}
43 46
44void KServerSession::Destroy() { 47void KServerSession::Destroy() {
45 parent->OnServerClosed(); 48 parent->OnServerClosed();
46 49
50 this->CleanupRequests();
51
47 parent->Close(); 52 parent->Close();
48 53
49 // Release host emulation members. 54 // Release host emulation members.
@@ -54,13 +59,13 @@ void KServerSession::Destroy() {
54} 59}
55 60
56void KServerSession::OnClientClosed() { 61void KServerSession::OnClientClosed() {
57 if (manager->HasSessionHandler()) { 62 if (manager && manager->HasSessionHandler()) {
58 manager->SessionHandler().ClientDisconnected(this); 63 manager->SessionHandler().ClientDisconnected(this);
59 } 64 }
60} 65}
61 66
62bool KServerSession::IsSignaled() const { 67bool KServerSession::IsSignaled() const {
63 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 68 ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
64 69
65 // If the client is closed, we're always signaled. 70 // If the client is closed, we're always signaled.
66 if (parent->IsClientClosed()) { 71 if (parent->IsClientClosed()) {
@@ -68,7 +73,7 @@ bool KServerSession::IsSignaled() const {
68 } 73 }
69 74
70 // Otherwise, we're signaled if we have a request and aren't handling one. 75 // Otherwise, we're signaled if we have a request and aren't handling one.
71 return false; 76 return !m_thread_request_list.empty() && m_current_thread_request == nullptr;
72} 77}
73 78
74void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { 79void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) {
@@ -173,9 +178,221 @@ Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
173 return result; 178 return result;
174} 179}
175 180
176Result KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, 181Result KServerSession::OnRequest() {
177 Core::Timing::CoreTiming& core_timing) { 182 // Create the wait queue.
178 return QueueSyncRequest(thread, memory); 183 ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
184
185 {
186 // Lock the scheduler.
187 KScopedSchedulerLock sl{kernel};
188
189 // Ensure that we can handle new requests.
190 R_UNLESS(!parent->IsServerClosed(), ResultSessionClosed);
191
192 // Check that we're not terminating.
193 R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
194
195 if (manager) {
196 // HLE request.
197 auto& memory{kernel.System().Memory()};
198 this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
199 } else {
200 // Non-HLE request.
201 auto* thread{GetCurrentThreadPointer(kernel)};
202
203 // Get whether we're empty.
204 const bool was_empty = m_thread_request_list.empty();
205
206 // Add the thread to the list.
207 thread->Open();
208 m_thread_request_list.push_back(thread);
209
210 // If we were empty, signal.
211 if (was_empty) {
212 this->NotifyAvailable();
213 }
214 }
215
216 // This is a synchronous request, so we should wait for our request to complete.
217 GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
218 GetCurrentThread(kernel).BeginWait(&wait_queue);
219 }
220
221 return GetCurrentThread(kernel).GetWaitResult();
222}
223
224Result KServerSession::SendReply() {
225 // Lock the session.
226 KScopedLightLock lk(m_lock);
227
228 // Get the request.
229 KThread* client_thread;
230 {
231 KScopedSchedulerLock sl{kernel};
232
233 // Get the current request.
234 client_thread = m_current_thread_request;
235 R_UNLESS(client_thread != nullptr, ResultInvalidState);
236
237 // Clear the current request, since we're processing it.
238 m_current_thread_request = nullptr;
239 if (!m_thread_request_list.empty()) {
240 this->NotifyAvailable();
241 }
242 }
243
244 // Close reference to the request once we're done processing it.
245 SCOPE_EXIT({ client_thread->Close(); });
246
247 // Extract relevant information from the request.
248 // const uintptr_t client_message = request->GetAddress();
249 // const size_t client_buffer_size = request->GetSize();
250 // KThread *client_thread = request->GetThread();
251 // KEvent *event = request->GetEvent();
252
253 // Check whether we're closed.
254 const bool closed = (client_thread == nullptr || parent->IsClientClosed());
255
256 Result result = ResultSuccess;
257 if (!closed) {
258 // If we're not closed, send the reply.
259 Core::Memory::Memory& memory{kernel.System().Memory()};
260 KThread* server_thread{GetCurrentThreadPointer(kernel)};
261 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
262
263 auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
264 auto* dst_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress());
265 std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize);
266 } else {
267 result = ResultSessionClosed;
268 }
269
270 // Select a result for the client.
271 Result client_result = result;
272 if (closed && R_SUCCEEDED(result)) {
273 result = ResultSessionClosed;
274 client_result = ResultSessionClosed;
275 } else {
276 result = ResultSuccess;
277 }
278
279 // If there's a client thread, update it.
280 if (client_thread != nullptr) {
281 // End the client thread's wait.
282 KScopedSchedulerLock sl{kernel};
283
284 if (!client_thread->IsTerminationRequested()) {
285 client_thread->EndWait(client_result);
286 }
287 }
288
289 return result;
290}
291
292Result KServerSession::ReceiveRequest() {
293 // Lock the session.
294 KScopedLightLock lk(m_lock);
295
296 // Get the request and client thread.
297 // KSessionRequest *request;
298 KThread* client_thread;
299
300 {
301 KScopedSchedulerLock sl{kernel};
302
303 // Ensure that we can service the request.
304 R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
305
306 // Ensure we aren't already servicing a request.
307 R_UNLESS(m_current_thread_request == nullptr, ResultNotFound);
308
309 // Ensure we have a request to service.
310 R_UNLESS(!m_thread_request_list.empty(), ResultNotFound);
311
312 // Pop the first request from the list.
313 client_thread = m_thread_request_list.front();
314 m_thread_request_list.pop_front();
315
316 // Get the thread for the request.
317 R_UNLESS(client_thread != nullptr, ResultSessionClosed);
318
319 // Open the client thread.
320 client_thread->Open();
321 }
322
323 // SCOPE_EXIT({ client_thread->Close(); });
324
325 // Set the request as our current.
326 m_current_thread_request = client_thread;
327
328 // Receive the message.
329 Core::Memory::Memory& memory{kernel.System().Memory()};
330 KThread* server_thread{GetCurrentThreadPointer(kernel)};
331 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
332
333 auto* src_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress());
334 auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
335 std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize);
336
337 // We succeeded.
338 return ResultSuccess;
339}
340
341void KServerSession::CleanupRequests() {
342 KScopedLightLock lk(m_lock);
343
344 // Clean up any pending requests.
345 while (true) {
346 // Get the next request.
347 // KSessionRequest *request = nullptr;
348 KThread* client_thread = nullptr;
349 {
350 KScopedSchedulerLock sl{kernel};
351
352 if (m_current_thread_request) {
353 // Choose the current request if we have one.
354 client_thread = m_current_thread_request;
355 m_current_thread_request = nullptr;
356 } else if (!m_thread_request_list.empty()) {
357 // Pop the request from the front of the list.
358 client_thread = m_thread_request_list.front();
359 m_thread_request_list.pop_front();
360 }
361 }
362
363 // If there's no request, we're done.
364 if (client_thread == nullptr) {
365 break;
366 }
367
368 // Close a reference to the request once it's cleaned up.
369 SCOPE_EXIT({ client_thread->Close(); });
370
371 // Extract relevant information from the request.
372 // const uintptr_t client_message = request->GetAddress();
373 // const size_t client_buffer_size = request->GetSize();
374 // KThread *client_thread = request->GetThread();
375 // KEvent *event = request->GetEvent();
376
377 // KProcess *server_process = request->GetServerProcess();
378 // KProcess *client_process = (client_thread != nullptr) ?
379 // client_thread->GetOwnerProcess() : nullptr;
380 // KProcessPageTable *client_page_table = (client_process != nullptr) ?
381 // &client_process->GetPageTable() : nullptr;
382
383 // Cleanup the mappings.
384 // Result result = CleanupMap(request, server_process, client_page_table);
385
386 // If there's a client thread, update it.
387 if (client_thread != nullptr) {
388 // End the client thread's wait.
389 KScopedSchedulerLock sl{kernel};
390
391 if (!client_thread->IsTerminationRequested()) {
392 client_thread->EndWait(ResultSessionClosed);
393 }
394 }
395 }
179} 396}
180 397
181} // namespace Kernel 398} // namespace Kernel
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index 6d0821945..748d52826 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <list>
6#include <memory> 7#include <memory>
7#include <string> 8#include <string>
8#include <utility> 9#include <utility>
@@ -10,6 +11,7 @@
10#include <boost/intrusive/list.hpp> 11#include <boost/intrusive/list.hpp>
11 12
12#include "core/hle/kernel/hle_ipc.h" 13#include "core/hle/kernel/hle_ipc.h"
14#include "core/hle/kernel/k_light_lock.h"
13#include "core/hle/kernel/k_synchronization_object.h" 15#include "core/hle/kernel/k_synchronization_object.h"
14#include "core/hle/result.h" 16#include "core/hle/result.h"
15 17
@@ -59,25 +61,15 @@ public:
59 void OnClientClosed(); 61 void OnClientClosed();
60 62
61 void ClientConnected(SessionRequestHandlerPtr handler) { 63 void ClientConnected(SessionRequestHandlerPtr handler) {
62 manager->SetSessionHandler(std::move(handler)); 64 if (manager) {
65 manager->SetSessionHandler(std::move(handler));
66 }
63 } 67 }
64 68
65 void ClientDisconnected() { 69 void ClientDisconnected() {
66 manager = nullptr; 70 manager = nullptr;
67 } 71 }
68 72
69 /**
70 * Handle a sync request from the emulated application.
71 *
72 * @param thread Thread that initiated the request.
73 * @param memory Memory context to handle the sync request under.
74 * @param core_timing Core timing context to schedule the request event under.
75 *
76 * @returns Result from the operation.
77 */
78 Result HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory,
79 Core::Timing::CoreTiming& core_timing);
80
81 /// Adds a new domain request handler to the collection of request handlers within 73 /// Adds a new domain request handler to the collection of request handlers within
82 /// this ServerSession instance. 74 /// this ServerSession instance.
83 void AppendDomainHandler(SessionRequestHandlerPtr handler); 75 void AppendDomainHandler(SessionRequestHandlerPtr handler);
@@ -88,7 +80,7 @@ public:
88 80
89 /// Returns true if the session has been converted to a domain, otherwise False 81 /// Returns true if the session has been converted to a domain, otherwise False
90 bool IsDomain() const { 82 bool IsDomain() const {
91 return manager->IsDomain(); 83 return manager && manager->IsDomain();
92 } 84 }
93 85
94 /// Converts the session to a domain at the end of the current command 86 /// Converts the session to a domain at the end of the current command
@@ -101,7 +93,15 @@ public:
101 return manager; 93 return manager;
102 } 94 }
103 95
96 /// TODO: flesh these out to match the real kernel
97 Result OnRequest();
98 Result SendReply();
99 Result ReceiveRequest();
100
104private: 101private:
102 /// Frees up waiting client sessions when this server session is about to die
103 void CleanupRequests();
104
105 /// Queues a sync request from the emulated application. 105 /// Queues a sync request from the emulated application.
106 Result QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); 106 Result QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
107 107
@@ -112,7 +112,7 @@ private:
112 /// object handle. 112 /// object handle.
113 Result HandleDomainSyncRequest(Kernel::HLERequestContext& context); 113 Result HandleDomainSyncRequest(Kernel::HLERequestContext& context);
114 114
115 /// This session's HLE request handlers 115 /// This session's HLE request handlers; if nullptr, this is not an HLE server
116 std::shared_ptr<SessionRequestManager> manager; 116 std::shared_ptr<SessionRequestManager> manager;
117 117
118 /// When set to True, converts the session to a domain at the end of the command 118 /// When set to True, converts the session to a domain at the end of the command
@@ -120,6 +120,13 @@ private:
120 120
121 /// KSession that owns this KServerSession 121 /// KSession that owns this KServerSession
122 KSession* parent{}; 122 KSession* parent{};
123
124 /// List of threads which are pending a reply.
125 /// FIXME: KSessionRequest
126 std::list<KThread*> m_thread_request_list;
127 KThread* m_current_thread_request{};
128
129 KLightLock m_lock;
123}; 130};
124 131
125} // namespace Kernel 132} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 3a89511aa..510a9b3e3 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -323,7 +323,7 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
323 // Add the server session to the handle table. 323 // Add the server session to the handle table.
324 R_TRY(handle_table.Add(out_server, &session->GetServerSession())); 324 R_TRY(handle_table.Add(out_server, &session->GetServerSession()));
325 325
326 // Add the client session to the handle table. */ 326 // Add the client session to the handle table.
327 const auto result = handle_table.Add(out_client, &session->GetClientSession()); 327 const auto result = handle_table.Add(out_client, &session->GetClientSession());
328 328
329 if (!R_SUCCEEDED(result)) { 329 if (!R_SUCCEEDED(result)) {
@@ -383,7 +383,8 @@ static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_n
383 383
384 // Create a session. 384 // Create a session.
385 KClientSession* session{}; 385 KClientSession* session{};
386 R_TRY(port->CreateSession(std::addressof(session))); 386 R_TRY(port->CreateSession(std::addressof(session),
387 std::make_shared<SessionRequestManager>(kernel)));
387 port->Close(); 388 port->Close();
388 389
389 // Register the session in the table, close the extra reference. 390 // Register the session in the table, close the extra reference.
@@ -401,7 +402,7 @@ static Result ConnectToNamedPort32(Core::System& system, Handle* out_handle,
401 return ConnectToNamedPort(system, out_handle, port_name_address); 402 return ConnectToNamedPort(system, out_handle, port_name_address);
402} 403}
403 404
404/// Makes a blocking IPC call to an OS service. 405/// Makes a blocking IPC call to a service.
405static Result SendSyncRequest(Core::System& system, Handle handle) { 406static Result SendSyncRequest(Core::System& system, Handle handle) {
406 auto& kernel = system.Kernel(); 407 auto& kernel = system.Kernel();
407 408
@@ -415,22 +416,75 @@ static Result SendSyncRequest(Core::System& system, Handle handle) {
415 416
416 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); 417 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
417 418
418 { 419 return session->SendSyncRequest();
419 KScopedSchedulerLock lock(kernel);
420
421 // This is a synchronous request, so we should wait for our request to complete.
422 GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue));
423 GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
424 session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), system.CoreTiming());
425 }
426
427 return GetCurrentThread(kernel).GetWaitResult();
428} 420}
429 421
430static Result SendSyncRequest32(Core::System& system, Handle handle) { 422static Result SendSyncRequest32(Core::System& system, Handle handle) {
431 return SendSyncRequest(system, handle); 423 return SendSyncRequest(system, handle);
432} 424}
433 425
426static Result ReplyAndReceive(Core::System& system, s32* out_index, Handle* handles,
427 s32 num_handles, Handle reply_target, s64 timeout_ns) {
428 auto& kernel = system.Kernel();
429 auto& handle_table = GetCurrentThread(kernel).GetOwnerProcess()->GetHandleTable();
430
431 // Convert handle list to object table.
432 std::vector<KSynchronizationObject*> objs(num_handles);
433 R_UNLESS(
434 handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, num_handles),
435 ResultInvalidHandle);
436
437 // Ensure handles are closed when we're done.
438 SCOPE_EXIT({
439 for (auto i = 0; i < num_handles; ++i) {
440 objs[i]->Close();
441 }
442 });
443
444 // Reply to the target, if one is specified.
445 if (reply_target != InvalidHandle) {
446 KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target);
447 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
448
449 // If we fail to reply, we want to set the output index to -1.
450 // ON_RESULT_FAILURE { *out_index = -1; };
451
452 // Send the reply.
453 // R_TRY(session->SendReply());
454
455 Result rc = session->SendReply();
456 if (!R_SUCCEEDED(rc)) {
457 *out_index = -1;
458 return rc;
459 }
460 }
461
462 // Wait for a message.
463 while (true) {
464 // Wait for an object.
465 s32 index;
466 Result result = KSynchronizationObject::Wait(kernel, &index, objs.data(),
467 static_cast<s32>(objs.size()), timeout_ns);
468 if (result == ResultTimedOut) {
469 return result;
470 }
471
472 // Receive the request.
473 if (R_SUCCEEDED(result)) {
474 KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
475 if (session != nullptr) {
476 result = session->ReceiveRequest();
477 if (result == ResultNotFound) {
478 continue;
479 }
480 }
481 }
482
483 *out_index = index;
484 return result;
485 }
486}
487
434/// Get the ID for the specified thread. 488/// Get the ID for the specified thread.
435static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { 489static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
436 // Get the thread from its handle. 490 // Get the thread from its handle.
@@ -2951,7 +3005,7 @@ static const FunctionDef SVC_Table_64[] = {
2951 {0x40, SvcWrap64<CreateSession>, "CreateSession"}, 3005 {0x40, SvcWrap64<CreateSession>, "CreateSession"},
2952 {0x41, nullptr, "AcceptSession"}, 3006 {0x41, nullptr, "AcceptSession"},
2953 {0x42, nullptr, "ReplyAndReceiveLight"}, 3007 {0x42, nullptr, "ReplyAndReceiveLight"},
2954 {0x43, nullptr, "ReplyAndReceive"}, 3008 {0x43, SvcWrap64<ReplyAndReceive>, "ReplyAndReceive"},
2955 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, 3009 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
2956 {0x45, SvcWrap64<CreateEvent>, "CreateEvent"}, 3010 {0x45, SvcWrap64<CreateEvent>, "CreateEvent"},
2957 {0x46, nullptr, "MapIoRegion"}, 3011 {0x46, nullptr, "MapIoRegion"},
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 16bf65802..272c54cf7 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -8,6 +8,7 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/svc_types.h" 9#include "core/hle/kernel/svc_types.h"
10#include "core/hle/result.h" 10#include "core/hle/result.h"
11#include "core/memory.h"
11 12
12namespace Kernel { 13namespace Kernel {
13 14
@@ -360,6 +361,23 @@ void SvcWrap64(Core::System& system) {
360 FuncReturn(system, retval); 361 FuncReturn(system, retval);
361} 362}
362 363
364// Used by ReplyAndReceive
365template <Result func(Core::System&, s32*, Handle*, s32, Handle, s64)>
366void SvcWrap64(Core::System& system) {
367 s32 param_1 = 0;
368 s32 num_handles = static_cast<s32>(Param(system, 2));
369
370 std::vector<Handle> handles(num_handles);
371 system.Memory().ReadBlock(Param(system, 1), handles.data(), num_handles * sizeof(Handle));
372
373 const u32 retval = func(system, &param_1, handles.data(), num_handles,
374 static_cast<s32>(Param(system, 3)), static_cast<s64>(Param(system, 4)))
375 .raw;
376
377 system.CurrentArmInterface().SetReg(1, param_1);
378 FuncReturn(system, retval);
379}
380
363// Used by WaitForAddress 381// Used by WaitForAddress
364template <Result func(Core::System&, u64, Svc::ArbitrationType, s32, s64)> 382template <Result func(Core::System&, u64, Svc::ArbitrationType, s32, s64)>
365void SvcWrap64(Core::System& system) { 383void SvcWrap64(Core::System& system) {
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 246c94623..48e70f93c 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -156,7 +156,8 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
156 156
157 // Create a new session. 157 // Create a new session.
158 Kernel::KClientSession* session{}; 158 Kernel::KClientSession* session{};
159 if (const auto result = port->GetClientPort().CreateSession(std::addressof(session)); 159 if (const auto result = port->GetClientPort().CreateSession(
160 std::addressof(session), std::make_shared<Kernel::SessionRequestManager>(kernel));
160 result.IsError()) { 161 result.IsError()) {
161 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); 162 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
162 return result; 163 return result;