summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar liamwhite2022-10-20 18:07:30 -0400
committerGravatar GitHub2022-10-20 18:07:30 -0400
commita6628e8dba0432031a5bc470e5716c831128a357 (patch)
tree533eef88596325c5f14b3caf5350cb9a09265afa
parentMerge pull request #9099 from Docteh/undocked (diff)
parentkernel: remove most SessionRequestManager handling from KServerSession (diff)
downloadyuzu-a6628e8dba0432031a5bc470e5716c831128a357.tar.gz
yuzu-a6628e8dba0432031a5bc470e5716c831128a357.tar.xz
yuzu-a6628e8dba0432031a5bc470e5716c831128a357.zip
Merge pull request #9078 from liamwhite/session-request
kernel: Session request cleanup
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/ipc_helpers.h11
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp110
-rw-r--r--src/core/hle/kernel/hle_ipc.h9
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp2
-rw-r--r--src/core/hle/kernel/k_client_session.cpp15
-rw-r--r--src/core/hle/kernel/k_linked_list.h1
-rw-r--r--src/core/hle/kernel/k_page_buffer.h1
-rw-r--r--src/core/hle/kernel/k_server_session.cpp232
-rw-r--r--src/core/hle/kernel/k_server_session.h41
-rw-r--r--src/core/hle/kernel/k_session_request.cpp61
-rw-r--r--src/core/hle/kernel/k_session_request.h307
-rw-r--r--src/core/hle/kernel/k_shared_memory_info.h3
-rw-r--r--src/core/hle/kernel/k_thread_local_page.h2
-rw-r--r--src/core/hle/kernel/kernel.h4
-rw-r--r--src/core/hle/kernel/slab_helpers.h2
-rw-r--r--src/core/hle/service/sm/sm_controller.cpp5
17 files changed, 608 insertions, 200 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e7fe675cb..055bea641 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -243,6 +243,8 @@ add_library(core STATIC
243 hle/kernel/k_server_session.h 243 hle/kernel/k_server_session.h
244 hle/kernel/k_session.cpp 244 hle/kernel/k_session.cpp
245 hle/kernel/k_session.h 245 hle/kernel/k_session.h
246 hle/kernel/k_session_request.cpp
247 hle/kernel/k_session_request.h
246 hle/kernel/k_shared_memory.cpp 248 hle/kernel/k_shared_memory.cpp
247 hle/kernel/k_shared_memory.h 249 hle/kernel/k_shared_memory.h
248 hle/kernel/k_shared_memory_info.h 250 hle/kernel/k_shared_memory_info.h
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 0cc26a211..aa27be767 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -86,13 +86,13 @@ public:
86 u32 num_domain_objects{}; 86 u32 num_domain_objects{};
87 const bool always_move_handles{ 87 const bool always_move_handles{
88 (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0}; 88 (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
89 if (!ctx.Session()->IsDomain() || always_move_handles) { 89 if (!ctx.Session()->GetSessionRequestManager()->IsDomain() || always_move_handles) {
90 num_handles_to_move = num_objects_to_move; 90 num_handles_to_move = num_objects_to_move;
91 } else { 91 } else {
92 num_domain_objects = num_objects_to_move; 92 num_domain_objects = num_objects_to_move;
93 } 93 }
94 94
95 if (ctx.Session()->IsDomain()) { 95 if (ctx.Session()->GetSessionRequestManager()->IsDomain()) {
96 raw_data_size += 96 raw_data_size +=
97 static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects); 97 static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
98 ctx.write_size += num_domain_objects; 98 ctx.write_size += num_domain_objects;
@@ -125,7 +125,8 @@ public:
125 if (!ctx.IsTipc()) { 125 if (!ctx.IsTipc()) {
126 AlignWithPadding(); 126 AlignWithPadding();
127 127
128 if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) { 128 if (ctx.Session()->GetSessionRequestManager()->IsDomain() &&
129 ctx.HasDomainMessageHeader()) {
129 IPC::DomainMessageHeader domain_header{}; 130 IPC::DomainMessageHeader domain_header{};
130 domain_header.num_objects = num_domain_objects; 131 domain_header.num_objects = num_domain_objects;
131 PushRaw(domain_header); 132 PushRaw(domain_header);
@@ -145,7 +146,7 @@ public:
145 146
146 template <class T> 147 template <class T>
147 void PushIpcInterface(std::shared_ptr<T> iface) { 148 void PushIpcInterface(std::shared_ptr<T> iface) {
148 if (context->Session()->IsDomain()) { 149 if (context->Session()->GetSessionRequestManager()->IsDomain()) {
149 context->AddDomainObject(std::move(iface)); 150 context->AddDomainObject(std::move(iface));
150 } else { 151 } else {
151 kernel.CurrentProcess()->GetResourceLimit()->Reserve( 152 kernel.CurrentProcess()->GetResourceLimit()->Reserve(
@@ -386,7 +387,7 @@ public:
386 387
387 template <class T> 388 template <class T>
388 std::weak_ptr<T> PopIpcInterface() { 389 std::weak_ptr<T> PopIpcInterface() {
389 ASSERT(context->Session()->IsDomain()); 390 ASSERT(context->Session()->GetSessionRequestManager()->IsDomain());
390 ASSERT(context->GetDomainMessageHeader().input_object_count > 0); 391 ASSERT(context->GetDomainMessageHeader().input_object_count > 0);
391 return context->GetDomainHandler<T>(Pop<u32>() - 1); 392 return context->GetDomainHandler<T>(Pop<u32>() - 1);
392 } 393 }
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 5b3feec66..e4f43a053 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -19,6 +19,7 @@
19#include "core/hle/kernel/k_server_session.h" 19#include "core/hle/kernel/k_server_session.h"
20#include "core/hle/kernel/k_thread.h" 20#include "core/hle/kernel/k_thread.h"
21#include "core/hle/kernel/kernel.h" 21#include "core/hle/kernel/kernel.h"
22#include "core/hle/kernel/service_thread.h"
22#include "core/memory.h" 23#include "core/memory.h"
23 24
24namespace Kernel { 25namespace Kernel {
@@ -56,16 +57,103 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co
56 } 57 }
57} 58}
58 59
60Result SessionRequestManager::CompleteSyncRequest(KServerSession* server_session,
61 HLERequestContext& context) {
62 Result result = ResultSuccess;
63
64 // If the session has been converted to a domain, handle the domain request
65 if (this->HasSessionRequestHandler(context)) {
66 if (IsDomain() && context.HasDomainMessageHeader()) {
67 result = HandleDomainSyncRequest(server_session, context);
68 // If there is no domain header, the regular session handler is used
69 } else if (this->HasSessionHandler()) {
70 // If this manager has an associated HLE handler, forward the request to it.
71 result = this->SessionHandler().HandleSyncRequest(*server_session, context);
72 }
73 } else {
74 ASSERT_MSG(false, "Session handler is invalid, stubbing response!");
75 IPC::ResponseBuilder rb(context, 2);
76 rb.Push(ResultSuccess);
77 }
78
79 if (convert_to_domain) {
80 ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance.");
81 this->ConvertToDomain();
82 convert_to_domain = false;
83 }
84
85 return result;
86}
87
88Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_session,
89 HLERequestContext& context) {
90 if (!context.HasDomainMessageHeader()) {
91 return ResultSuccess;
92 }
93
94 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
95 context.SetSessionRequestManager(server_session->GetSessionRequestManager());
96
97 // If there is a DomainMessageHeader, then this is CommandType "Request"
98 const auto& domain_message_header = context.GetDomainMessageHeader();
99 const u32 object_id{domain_message_header.object_id};
100 switch (domain_message_header.command) {
101 case IPC::DomainMessageHeader::CommandType::SendMessage:
102 if (object_id > this->DomainHandlerCount()) {
103 LOG_CRITICAL(IPC,
104 "object_id {} is too big! This probably means a recent service call "
105 "needed to return a new interface!",
106 object_id);
107 ASSERT(false);
108 return ResultSuccess; // Ignore error if asserts are off
109 }
110 if (auto strong_ptr = this->DomainHandler(object_id - 1).lock()) {
111 return strong_ptr->HandleSyncRequest(*server_session, context);
112 } else {
113 ASSERT(false);
114 return ResultSuccess;
115 }
116
117 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
118 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
119
120 this->CloseDomainHandler(object_id - 1);
121
122 IPC::ResponseBuilder rb{context, 2};
123 rb.Push(ResultSuccess);
124 return ResultSuccess;
125 }
126 }
127
128 LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value());
129 ASSERT(false);
130 return ResultSuccess;
131}
132
133Result SessionRequestManager::QueueSyncRequest(KSession* parent,
134 std::shared_ptr<HLERequestContext>&& context) {
135 // Ensure we have a session request handler
136 if (this->HasSessionRequestHandler(*context)) {
137 if (auto strong_ptr = this->GetServiceThread().lock()) {
138 strong_ptr->QueueSyncRequest(*parent, std::move(context));
139 } else {
140 ASSERT_MSG(false, "strong_ptr is nullptr!");
141 }
142 } else {
143 ASSERT_MSG(false, "handler is invalid!");
144 }
145
146 return ResultSuccess;
147}
148
59void SessionRequestHandler::ClientConnected(KServerSession* session) { 149void SessionRequestHandler::ClientConnected(KServerSession* session) {
60 session->ClientConnected(shared_from_this()); 150 session->GetSessionRequestManager()->SetSessionHandler(shared_from_this());
61 151
62 // Ensure our server session is tracked globally. 152 // Ensure our server session is tracked globally.
63 kernel.RegisterServerObject(session); 153 kernel.RegisterServerObject(session);
64} 154}
65 155
66void SessionRequestHandler::ClientDisconnected(KServerSession* session) { 156void SessionRequestHandler::ClientDisconnected(KServerSession* session) {}
67 session->ClientDisconnected();
68}
69 157
70HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, 158HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
71 KServerSession* server_session_, KThread* thread_) 159 KServerSession* server_session_, KThread* thread_)
@@ -126,7 +214,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
126 // Padding to align to 16 bytes 214 // Padding to align to 16 bytes
127 rp.AlignWithPadding(); 215 rp.AlignWithPadding();
128 216
129 if (Session()->IsDomain() && 217 if (Session()->GetSessionRequestManager()->IsDomain() &&
130 ((command_header->type == IPC::CommandType::Request || 218 ((command_header->type == IPC::CommandType::Request ||
131 command_header->type == IPC::CommandType::RequestWithContext) || 219 command_header->type == IPC::CommandType::RequestWithContext) ||
132 !incoming)) { 220 !incoming)) {
@@ -135,7 +223,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
135 if (incoming || domain_message_header) { 223 if (incoming || domain_message_header) {
136 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); 224 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
137 } else { 225 } else {
138 if (Session()->IsDomain()) { 226 if (Session()->GetSessionRequestManager()->IsDomain()) {
139 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); 227 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
140 } 228 }
141 } 229 }
@@ -228,12 +316,12 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
228 // Write the domain objects to the command buffer, these go after the raw untranslated data. 316 // Write the domain objects to the command buffer, these go after the raw untranslated data.
229 // TODO(Subv): This completely ignores C buffers. 317 // TODO(Subv): This completely ignores C buffers.
230 318
231 if (Session()->IsDomain()) { 319 if (server_session->GetSessionRequestManager()->IsDomain()) {
232 current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); 320 current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size());
233 for (const auto& object : outgoing_domain_objects) { 321 for (auto& object : outgoing_domain_objects) {
234 server_session->AppendDomainHandler(object); 322 server_session->GetSessionRequestManager()->AppendDomainHandler(std::move(object));
235 cmd_buf[current_offset++] = 323 cmd_buf[current_offset++] = static_cast<u32_le>(
236 static_cast<u32_le>(server_session->NumDomainRequestHandlers()); 324 server_session->GetSessionRequestManager()->DomainHandlerCount());
237 } 325 }
238 } 326 }
239 327
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index e258e2cdf..a0522bca0 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -121,6 +121,10 @@ public:
121 is_domain = true; 121 is_domain = true;
122 } 122 }
123 123
124 void ConvertToDomainOnRequestEnd() {
125 convert_to_domain = true;
126 }
127
124 std::size_t DomainHandlerCount() const { 128 std::size_t DomainHandlerCount() const {
125 return domain_handlers.size(); 129 return domain_handlers.size();
126 } 130 }
@@ -164,7 +168,12 @@ public:
164 168
165 bool HasSessionRequestHandler(const HLERequestContext& context) const; 169 bool HasSessionRequestHandler(const HLERequestContext& context) const;
166 170
171 Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context);
172 Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context);
173 Result QueueSyncRequest(KSession* parent, std::shared_ptr<HLERequestContext>&& context);
174
167private: 175private:
176 bool convert_to_domain{};
168 bool is_domain{}; 177 bool is_domain{};
169 SessionRequestHandlerPtr session_handler; 178 SessionRequestHandlerPtr session_handler;
170 std::vector<SessionRequestHandlerPtr> domain_handlers; 179 std::vector<SessionRequestHandlerPtr> domain_handlers;
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index c84d36c8c..477e4e407 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -18,6 +18,7 @@
18#include "core/hle/kernel/k_process.h" 18#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/k_resource_limit.h" 19#include "core/hle/kernel/k_resource_limit.h"
20#include "core/hle/kernel/k_session.h" 20#include "core/hle/kernel/k_session.h"
21#include "core/hle/kernel/k_session_request.h"
21#include "core/hle/kernel/k_shared_memory.h" 22#include "core/hle/kernel/k_shared_memory.h"
22#include "core/hle/kernel/k_shared_memory_info.h" 23#include "core/hle/kernel/k_shared_memory_info.h"
23#include "core/hle/kernel/k_system_control.h" 24#include "core/hle/kernel/k_system_control.h"
@@ -34,6 +35,7 @@ namespace Kernel::Init {
34 HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ 35 HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \
35 HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ 36 HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
36 HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ 37 HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
38 HANDLER(KSessionRequest, (SLAB_COUNT(KSession) * 2), ##__VA_ARGS__) \
37 HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ 39 HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
38 HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \ 40 HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \
39 HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ 41 HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp
index 8892c5b7c..b4197a8d5 100644
--- a/src/core/hle/kernel/k_client_session.cpp
+++ b/src/core/hle/kernel/k_client_session.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 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 "common/scope_exit.h"
4#include "core/hle/kernel/hle_ipc.h" 5#include "core/hle/kernel/hle_ipc.h"
5#include "core/hle/kernel/k_client_session.h" 6#include "core/hle/kernel/k_client_session.h"
6#include "core/hle/kernel/k_server_session.h" 7#include "core/hle/kernel/k_server_session.h"
@@ -10,6 +11,8 @@
10 11
11namespace Kernel { 12namespace Kernel {
12 13
14static constexpr u32 MessageBufferSize = 0x100;
15
13KClientSession::KClientSession(KernelCore& kernel_) 16KClientSession::KClientSession(KernelCore& kernel_)
14 : KAutoObjectWithSlabHeapAndContainer{kernel_} {} 17 : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
15KClientSession::~KClientSession() = default; 18KClientSession::~KClientSession() = default;
@@ -22,8 +25,16 @@ void KClientSession::Destroy() {
22void KClientSession::OnServerClosed() {} 25void KClientSession::OnServerClosed() {}
23 26
24Result KClientSession::SendSyncRequest() { 27Result KClientSession::SendSyncRequest() {
25 // Signal the server session that new data is available 28 // Create a session request.
26 return parent->GetServerSession().OnRequest(); 29 KSessionRequest* request = KSessionRequest::Create(kernel);
30 R_UNLESS(request != nullptr, ResultOutOfResource);
31 SCOPE_EXIT({ request->Close(); });
32
33 // Initialize the request.
34 request->Initialize(nullptr, GetCurrentThread(kernel).GetTLSAddress(), MessageBufferSize);
35
36 // Send the request.
37 return parent->GetServerSession().OnRequest(request);
27} 38}
28 39
29} // namespace Kernel 40} // namespace Kernel
diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h
index 78859ced3..29ebd16b7 100644
--- a/src/core/hle/kernel/k_linked_list.h
+++ b/src/core/hle/kernel/k_linked_list.h
@@ -16,6 +16,7 @@ class KLinkedListNode : public boost::intrusive::list_base_hook<>,
16 public KSlabAllocated<KLinkedListNode> { 16 public KSlabAllocated<KLinkedListNode> {
17 17
18public: 18public:
19 explicit KLinkedListNode(KernelCore&) {}
19 KLinkedListNode() = default; 20 KLinkedListNode() = default;
20 21
21 void Initialize(void* it) { 22 void Initialize(void* it) {
diff --git a/src/core/hle/kernel/k_page_buffer.h b/src/core/hle/kernel/k_page_buffer.h
index 7e50dc1d1..aef06e213 100644
--- a/src/core/hle/kernel/k_page_buffer.h
+++ b/src/core/hle/kernel/k_page_buffer.h
@@ -13,6 +13,7 @@ namespace Kernel {
13 13
14class KPageBuffer final : public KSlabAllocated<KPageBuffer> { 14class KPageBuffer final : public KSlabAllocated<KPageBuffer> {
15public: 15public:
16 explicit KPageBuffer(KernelCore&) {}
16 KPageBuffer() = default; 17 KPageBuffer() = default;
17 18
18 static KPageBuffer* FromPhysicalAddress(Core::System& system, PAddr phys_addr); 19 static KPageBuffer* FromPhysicalAddress(Core::System& system, PAddr phys_addr);
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 4252c9adb..faf03fcc8 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -22,15 +22,12 @@
22#include "core/hle/kernel/k_thread.h" 22#include "core/hle/kernel/k_thread.h"
23#include "core/hle/kernel/k_thread_queue.h" 23#include "core/hle/kernel/k_thread_queue.h"
24#include "core/hle/kernel/kernel.h" 24#include "core/hle/kernel/kernel.h"
25#include "core/hle/kernel/service_thread.h"
26#include "core/memory.h" 25#include "core/memory.h"
27 26
28namespace Kernel { 27namespace Kernel {
29 28
30using ThreadQueueImplForKServerSessionRequest = KThreadQueue; 29using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
31 30
32static constexpr u32 MessageBufferSize = 0x100;
33
34KServerSession::KServerSession(KernelCore& kernel_) 31KServerSession::KServerSession(KernelCore& kernel_)
35 : KSynchronizationObject{kernel_}, m_lock{kernel_} {} 32 : KSynchronizationObject{kernel_}, m_lock{kernel_} {}
36 33
@@ -73,59 +70,7 @@ bool KServerSession::IsSignaled() const {
73 } 70 }
74 71
75 // Otherwise, we're signaled if we have a request and aren't handling one. 72 // Otherwise, we're signaled if we have a request and aren't handling one.
76 return !m_thread_request_list.empty() && m_current_thread_request == nullptr; 73 return !m_request_list.empty() && m_current_request == nullptr;
77}
78
79void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) {
80 manager->AppendDomainHandler(std::move(handler));
81}
82
83std::size_t KServerSession::NumDomainRequestHandlers() const {
84 return manager->DomainHandlerCount();
85}
86
87Result KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
88 if (!context.HasDomainMessageHeader()) {
89 return ResultSuccess;
90 }
91
92 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
93 context.SetSessionRequestManager(manager);
94
95 // If there is a DomainMessageHeader, then this is CommandType "Request"
96 const auto& domain_message_header = context.GetDomainMessageHeader();
97 const u32 object_id{domain_message_header.object_id};
98 switch (domain_message_header.command) {
99 case IPC::DomainMessageHeader::CommandType::SendMessage:
100 if (object_id > manager->DomainHandlerCount()) {
101 LOG_CRITICAL(IPC,
102 "object_id {} is too big! This probably means a recent service call "
103 "to {} needed to return a new interface!",
104 object_id, name);
105 ASSERT(false);
106 return ResultSuccess; // Ignore error if asserts are off
107 }
108 if (auto strong_ptr = manager->DomainHandler(object_id - 1).lock()) {
109 return strong_ptr->HandleSyncRequest(*this, context);
110 } else {
111 ASSERT(false);
112 return ResultSuccess;
113 }
114
115 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
116 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
117
118 manager->CloseDomainHandler(object_id - 1);
119
120 IPC::ResponseBuilder rb{context, 2};
121 rb.Push(ResultSuccess);
122 return ResultSuccess;
123 }
124 }
125
126 LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value());
127 ASSERT(false);
128 return ResultSuccess;
129} 74}
130 75
131Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { 76Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
@@ -134,43 +79,11 @@ Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& m
134 79
135 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); 80 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
136 81
137 // Ensure we have a session request handler 82 return manager->QueueSyncRequest(parent, std::move(context));
138 if (manager->HasSessionRequestHandler(*context)) {
139 if (auto strong_ptr = manager->GetServiceThread().lock()) {
140 strong_ptr->QueueSyncRequest(*parent, std::move(context));
141 } else {
142 ASSERT_MSG(false, "strong_ptr is nullptr!");
143 }
144 } else {
145 ASSERT_MSG(false, "handler is invalid!");
146 }
147
148 return ResultSuccess;
149} 83}
150 84
151Result KServerSession::CompleteSyncRequest(HLERequestContext& context) { 85Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
152 Result result = ResultSuccess; 86 Result result = manager->CompleteSyncRequest(this, context);
153
154 // If the session has been converted to a domain, handle the domain request
155 if (manager->HasSessionRequestHandler(context)) {
156 if (IsDomain() && context.HasDomainMessageHeader()) {
157 result = HandleDomainSyncRequest(context);
158 // If there is no domain header, the regular session handler is used
159 } else if (manager->HasSessionHandler()) {
160 // If this ServerSession has an associated HLE handler, forward the request to it.
161 result = manager->SessionHandler().HandleSyncRequest(*this, context);
162 }
163 } else {
164 ASSERT_MSG(false, "Session handler is invalid, stubbing response!");
165 IPC::ResponseBuilder rb(context, 2);
166 rb.Push(ResultSuccess);
167 }
168
169 if (convert_to_domain) {
170 ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance.");
171 manager->ConvertToDomain();
172 convert_to_domain = false;
173 }
174 87
175 // The calling thread is waiting for this request to complete, so wake it up. 88 // The calling thread is waiting for this request to complete, so wake it up.
176 context.GetThread().EndWait(result); 89 context.GetThread().EndWait(result);
@@ -178,7 +91,7 @@ Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
178 return result; 91 return result;
179} 92}
180 93
181Result KServerSession::OnRequest() { 94Result KServerSession::OnRequest(KSessionRequest* request) {
182 // Create the wait queue. 95 // Create the wait queue.
183 ThreadQueueImplForKServerSessionRequest wait_queue{kernel}; 96 ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
184 97
@@ -198,14 +111,13 @@ Result KServerSession::OnRequest() {
198 this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory); 111 this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
199 } else { 112 } else {
200 // Non-HLE request. 113 // Non-HLE request.
201 auto* thread{GetCurrentThreadPointer(kernel)};
202 114
203 // Get whether we're empty. 115 // Get whether we're empty.
204 const bool was_empty = m_thread_request_list.empty(); 116 const bool was_empty = m_request_list.empty();
205 117
206 // Add the thread to the list. 118 // Add the request to the list.
207 thread->Open(); 119 request->Open();
208 m_thread_request_list.push_back(thread); 120 m_request_list.push_back(*request);
209 121
210 // If we were empty, signal. 122 // If we were empty, signal.
211 if (was_empty) { 123 if (was_empty) {
@@ -213,6 +125,9 @@ Result KServerSession::OnRequest() {
213 } 125 }
214 } 126 }
215 127
128 // If we have a request event, this is asynchronous, and we don't need to wait.
129 R_SUCCEED_IF(request->GetEvent() != nullptr);
130
216 // This is a synchronous request, so we should wait for our request to complete. 131 // This is a synchronous request, so we should wait for our request to complete.
217 GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); 132 GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
218 GetCurrentThread(kernel).BeginWait(&wait_queue); 133 GetCurrentThread(kernel).BeginWait(&wait_queue);
@@ -223,32 +138,32 @@ Result KServerSession::OnRequest() {
223 138
224Result KServerSession::SendReply() { 139Result KServerSession::SendReply() {
225 // Lock the session. 140 // Lock the session.
226 KScopedLightLock lk(m_lock); 141 KScopedLightLock lk{m_lock};
227 142
228 // Get the request. 143 // Get the request.
229 KThread* client_thread; 144 KSessionRequest* request;
230 { 145 {
231 KScopedSchedulerLock sl{kernel}; 146 KScopedSchedulerLock sl{kernel};
232 147
233 // Get the current request. 148 // Get the current request.
234 client_thread = m_current_thread_request; 149 request = m_current_request;
235 R_UNLESS(client_thread != nullptr, ResultInvalidState); 150 R_UNLESS(request != nullptr, ResultInvalidState);
236 151
237 // Clear the current request, since we're processing it. 152 // Clear the current request, since we're processing it.
238 m_current_thread_request = nullptr; 153 m_current_request = nullptr;
239 if (!m_thread_request_list.empty()) { 154 if (!m_request_list.empty()) {
240 this->NotifyAvailable(); 155 this->NotifyAvailable();
241 } 156 }
242 } 157 }
243 158
244 // Close reference to the request once we're done processing it. 159 // Close reference to the request once we're done processing it.
245 SCOPE_EXIT({ client_thread->Close(); }); 160 SCOPE_EXIT({ request->Close(); });
246 161
247 // Extract relevant information from the request. 162 // Extract relevant information from the request.
248 // const uintptr_t client_message = request->GetAddress(); 163 const uintptr_t client_message = request->GetAddress();
249 // const size_t client_buffer_size = request->GetSize(); 164 const size_t client_buffer_size = request->GetSize();
250 // KThread *client_thread = request->GetThread(); 165 KThread* client_thread = request->GetThread();
251 // KEvent *event = request->GetEvent(); 166 KEvent* event = request->GetEvent();
252 167
253 // Check whether we're closed. 168 // Check whether we're closed.
254 const bool closed = (client_thread == nullptr || parent->IsClientClosed()); 169 const bool closed = (client_thread == nullptr || parent->IsClientClosed());
@@ -261,8 +176,8 @@ Result KServerSession::SendReply() {
261 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); 176 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
262 177
263 auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); 178 auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
264 auto* dst_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress()); 179 auto* dst_msg_buffer = memory.GetPointer(client_message);
265 std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize); 180 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
266 } else { 181 } else {
267 result = ResultSessionClosed; 182 result = ResultSessionClosed;
268 } 183 }
@@ -278,11 +193,30 @@ Result KServerSession::SendReply() {
278 193
279 // If there's a client thread, update it. 194 // If there's a client thread, update it.
280 if (client_thread != nullptr) { 195 if (client_thread != nullptr) {
281 // End the client thread's wait. 196 if (event != nullptr) {
282 KScopedSchedulerLock sl{kernel}; 197 // // Get the client process/page table.
198 // KProcess *client_process = client_thread->GetOwnerProcess();
199 // KPageTable *client_page_table = &client_process->PageTable();
200
201 // // If we need to, reply with an async error.
202 // if (R_FAILED(client_result)) {
203 // ReplyAsyncError(client_process, client_message, client_buffer_size,
204 // client_result);
205 // }
206
207 // // Unlock the client buffer.
208 // // NOTE: Nintendo does not check the result of this.
209 // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
210
211 // Signal the event.
212 event->Signal();
213 } else {
214 // End the client thread's wait.
215 KScopedSchedulerLock sl{kernel};
283 216
284 if (!client_thread->IsTerminationRequested()) { 217 if (!client_thread->IsTerminationRequested()) {
285 client_thread->EndWait(client_result); 218 client_thread->EndWait(client_result);
219 }
286 } 220 }
287 } 221 }
288 222
@@ -291,10 +225,10 @@ Result KServerSession::SendReply() {
291 225
292Result KServerSession::ReceiveRequest() { 226Result KServerSession::ReceiveRequest() {
293 // Lock the session. 227 // Lock the session.
294 KScopedLightLock lk(m_lock); 228 KScopedLightLock lk{m_lock};
295 229
296 // Get the request and client thread. 230 // Get the request and client thread.
297 // KSessionRequest *request; 231 KSessionRequest* request;
298 KThread* client_thread; 232 KThread* client_thread;
299 233
300 { 234 {
@@ -304,35 +238,41 @@ Result KServerSession::ReceiveRequest() {
304 R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed); 238 R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
305 239
306 // Ensure we aren't already servicing a request. 240 // Ensure we aren't already servicing a request.
307 R_UNLESS(m_current_thread_request == nullptr, ResultNotFound); 241 R_UNLESS(m_current_request == nullptr, ResultNotFound);
308 242
309 // Ensure we have a request to service. 243 // Ensure we have a request to service.
310 R_UNLESS(!m_thread_request_list.empty(), ResultNotFound); 244 R_UNLESS(!m_request_list.empty(), ResultNotFound);
311 245
312 // Pop the first request from the list. 246 // Pop the first request from the list.
313 client_thread = m_thread_request_list.front(); 247 request = &m_request_list.front();
314 m_thread_request_list.pop_front(); 248 m_request_list.pop_front();
315 249
316 // Get the thread for the request. 250 // Get the thread for the request.
251 client_thread = request->GetThread();
317 R_UNLESS(client_thread != nullptr, ResultSessionClosed); 252 R_UNLESS(client_thread != nullptr, ResultSessionClosed);
318 253
319 // Open the client thread. 254 // Open the client thread.
320 client_thread->Open(); 255 client_thread->Open();
321 } 256 }
322 257
323 // SCOPE_EXIT({ client_thread->Close(); }); 258 SCOPE_EXIT({ client_thread->Close(); });
324 259
325 // Set the request as our current. 260 // Set the request as our current.
326 m_current_thread_request = client_thread; 261 m_current_request = request;
262
263 // Get the client address.
264 uintptr_t client_message = request->GetAddress();
265 size_t client_buffer_size = request->GetSize();
266 // bool recv_list_broken = false;
327 267
328 // Receive the message. 268 // Receive the message.
329 Core::Memory::Memory& memory{kernel.System().Memory()}; 269 Core::Memory::Memory& memory{kernel.System().Memory()};
330 KThread* server_thread{GetCurrentThreadPointer(kernel)}; 270 KThread* server_thread{GetCurrentThreadPointer(kernel)};
331 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); 271 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
332 272
333 auto* src_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress()); 273 auto* src_msg_buffer = memory.GetPointer(client_message);
334 auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); 274 auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
335 std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize); 275 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
336 276
337 // We succeeded. 277 // We succeeded.
338 return ResultSuccess; 278 return ResultSuccess;
@@ -344,35 +284,34 @@ void KServerSession::CleanupRequests() {
344 // Clean up any pending requests. 284 // Clean up any pending requests.
345 while (true) { 285 while (true) {
346 // Get the next request. 286 // Get the next request.
347 // KSessionRequest *request = nullptr; 287 KSessionRequest* request = nullptr;
348 KThread* client_thread = nullptr;
349 { 288 {
350 KScopedSchedulerLock sl{kernel}; 289 KScopedSchedulerLock sl{kernel};
351 290
352 if (m_current_thread_request) { 291 if (m_current_request) {
353 // Choose the current request if we have one. 292 // Choose the current request if we have one.
354 client_thread = m_current_thread_request; 293 request = m_current_request;
355 m_current_thread_request = nullptr; 294 m_current_request = nullptr;
356 } else if (!m_thread_request_list.empty()) { 295 } else if (!m_request_list.empty()) {
357 // Pop the request from the front of the list. 296 // Pop the request from the front of the list.
358 client_thread = m_thread_request_list.front(); 297 request = &m_request_list.front();
359 m_thread_request_list.pop_front(); 298 m_request_list.pop_front();
360 } 299 }
361 } 300 }
362 301
363 // If there's no request, we're done. 302 // If there's no request, we're done.
364 if (client_thread == nullptr) { 303 if (request == nullptr) {
365 break; 304 break;
366 } 305 }
367 306
368 // Close a reference to the request once it's cleaned up. 307 // Close a reference to the request once it's cleaned up.
369 SCOPE_EXIT({ client_thread->Close(); }); 308 SCOPE_EXIT({ request->Close(); });
370 309
371 // Extract relevant information from the request. 310 // Extract relevant information from the request.
372 // const uintptr_t client_message = request->GetAddress(); 311 // const uintptr_t client_message = request->GetAddress();
373 // const size_t client_buffer_size = request->GetSize(); 312 // const size_t client_buffer_size = request->GetSize();
374 // KThread *client_thread = request->GetThread(); 313 KThread* client_thread = request->GetThread();
375 // KEvent *event = request->GetEvent(); 314 KEvent* event = request->GetEvent();
376 315
377 // KProcess *server_process = request->GetServerProcess(); 316 // KProcess *server_process = request->GetServerProcess();
378 // KProcess *client_process = (client_thread != nullptr) ? 317 // KProcess *client_process = (client_thread != nullptr) ?
@@ -385,11 +324,24 @@ void KServerSession::CleanupRequests() {
385 324
386 // If there's a client thread, update it. 325 // If there's a client thread, update it.
387 if (client_thread != nullptr) { 326 if (client_thread != nullptr) {
388 // End the client thread's wait. 327 if (event != nullptr) {
389 KScopedSchedulerLock sl{kernel}; 328 // // We need to reply async.
390 329 // ReplyAsyncError(client_process, client_message, client_buffer_size,
391 if (!client_thread->IsTerminationRequested()) { 330 // (R_SUCCEEDED(result) ? ResultSessionClosed : result));
392 client_thread->EndWait(ResultSessionClosed); 331
332 // // Unlock the client buffer.
333 // NOTE: Nintendo does not check the result of this.
334 // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
335
336 // Signal the event.
337 event->Signal();
338 } else {
339 // End the client thread's wait.
340 KScopedSchedulerLock sl{kernel};
341
342 if (!client_thread->IsTerminationRequested()) {
343 client_thread->EndWait(ResultSessionClosed);
344 }
393 } 345 }
394 } 346 }
395 } 347 }
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index 748d52826..32135473b 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -12,6 +12,7 @@
12 12
13#include "core/hle/kernel/hle_ipc.h" 13#include "core/hle/kernel/hle_ipc.h"
14#include "core/hle/kernel/k_light_lock.h" 14#include "core/hle/kernel/k_light_lock.h"
15#include "core/hle/kernel/k_session_request.h"
15#include "core/hle/kernel/k_synchronization_object.h" 16#include "core/hle/kernel/k_synchronization_object.h"
16#include "core/hle/result.h" 17#include "core/hle/result.h"
17 18
@@ -57,44 +58,15 @@ public:
57 } 58 }
58 59
59 bool IsSignaled() const override; 60 bool IsSignaled() const override;
60
61 void OnClientClosed(); 61 void OnClientClosed();
62 62
63 void ClientConnected(SessionRequestHandlerPtr handler) {
64 if (manager) {
65 manager->SetSessionHandler(std::move(handler));
66 }
67 }
68
69 void ClientDisconnected() {
70 manager = nullptr;
71 }
72
73 /// Adds a new domain request handler to the collection of request handlers within
74 /// this ServerSession instance.
75 void AppendDomainHandler(SessionRequestHandlerPtr handler);
76
77 /// Retrieves the total number of domain request handlers that have been
78 /// appended to this ServerSession instance.
79 std::size_t NumDomainRequestHandlers() const;
80
81 /// Returns true if the session has been converted to a domain, otherwise False
82 bool IsDomain() const {
83 return manager && manager->IsDomain();
84 }
85
86 /// Converts the session to a domain at the end of the current command
87 void ConvertToDomain() {
88 convert_to_domain = true;
89 }
90
91 /// Gets the session request manager, which forwards requests to the underlying service 63 /// Gets the session request manager, which forwards requests to the underlying service
92 std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() { 64 std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() {
93 return manager; 65 return manager;
94 } 66 }
95 67
96 /// TODO: flesh these out to match the real kernel 68 /// TODO: flesh these out to match the real kernel
97 Result OnRequest(); 69 Result OnRequest(KSessionRequest* request);
98 Result SendReply(); 70 Result SendReply();
99 Result ReceiveRequest(); 71 Result ReceiveRequest();
100 72
@@ -108,10 +80,6 @@ private:
108 /// Completes a sync request from the emulated application. 80 /// Completes a sync request from the emulated application.
109 Result CompleteSyncRequest(HLERequestContext& context); 81 Result CompleteSyncRequest(HLERequestContext& context);
110 82
111 /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
112 /// object handle.
113 Result HandleDomainSyncRequest(Kernel::HLERequestContext& context);
114
115 /// This session's HLE request handlers; if nullptr, this is not an HLE server 83 /// This session's HLE request handlers; if nullptr, this is not an HLE server
116 std::shared_ptr<SessionRequestManager> manager; 84 std::shared_ptr<SessionRequestManager> manager;
117 85
@@ -122,9 +90,8 @@ private:
122 KSession* parent{}; 90 KSession* parent{};
123 91
124 /// List of threads which are pending a reply. 92 /// List of threads which are pending a reply.
125 /// FIXME: KSessionRequest 93 boost::intrusive::list<KSessionRequest> m_request_list;
126 std::list<KThread*> m_thread_request_list; 94 KSessionRequest* m_current_request;
127 KThread* m_current_thread_request{};
128 95
129 KLightLock m_lock; 96 KLightLock m_lock;
130}; 97};
diff --git a/src/core/hle/kernel/k_session_request.cpp b/src/core/hle/kernel/k_session_request.cpp
new file mode 100644
index 000000000..520da6aa7
--- /dev/null
+++ b/src/core/hle/kernel/k_session_request.cpp
@@ -0,0 +1,61 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_page_buffer.h"
5#include "core/hle/kernel/k_session_request.h"
6
7namespace Kernel {
8
9Result KSessionRequest::SessionMappings::PushMap(VAddr client, VAddr server, size_t size,
10 KMemoryState state, size_t index) {
11 // At most 15 buffers of each type (4-bit descriptor counts).
12 ASSERT(index < ((1ul << 4) - 1) * 3);
13
14 // Get the mapping.
15 Mapping* mapping;
16 if (index < NumStaticMappings) {
17 mapping = &m_static_mappings[index];
18 } else {
19 // Allocate a page for the extra mappings.
20 if (m_mappings == nullptr) {
21 KPageBuffer* page_buffer = KPageBuffer::Allocate(kernel);
22 R_UNLESS(page_buffer != nullptr, ResultOutOfMemory);
23
24 m_mappings = reinterpret_cast<Mapping*>(page_buffer);
25 }
26
27 mapping = &m_mappings[index - NumStaticMappings];
28 }
29
30 // Set the mapping.
31 mapping->Set(client, server, size, state);
32
33 return ResultSuccess;
34}
35
36Result KSessionRequest::SessionMappings::PushSend(VAddr client, VAddr server, size_t size,
37 KMemoryState state) {
38 ASSERT(m_num_recv == 0);
39 ASSERT(m_num_exch == 0);
40 return this->PushMap(client, server, size, state, m_num_send++);
41}
42
43Result KSessionRequest::SessionMappings::PushReceive(VAddr client, VAddr server, size_t size,
44 KMemoryState state) {
45 ASSERT(m_num_exch == 0);
46 return this->PushMap(client, server, size, state, m_num_send + m_num_recv++);
47}
48
49Result KSessionRequest::SessionMappings::PushExchange(VAddr client, VAddr server, size_t size,
50 KMemoryState state) {
51 return this->PushMap(client, server, size, state, m_num_send + m_num_recv + m_num_exch++);
52}
53
54void KSessionRequest::SessionMappings::Finalize() {
55 if (m_mappings) {
56 KPageBuffer::Free(kernel, reinterpret_cast<KPageBuffer*>(m_mappings));
57 m_mappings = nullptr;
58 }
59}
60
61} // namespace Kernel
diff --git a/src/core/hle/kernel/k_session_request.h b/src/core/hle/kernel/k_session_request.h
new file mode 100644
index 000000000..fcf521597
--- /dev/null
+++ b/src/core/hle/kernel/k_session_request.h
@@ -0,0 +1,307 @@
1// SPDX-FileCopyrightText: Copyright 2022 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_event.h"
8#include "core/hle/kernel/k_memory_block.h"
9#include "core/hle/kernel/k_process.h"
10#include "core/hle/kernel/k_thread.h"
11#include "core/hle/kernel/slab_helpers.h"
12
13namespace Kernel {
14
15class KSessionRequest final : public KSlabAllocated<KSessionRequest>,
16 public KAutoObject,
17 public boost::intrusive::list_base_hook<> {
18 KERNEL_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject);
19
20public:
21 class SessionMappings {
22 private:
23 static constexpr size_t NumStaticMappings = 8;
24
25 class Mapping {
26 public:
27 constexpr void Set(VAddr c, VAddr s, size_t sz, KMemoryState st) {
28 m_client_address = c;
29 m_server_address = s;
30 m_size = sz;
31 m_state = st;
32 }
33
34 constexpr VAddr GetClientAddress() const {
35 return m_client_address;
36 }
37 constexpr VAddr GetServerAddress() const {
38 return m_server_address;
39 }
40 constexpr size_t GetSize() const {
41 return m_size;
42 }
43 constexpr KMemoryState GetMemoryState() const {
44 return m_state;
45 }
46
47 private:
48 VAddr m_client_address;
49 VAddr m_server_address;
50 size_t m_size;
51 KMemoryState m_state;
52 };
53
54 public:
55 explicit SessionMappings(KernelCore& kernel_)
56 : kernel(kernel_), m_mappings(nullptr), m_num_send(), m_num_recv(), m_num_exch() {}
57
58 void Initialize() {}
59 void Finalize();
60
61 size_t GetSendCount() const {
62 return m_num_send;
63 }
64 size_t GetReceiveCount() const {
65 return m_num_recv;
66 }
67 size_t GetExchangeCount() const {
68 return m_num_exch;
69 }
70
71 Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state);
72 Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state);
73 Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state);
74
75 VAddr GetSendClientAddress(size_t i) const {
76 return GetSendMapping(i).GetClientAddress();
77 }
78 VAddr GetSendServerAddress(size_t i) const {
79 return GetSendMapping(i).GetServerAddress();
80 }
81 size_t GetSendSize(size_t i) const {
82 return GetSendMapping(i).GetSize();
83 }
84 KMemoryState GetSendMemoryState(size_t i) const {
85 return GetSendMapping(i).GetMemoryState();
86 }
87
88 VAddr GetReceiveClientAddress(size_t i) const {
89 return GetReceiveMapping(i).GetClientAddress();
90 }
91 VAddr GetReceiveServerAddress(size_t i) const {
92 return GetReceiveMapping(i).GetServerAddress();
93 }
94 size_t GetReceiveSize(size_t i) const {
95 return GetReceiveMapping(i).GetSize();
96 }
97 KMemoryState GetReceiveMemoryState(size_t i) const {
98 return GetReceiveMapping(i).GetMemoryState();
99 }
100
101 VAddr GetExchangeClientAddress(size_t i) const {
102 return GetExchangeMapping(i).GetClientAddress();
103 }
104 VAddr GetExchangeServerAddress(size_t i) const {
105 return GetExchangeMapping(i).GetServerAddress();
106 }
107 size_t GetExchangeSize(size_t i) const {
108 return GetExchangeMapping(i).GetSize();
109 }
110 KMemoryState GetExchangeMemoryState(size_t i) const {
111 return GetExchangeMapping(i).GetMemoryState();
112 }
113
114 private:
115 Result PushMap(VAddr client, VAddr server, size_t size, KMemoryState state, size_t index);
116
117 const Mapping& GetSendMapping(size_t i) const {
118 ASSERT(i < m_num_send);
119
120 const size_t index = i;
121 if (index < NumStaticMappings) {
122 return m_static_mappings[index];
123 } else {
124 return m_mappings[index - NumStaticMappings];
125 }
126 }
127
128 const Mapping& GetReceiveMapping(size_t i) const {
129 ASSERT(i < m_num_recv);
130
131 const size_t index = m_num_send + i;
132 if (index < NumStaticMappings) {
133 return m_static_mappings[index];
134 } else {
135 return m_mappings[index - NumStaticMappings];
136 }
137 }
138
139 const Mapping& GetExchangeMapping(size_t i) const {
140 ASSERT(i < m_num_exch);
141
142 const size_t index = m_num_send + m_num_recv + i;
143 if (index < NumStaticMappings) {
144 return m_static_mappings[index];
145 } else {
146 return m_mappings[index - NumStaticMappings];
147 }
148 }
149
150 private:
151 KernelCore& kernel;
152 Mapping m_static_mappings[NumStaticMappings];
153 Mapping* m_mappings;
154 u8 m_num_send;
155 u8 m_num_recv;
156 u8 m_num_exch;
157 };
158
159public:
160 explicit KSessionRequest(KernelCore& kernel_)
161 : KAutoObject(kernel_), m_mappings(kernel_), m_thread(nullptr), m_server(nullptr),
162 m_event(nullptr) {}
163
164 static KSessionRequest* Create(KernelCore& kernel) {
165 KSessionRequest* req = KSessionRequest::Allocate(kernel);
166 if (req != nullptr) [[likely]] {
167 KAutoObject::Create(req);
168 }
169 return req;
170 }
171
172 void Destroy() override {
173 this->Finalize();
174 KSessionRequest::Free(kernel, this);
175 }
176
177 void Initialize(KEvent* event, uintptr_t address, size_t size) {
178 m_mappings.Initialize();
179
180 m_thread = GetCurrentThreadPointer(kernel);
181 m_event = event;
182 m_address = address;
183 m_size = size;
184
185 m_thread->Open();
186 if (m_event != nullptr) {
187 m_event->Open();
188 }
189 }
190
191 static void PostDestroy(uintptr_t arg) {}
192
193 KThread* GetThread() const {
194 return m_thread;
195 }
196 KEvent* GetEvent() const {
197 return m_event;
198 }
199 uintptr_t GetAddress() const {
200 return m_address;
201 }
202 size_t GetSize() const {
203 return m_size;
204 }
205 KProcess* GetServerProcess() const {
206 return m_server;
207 }
208
209 void SetServerProcess(KProcess* process) {
210 m_server = process;
211 m_server->Open();
212 }
213
214 void ClearThread() {
215 m_thread = nullptr;
216 }
217 void ClearEvent() {
218 m_event = nullptr;
219 }
220
221 size_t GetSendCount() const {
222 return m_mappings.GetSendCount();
223 }
224 size_t GetReceiveCount() const {
225 return m_mappings.GetReceiveCount();
226 }
227 size_t GetExchangeCount() const {
228 return m_mappings.GetExchangeCount();
229 }
230
231 Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state) {
232 return m_mappings.PushSend(client, server, size, state);
233 }
234
235 Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state) {
236 return m_mappings.PushReceive(client, server, size, state);
237 }
238
239 Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state) {
240 return m_mappings.PushExchange(client, server, size, state);
241 }
242
243 VAddr GetSendClientAddress(size_t i) const {
244 return m_mappings.GetSendClientAddress(i);
245 }
246 VAddr GetSendServerAddress(size_t i) const {
247 return m_mappings.GetSendServerAddress(i);
248 }
249 size_t GetSendSize(size_t i) const {
250 return m_mappings.GetSendSize(i);
251 }
252 KMemoryState GetSendMemoryState(size_t i) const {
253 return m_mappings.GetSendMemoryState(i);
254 }
255
256 VAddr GetReceiveClientAddress(size_t i) const {
257 return m_mappings.GetReceiveClientAddress(i);
258 }
259 VAddr GetReceiveServerAddress(size_t i) const {
260 return m_mappings.GetReceiveServerAddress(i);
261 }
262 size_t GetReceiveSize(size_t i) const {
263 return m_mappings.GetReceiveSize(i);
264 }
265 KMemoryState GetReceiveMemoryState(size_t i) const {
266 return m_mappings.GetReceiveMemoryState(i);
267 }
268
269 VAddr GetExchangeClientAddress(size_t i) const {
270 return m_mappings.GetExchangeClientAddress(i);
271 }
272 VAddr GetExchangeServerAddress(size_t i) const {
273 return m_mappings.GetExchangeServerAddress(i);
274 }
275 size_t GetExchangeSize(size_t i) const {
276 return m_mappings.GetExchangeSize(i);
277 }
278 KMemoryState GetExchangeMemoryState(size_t i) const {
279 return m_mappings.GetExchangeMemoryState(i);
280 }
281
282private:
283 // NOTE: This is public and virtual in Nintendo's kernel.
284 void Finalize() {
285 m_mappings.Finalize();
286
287 if (m_thread) {
288 m_thread->Close();
289 }
290 if (m_event) {
291 m_event->Close();
292 }
293 if (m_server) {
294 m_server->Close();
295 }
296 }
297
298private:
299 SessionMappings m_mappings;
300 KThread* m_thread;
301 KProcess* m_server;
302 KEvent* m_event;
303 uintptr_t m_address;
304 size_t m_size;
305};
306
307} // namespace Kernel
diff --git a/src/core/hle/kernel/k_shared_memory_info.h b/src/core/hle/kernel/k_shared_memory_info.h
index e43db8515..2bb6b6d08 100644
--- a/src/core/hle/kernel/k_shared_memory_info.h
+++ b/src/core/hle/kernel/k_shared_memory_info.h
@@ -15,7 +15,8 @@ class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>,
15 public boost::intrusive::list_base_hook<> { 15 public boost::intrusive::list_base_hook<> {
16 16
17public: 17public:
18 explicit KSharedMemoryInfo() = default; 18 explicit KSharedMemoryInfo(KernelCore&) {}
19 KSharedMemoryInfo() = default;
19 20
20 constexpr void Initialize(KSharedMemory* shmem) { 21 constexpr void Initialize(KSharedMemory* shmem) {
21 shared_memory = shmem; 22 shared_memory = shmem;
diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h
index 0a7f22680..5d466ace7 100644
--- a/src/core/hle/kernel/k_thread_local_page.h
+++ b/src/core/hle/kernel/k_thread_local_page.h
@@ -26,7 +26,7 @@ public:
26 static_assert(RegionsPerPage > 0); 26 static_assert(RegionsPerPage > 0);
27 27
28public: 28public:
29 constexpr explicit KThreadLocalPage(VAddr addr = {}) : m_virt_addr(addr) { 29 constexpr explicit KThreadLocalPage(KernelCore&, VAddr addr = {}) : m_virt_addr(addr) {
30 m_is_region_free.fill(true); 30 m_is_region_free.fill(true);
31 } 31 }
32 32
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 6eded9539..266be2bc4 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -47,6 +47,7 @@ class KResourceLimit;
47class KScheduler; 47class KScheduler;
48class KServerSession; 48class KServerSession;
49class KSession; 49class KSession;
50class KSessionRequest;
50class KSharedMemory; 51class KSharedMemory;
51class KSharedMemoryInfo; 52class KSharedMemoryInfo;
52class KThread; 53class KThread;
@@ -360,6 +361,8 @@ public:
360 return slab_heap_container->page_buffer; 361 return slab_heap_container->page_buffer;
361 } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { 362 } else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
362 return slab_heap_container->thread_local_page; 363 return slab_heap_container->thread_local_page;
364 } else if constexpr (std::is_same_v<T, KSessionRequest>) {
365 return slab_heap_container->session_request;
363 } 366 }
364 } 367 }
365 368
@@ -422,6 +425,7 @@ private:
422 KSlabHeap<KCodeMemory> code_memory; 425 KSlabHeap<KCodeMemory> code_memory;
423 KSlabHeap<KPageBuffer> page_buffer; 426 KSlabHeap<KPageBuffer> page_buffer;
424 KSlabHeap<KThreadLocalPage> thread_local_page; 427 KSlabHeap<KThreadLocalPage> thread_local_page;
428 KSlabHeap<KSessionRequest> session_request;
425 }; 429 };
426 430
427 std::unique_ptr<SlabHeapContainer> slab_heap_container; 431 std::unique_ptr<SlabHeapContainer> slab_heap_container;
diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h
index 299a981a8..06b51e919 100644
--- a/src/core/hle/kernel/slab_helpers.h
+++ b/src/core/hle/kernel/slab_helpers.h
@@ -24,7 +24,7 @@ public:
24 } 24 }
25 25
26 static Derived* Allocate(KernelCore& kernel) { 26 static Derived* Allocate(KernelCore& kernel) {
27 return kernel.SlabHeap<Derived>().Allocate(); 27 return kernel.SlabHeap<Derived>().Allocate(kernel);
28 } 28 }
29 29
30 static void Free(KernelCore& kernel, Derived* obj) { 30 static void Free(KernelCore& kernel, Derived* obj) {
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp
index 2a4bd64ab..273f79568 100644
--- a/src/core/hle/service/sm/sm_controller.cpp
+++ b/src/core/hle/service/sm/sm_controller.cpp
@@ -15,9 +15,10 @@
15namespace Service::SM { 15namespace Service::SM {
16 16
17void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { 17void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
18 ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain"); 18 ASSERT_MSG(!ctx.Session()->GetSessionRequestManager()->IsDomain(),
19 "Session is already a domain");
19 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); 20 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId());
20 ctx.Session()->ConvertToDomain(); 21 ctx.Session()->GetSessionRequestManager()->ConvertToDomainOnRequestEnd();
21 22
22 IPC::ResponseBuilder rb{ctx, 3}; 23 IPC::ResponseBuilder rb{ctx, 3};
23 rb.Push(ResultSuccess); 24 rb.Push(ResultSuccess);