k_server_session.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <tuple>
  4. #include <utility>
  5. #include "common/assert.h"
  6. #include "common/common_types.h"
  7. #include "common/logging/log.h"
  8. #include "common/scope_exit.h"
  9. #include "core/core.h"
  10. #include "core/core_timing.h"
  11. #include "core/hle/ipc_helpers.h"
  12. #include "core/hle/kernel/hle_ipc.h"
  13. #include "core/hle/kernel/k_client_port.h"
  14. #include "core/hle/kernel/k_handle_table.h"
  15. #include "core/hle/kernel/k_process.h"
  16. #include "core/hle/kernel/k_scheduler.h"
  17. #include "core/hle/kernel/k_server_port.h"
  18. #include "core/hle/kernel/k_server_session.h"
  19. #include "core/hle/kernel/k_session.h"
  20. #include "core/hle/kernel/k_thread.h"
  21. #include "core/hle/kernel/k_thread_queue.h"
  22. #include "core/hle/kernel/kernel.h"
  23. #include "core/memory.h"
  24. namespace Kernel {
  25. using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
  26. KServerSession::KServerSession(KernelCore& kernel_)
  27. : KSynchronizationObject{kernel_}, m_lock{kernel_} {}
  28. KServerSession::~KServerSession() = default;
  29. void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
  30. std::shared_ptr<SessionRequestManager> manager_) {
  31. // Set member variables.
  32. parent = parent_session_;
  33. name = std::move(name_);
  34. manager = manager_;
  35. }
  36. void KServerSession::Destroy() {
  37. parent->OnServerClosed();
  38. this->CleanupRequests();
  39. parent->Close();
  40. // Release host emulation members.
  41. manager.reset();
  42. // Ensure that the global list tracking server objects does not hold on to a reference.
  43. kernel.UnregisterServerObject(this);
  44. }
  45. void KServerSession::OnClientClosed() {
  46. if (manager && manager->HasSessionHandler()) {
  47. manager->SessionHandler().ClientDisconnected(this);
  48. }
  49. }
  50. bool KServerSession::IsSignaled() const {
  51. ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
  52. // If the client is closed, we're always signaled.
  53. if (parent->IsClientClosed()) {
  54. return true;
  55. }
  56. // Otherwise, we're signaled if we have a request and aren't handling one.
  57. return !m_request_list.empty() && m_current_request == nullptr;
  58. }
  59. Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
  60. u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
  61. auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread);
  62. context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
  63. return manager->QueueSyncRequest(parent, std::move(context));
  64. }
  65. Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
  66. Result result = manager->CompleteSyncRequest(this, context);
  67. // The calling thread is waiting for this request to complete, so wake it up.
  68. context.GetThread().EndWait(result);
  69. return result;
  70. }
  71. Result KServerSession::OnRequest(KSessionRequest* request) {
  72. // Create the wait queue.
  73. ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
  74. {
  75. // Lock the scheduler.
  76. KScopedSchedulerLock sl{kernel};
  77. // Ensure that we can handle new requests.
  78. R_UNLESS(!parent->IsServerClosed(), ResultSessionClosed);
  79. // Check that we're not terminating.
  80. R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
  81. if (manager) {
  82. // HLE request.
  83. auto& memory{kernel.System().Memory()};
  84. this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
  85. } else {
  86. // Non-HLE request.
  87. // Get whether we're empty.
  88. const bool was_empty = m_request_list.empty();
  89. // Add the request to the list.
  90. request->Open();
  91. m_request_list.push_back(*request);
  92. // If we were empty, signal.
  93. if (was_empty) {
  94. this->NotifyAvailable();
  95. }
  96. }
  97. // If we have a request event, this is asynchronous, and we don't need to wait.
  98. R_SUCCEED_IF(request->GetEvent() != nullptr);
  99. // This is a synchronous request, so we should wait for our request to complete.
  100. GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
  101. GetCurrentThread(kernel).BeginWait(&wait_queue);
  102. }
  103. return GetCurrentThread(kernel).GetWaitResult();
  104. }
  105. Result KServerSession::SendReply() {
  106. // Lock the session.
  107. KScopedLightLock lk{m_lock};
  108. // Get the request.
  109. KSessionRequest* request;
  110. {
  111. KScopedSchedulerLock sl{kernel};
  112. // Get the current request.
  113. request = m_current_request;
  114. R_UNLESS(request != nullptr, ResultInvalidState);
  115. // Clear the current request, since we're processing it.
  116. m_current_request = nullptr;
  117. if (!m_request_list.empty()) {
  118. this->NotifyAvailable();
  119. }
  120. }
  121. // Close reference to the request once we're done processing it.
  122. SCOPE_EXIT({ request->Close(); });
  123. // Extract relevant information from the request.
  124. const uintptr_t client_message = request->GetAddress();
  125. const size_t client_buffer_size = request->GetSize();
  126. KThread* client_thread = request->GetThread();
  127. KEvent* event = request->GetEvent();
  128. // Check whether we're closed.
  129. const bool closed = (client_thread == nullptr || parent->IsClientClosed());
  130. Result result = ResultSuccess;
  131. if (!closed) {
  132. // If we're not closed, send the reply.
  133. Core::Memory::Memory& memory{kernel.System().Memory()};
  134. KThread* server_thread{GetCurrentThreadPointer(kernel)};
  135. UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
  136. auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
  137. auto* dst_msg_buffer = memory.GetPointer(client_message);
  138. std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
  139. } else {
  140. result = ResultSessionClosed;
  141. }
  142. // Select a result for the client.
  143. Result client_result = result;
  144. if (closed && R_SUCCEEDED(result)) {
  145. result = ResultSessionClosed;
  146. client_result = ResultSessionClosed;
  147. } else {
  148. result = ResultSuccess;
  149. }
  150. // If there's a client thread, update it.
  151. if (client_thread != nullptr) {
  152. if (event != nullptr) {
  153. // // Get the client process/page table.
  154. // KProcess *client_process = client_thread->GetOwnerProcess();
  155. // KPageTable *client_page_table = &client_process->PageTable();
  156. // // If we need to, reply with an async error.
  157. // if (R_FAILED(client_result)) {
  158. // ReplyAsyncError(client_process, client_message, client_buffer_size,
  159. // client_result);
  160. // }
  161. // // Unlock the client buffer.
  162. // // NOTE: Nintendo does not check the result of this.
  163. // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
  164. // Signal the event.
  165. event->Signal();
  166. } else {
  167. // End the client thread's wait.
  168. KScopedSchedulerLock sl{kernel};
  169. if (!client_thread->IsTerminationRequested()) {
  170. client_thread->EndWait(client_result);
  171. }
  172. }
  173. }
  174. return result;
  175. }
  176. Result KServerSession::ReceiveRequest() {
  177. // Lock the session.
  178. KScopedLightLock lk{m_lock};
  179. // Get the request and client thread.
  180. KSessionRequest* request;
  181. KThread* client_thread;
  182. {
  183. KScopedSchedulerLock sl{kernel};
  184. // Ensure that we can service the request.
  185. R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
  186. // Ensure we aren't already servicing a request.
  187. R_UNLESS(m_current_request == nullptr, ResultNotFound);
  188. // Ensure we have a request to service.
  189. R_UNLESS(!m_request_list.empty(), ResultNotFound);
  190. // Pop the first request from the list.
  191. request = &m_request_list.front();
  192. m_request_list.pop_front();
  193. // Get the thread for the request.
  194. client_thread = request->GetThread();
  195. R_UNLESS(client_thread != nullptr, ResultSessionClosed);
  196. // Open the client thread.
  197. client_thread->Open();
  198. }
  199. SCOPE_EXIT({ client_thread->Close(); });
  200. // Set the request as our current.
  201. m_current_request = request;
  202. // Get the client address.
  203. uintptr_t client_message = request->GetAddress();
  204. size_t client_buffer_size = request->GetSize();
  205. // bool recv_list_broken = false;
  206. // Receive the message.
  207. Core::Memory::Memory& memory{kernel.System().Memory()};
  208. KThread* server_thread{GetCurrentThreadPointer(kernel)};
  209. UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
  210. auto* src_msg_buffer = memory.GetPointer(client_message);
  211. auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
  212. std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
  213. // We succeeded.
  214. return ResultSuccess;
  215. }
  216. void KServerSession::CleanupRequests() {
  217. KScopedLightLock lk(m_lock);
  218. // Clean up any pending requests.
  219. while (true) {
  220. // Get the next request.
  221. KSessionRequest* request = nullptr;
  222. {
  223. KScopedSchedulerLock sl{kernel};
  224. if (m_current_request) {
  225. // Choose the current request if we have one.
  226. request = m_current_request;
  227. m_current_request = nullptr;
  228. } else if (!m_request_list.empty()) {
  229. // Pop the request from the front of the list.
  230. request = &m_request_list.front();
  231. m_request_list.pop_front();
  232. }
  233. }
  234. // If there's no request, we're done.
  235. if (request == nullptr) {
  236. break;
  237. }
  238. // Close a reference to the request once it's cleaned up.
  239. SCOPE_EXIT({ request->Close(); });
  240. // Extract relevant information from the request.
  241. // const uintptr_t client_message = request->GetAddress();
  242. // const size_t client_buffer_size = request->GetSize();
  243. KThread* client_thread = request->GetThread();
  244. KEvent* event = request->GetEvent();
  245. // KProcess *server_process = request->GetServerProcess();
  246. // KProcess *client_process = (client_thread != nullptr) ?
  247. // client_thread->GetOwnerProcess() : nullptr;
  248. // KProcessPageTable *client_page_table = (client_process != nullptr) ?
  249. // &client_process->GetPageTable() : nullptr;
  250. // Cleanup the mappings.
  251. // Result result = CleanupMap(request, server_process, client_page_table);
  252. // If there's a client thread, update it.
  253. if (client_thread != nullptr) {
  254. if (event != nullptr) {
  255. // // We need to reply async.
  256. // ReplyAsyncError(client_process, client_message, client_buffer_size,
  257. // (R_SUCCEEDED(result) ? ResultSessionClosed : result));
  258. // // Unlock the client buffer.
  259. // NOTE: Nintendo does not check the result of this.
  260. // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
  261. // Signal the event.
  262. event->Signal();
  263. } else {
  264. // End the client thread's wait.
  265. KScopedSchedulerLock sl{kernel};
  266. if (!client_thread->IsTerminationRequested()) {
  267. client_thread->EndWait(ResultSessionClosed);
  268. }
  269. }
  270. }
  271. }
  272. }
  273. } // namespace Kernel