summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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/k_server_session.cpp89
-rw-r--r--src/core/hle/kernel/k_server_session.h33
-rw-r--r--src/core/hle/service/sm/sm_controller.cpp5
6 files changed, 119 insertions, 138 deletions
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/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 685a2a6e6..faf03fcc8 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -22,7 +22,6 @@
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 {
@@ -74,101 +73,17 @@ bool KServerSession::IsSignaled() const {
74 return !m_request_list.empty() && m_current_request == nullptr; 73 return !m_request_list.empty() && m_current_request == nullptr;
75} 74}
76 75
77void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) {
78 manager->AppendDomainHandler(std::move(handler));
79}
80
81std::size_t KServerSession::NumDomainRequestHandlers() const {
82 return manager->DomainHandlerCount();
83}
84
85Result KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
86 if (!context.HasDomainMessageHeader()) {
87 return ResultSuccess;
88 }
89
90 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
91 context.SetSessionRequestManager(manager);
92
93 // If there is a DomainMessageHeader, then this is CommandType "Request"
94 const auto& domain_message_header = context.GetDomainMessageHeader();
95 const u32 object_id{domain_message_header.object_id};
96 switch (domain_message_header.command) {
97 case IPC::DomainMessageHeader::CommandType::SendMessage:
98 if (object_id > manager->DomainHandlerCount()) {
99 LOG_CRITICAL(IPC,
100 "object_id {} is too big! This probably means a recent service call "
101 "to {} needed to return a new interface!",
102 object_id, name);
103 ASSERT(false);
104 return ResultSuccess; // Ignore error if asserts are off
105 }
106 if (auto strong_ptr = manager->DomainHandler(object_id - 1).lock()) {
107 return strong_ptr->HandleSyncRequest(*this, context);
108 } else {
109 ASSERT(false);
110 return ResultSuccess;
111 }
112
113 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
114 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
115
116 manager->CloseDomainHandler(object_id - 1);
117
118 IPC::ResponseBuilder rb{context, 2};
119 rb.Push(ResultSuccess);
120 return ResultSuccess;
121 }
122 }
123
124 LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value());
125 ASSERT(false);
126 return ResultSuccess;
127}
128
129Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { 76Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
130 u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; 77 u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
131 auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread); 78 auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread);
132 79
133 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); 80 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
134 81
135 // Ensure we have a session request handler 82 return manager->QueueSyncRequest(parent, std::move(context));
136 if (manager->HasSessionRequestHandler(*context)) {
137 if (auto strong_ptr = manager->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} 83}
148 84
149Result KServerSession::CompleteSyncRequest(HLERequestContext& context) { 85Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
150 Result result = ResultSuccess; 86 Result result = manager->CompleteSyncRequest(this, context);
151
152 // If the session has been converted to a domain, handle the domain request
153 if (manager->HasSessionRequestHandler(context)) {
154 if (IsDomain() && context.HasDomainMessageHeader()) {
155 result = HandleDomainSyncRequest(context);
156 // If there is no domain header, the regular session handler is used
157 } else if (manager->HasSessionHandler()) {
158 // If this ServerSession has an associated HLE handler, forward the request to it.
159 result = manager->SessionHandler().HandleSyncRequest(*this, context);
160 }
161 } else {
162 ASSERT_MSG(false, "Session handler is invalid, stubbing response!");
163 IPC::ResponseBuilder rb(context, 2);
164 rb.Push(ResultSuccess);
165 }
166
167 if (convert_to_domain) {
168 ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance.");
169 manager->ConvertToDomain();
170 convert_to_domain = false;
171 }
172 87
173 // 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.
174 context.GetThread().EndWait(result); 89 context.GetThread().EndWait(result);
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index c40ff4aaf..32135473b 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -58,37 +58,8 @@ public:
58 } 58 }
59 59
60 bool IsSignaled() const override; 60 bool IsSignaled() const override;
61
62 void OnClientClosed(); 61 void OnClientClosed();
63 62
64 void ClientConnected(SessionRequestHandlerPtr handler) {
65 if (manager) {
66 manager->SetSessionHandler(std::move(handler));
67 }
68 }
69
70 void ClientDisconnected() {
71 manager = nullptr;
72 }
73
74 /// Adds a new domain request handler to the collection of request handlers within
75 /// this ServerSession instance.
76 void AppendDomainHandler(SessionRequestHandlerPtr handler);
77
78 /// Retrieves the total number of domain request handlers that have been
79 /// appended to this ServerSession instance.
80 std::size_t NumDomainRequestHandlers() const;
81
82 /// Returns true if the session has been converted to a domain, otherwise False
83 bool IsDomain() const {
84 return manager && manager->IsDomain();
85 }
86
87 /// Converts the session to a domain at the end of the current command
88 void ConvertToDomain() {
89 convert_to_domain = true;
90 }
91
92 /// 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
93 std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() { 64 std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() {
94 return manager; 65 return manager;
@@ -109,10 +80,6 @@ private:
109 /// Completes a sync request from the emulated application. 80 /// Completes a sync request from the emulated application.
110 Result CompleteSyncRequest(HLERequestContext& context); 81 Result CompleteSyncRequest(HLERequestContext& context);
111 82
112 /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
113 /// object handle.
114 Result HandleDomainSyncRequest(Kernel::HLERequestContext& context);
115
116 /// 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
117 std::shared_ptr<SessionRequestManager> manager; 84 std::shared_ptr<SessionRequestManager> manager;
118 85
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);