k_server_session.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. // SPDX-FileCopyrightText: Copyright 2022 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/kernel/k_client_port.h"
  12. #include "core/hle/kernel/k_handle_table.h"
  13. #include "core/hle/kernel/k_process.h"
  14. #include "core/hle/kernel/k_scheduler.h"
  15. #include "core/hle/kernel/k_server_port.h"
  16. #include "core/hle/kernel/k_server_session.h"
  17. #include "core/hle/kernel/k_session.h"
  18. #include "core/hle/kernel/k_thread.h"
  19. #include "core/hle/kernel/k_thread_queue.h"
  20. #include "core/hle/kernel/kernel.h"
  21. #include "core/hle/kernel/message_buffer.h"
  22. #include "core/hle/service/hle_ipc.h"
  23. #include "core/hle/service/ipc_helpers.h"
  24. #include "core/memory.h"
  25. namespace Kernel {
  26. namespace {
  27. template <bool MoveHandleAllowed>
  28. Result ProcessMessageSpecialData(KProcess& dst_process, KProcess& src_process, KThread& src_thread,
  29. MessageBuffer& dst_msg, const MessageBuffer& src_msg,
  30. MessageBuffer::SpecialHeader& src_special_header) {
  31. // Copy the special header to the destination.
  32. s32 offset = dst_msg.Set(src_special_header);
  33. // Copy the process ID.
  34. if (src_special_header.GetHasProcessId()) {
  35. offset = dst_msg.SetProcessId(offset, src_process.GetProcessId());
  36. }
  37. // Prepare to process handles.
  38. auto& dst_handle_table = dst_process.GetHandleTable();
  39. auto& src_handle_table = src_process.GetHandleTable();
  40. Result result = ResultSuccess;
  41. // Process copy handles.
  42. for (auto i = 0; i < src_special_header.GetCopyHandleCount(); ++i) {
  43. // Get the handles.
  44. const Handle src_handle = src_msg.GetHandle(offset);
  45. Handle dst_handle = Svc::InvalidHandle;
  46. // If we're in a success state, try to move the handle to the new table.
  47. if (R_SUCCEEDED(result) && src_handle != Svc::InvalidHandle) {
  48. KScopedAutoObject obj =
  49. src_handle_table.GetObjectForIpc(src_handle, std::addressof(src_thread));
  50. if (obj.IsNotNull()) {
  51. Result add_result =
  52. dst_handle_table.Add(std::addressof(dst_handle), obj.GetPointerUnsafe());
  53. if (R_FAILED(add_result)) {
  54. result = add_result;
  55. dst_handle = Svc::InvalidHandle;
  56. }
  57. } else {
  58. result = ResultInvalidHandle;
  59. }
  60. }
  61. // Set the handle.
  62. offset = dst_msg.SetHandle(offset, dst_handle);
  63. }
  64. // Process move handles.
  65. if constexpr (MoveHandleAllowed) {
  66. for (auto i = 0; i < src_special_header.GetMoveHandleCount(); ++i) {
  67. // Get the handles.
  68. const Handle src_handle = src_msg.GetHandle(offset);
  69. Handle dst_handle = Svc::InvalidHandle;
  70. // Whether or not we've succeeded, we need to remove the handles from the source table.
  71. if (src_handle != Svc::InvalidHandle) {
  72. if (R_SUCCEEDED(result)) {
  73. KScopedAutoObject obj =
  74. src_handle_table.GetObjectForIpcWithoutPseudoHandle(src_handle);
  75. if (obj.IsNotNull()) {
  76. Result add_result = dst_handle_table.Add(std::addressof(dst_handle),
  77. obj.GetPointerUnsafe());
  78. src_handle_table.Remove(src_handle);
  79. if (R_FAILED(add_result)) {
  80. result = add_result;
  81. dst_handle = Svc::InvalidHandle;
  82. }
  83. } else {
  84. result = ResultInvalidHandle;
  85. }
  86. } else {
  87. src_handle_table.Remove(src_handle);
  88. }
  89. }
  90. // Set the handle.
  91. offset = dst_msg.SetHandle(offset, dst_handle);
  92. }
  93. }
  94. R_RETURN(result);
  95. }
  96. void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buffer_size) {
  97. // Parse the message.
  98. const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size);
  99. const MessageBuffer::MessageHeader dst_header(dst_msg);
  100. const MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header);
  101. // Check that the size is big enough.
  102. if (MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) > dst_buffer_size) {
  103. return;
  104. }
  105. // Set the special header.
  106. int offset = dst_msg.Set(dst_special_header);
  107. // Clear the process id, if needed.
  108. if (dst_special_header.GetHasProcessId()) {
  109. offset = dst_msg.SetProcessId(offset, 0);
  110. }
  111. // Clear handles, as relevant.
  112. auto& dst_handle_table = dst_process.GetHandleTable();
  113. for (auto i = 0;
  114. i < (dst_special_header.GetCopyHandleCount() + dst_special_header.GetMoveHandleCount());
  115. ++i) {
  116. const Handle handle = dst_msg.GetHandle(offset);
  117. if (handle != Svc::InvalidHandle) {
  118. dst_handle_table.Remove(handle);
  119. }
  120. offset = dst_msg.SetHandle(offset, Svc::InvalidHandle);
  121. }
  122. }
  123. } // namespace
  124. using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
  125. KServerSession::KServerSession(KernelCore& kernel)
  126. : KSynchronizationObject{kernel}, m_lock{m_kernel} {}
  127. KServerSession::~KServerSession() = default;
  128. void KServerSession::Destroy() {
  129. m_parent->OnServerClosed();
  130. this->CleanupRequests();
  131. m_parent->Close();
  132. }
  133. void KServerSession::OnClientClosed() {
  134. KScopedLightLock lk{m_lock};
  135. // Handle any pending requests.
  136. KSessionRequest* prev_request = nullptr;
  137. while (true) {
  138. // Declare variables for processing the request.
  139. KSessionRequest* request = nullptr;
  140. KEvent* event = nullptr;
  141. KThread* thread = nullptr;
  142. bool cur_request = false;
  143. bool terminate = false;
  144. // Get the next request.
  145. {
  146. KScopedSchedulerLock sl{m_kernel};
  147. if (m_current_request != nullptr && m_current_request != prev_request) {
  148. // Set the request, open a reference as we process it.
  149. request = m_current_request;
  150. request->Open();
  151. cur_request = true;
  152. // Get thread and event for the request.
  153. thread = request->GetThread();
  154. event = request->GetEvent();
  155. // If the thread is terminating, handle that.
  156. if (thread->IsTerminationRequested()) {
  157. request->ClearThread();
  158. request->ClearEvent();
  159. terminate = true;
  160. }
  161. prev_request = request;
  162. } else if (!m_request_list.empty()) {
  163. // Pop the request from the front of the list.
  164. request = std::addressof(m_request_list.front());
  165. m_request_list.pop_front();
  166. // Get thread and event for the request.
  167. thread = request->GetThread();
  168. event = request->GetEvent();
  169. }
  170. }
  171. // If there are no requests, we're done.
  172. if (request == nullptr) {
  173. break;
  174. }
  175. // All requests must have threads.
  176. ASSERT(thread != nullptr);
  177. // Ensure that we close the request when done.
  178. SCOPE_EXIT({ request->Close(); });
  179. // If we're terminating, close a reference to the thread and event.
  180. if (terminate) {
  181. thread->Close();
  182. if (event != nullptr) {
  183. event->Close();
  184. }
  185. }
  186. // If we need to, reply.
  187. if (event != nullptr && !cur_request) {
  188. // There must be no mappings.
  189. ASSERT(request->GetSendCount() == 0);
  190. ASSERT(request->GetReceiveCount() == 0);
  191. ASSERT(request->GetExchangeCount() == 0);
  192. // // Get the process and page table.
  193. // KProcess *client_process = thread->GetOwnerProcess();
  194. // auto& client_pt = client_process->GetPageTable();
  195. // // Reply to the request.
  196. // ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(),
  197. // ResultSessionClosed);
  198. // // Unlock the buffer.
  199. // // NOTE: Nintendo does not check the result of this.
  200. // client_pt.UnlockForIpcUserBuffer(request->GetAddress(), request->GetSize());
  201. // Signal the event.
  202. event->Signal();
  203. }
  204. }
  205. // Notify.
  206. this->NotifyAvailable(ResultSessionClosed);
  207. }
  208. bool KServerSession::IsSignaled() const {
  209. ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
  210. // If the client is closed, we're always signaled.
  211. if (m_parent->IsClientClosed()) {
  212. return true;
  213. }
  214. // Otherwise, we're signaled if we have a request and aren't handling one.
  215. return !m_request_list.empty() && m_current_request == nullptr;
  216. }
  217. Result KServerSession::OnRequest(KSessionRequest* request) {
  218. // Create the wait queue.
  219. ThreadQueueImplForKServerSessionRequest wait_queue{m_kernel};
  220. {
  221. // Lock the scheduler.
  222. KScopedSchedulerLock sl{m_kernel};
  223. // Ensure that we can handle new requests.
  224. R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed);
  225. // Check that we're not terminating.
  226. R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(), ResultTerminationRequested);
  227. // Get whether we're empty.
  228. const bool was_empty = m_request_list.empty();
  229. // Add the request to the list.
  230. request->Open();
  231. m_request_list.push_back(*request);
  232. // If we were empty, signal.
  233. if (was_empty) {
  234. this->NotifyAvailable();
  235. }
  236. // If we have a request event, this is asynchronous, and we don't need to wait.
  237. R_SUCCEED_IF(request->GetEvent() != nullptr);
  238. // This is a synchronous request, so we should wait for our request to complete.
  239. GetCurrentThread(m_kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
  240. GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue));
  241. }
  242. return GetCurrentThread(m_kernel).GetWaitResult();
  243. }
  244. Result KServerSession::SendReply(bool is_hle) {
  245. // Lock the session.
  246. KScopedLightLock lk{m_lock};
  247. // Get the request.
  248. KSessionRequest* request;
  249. {
  250. KScopedSchedulerLock sl{m_kernel};
  251. // Get the current request.
  252. request = m_current_request;
  253. R_UNLESS(request != nullptr, ResultInvalidState);
  254. // Clear the current request, since we're processing it.
  255. m_current_request = nullptr;
  256. if (!m_request_list.empty()) {
  257. this->NotifyAvailable();
  258. }
  259. }
  260. // Close reference to the request once we're done processing it.
  261. SCOPE_EXIT({ request->Close(); });
  262. // Extract relevant information from the request.
  263. const uintptr_t client_message = request->GetAddress();
  264. const size_t client_buffer_size = request->GetSize();
  265. KThread* client_thread = request->GetThread();
  266. KEvent* event = request->GetEvent();
  267. // Check whether we're closed.
  268. const bool closed = (client_thread == nullptr || m_parent->IsClientClosed());
  269. Result result = ResultSuccess;
  270. if (!closed) {
  271. // If we're not closed, send the reply.
  272. if (is_hle) {
  273. // HLE servers write directly to a pointer to the thread command buffer. Therefore
  274. // the reply has already been written in this case.
  275. } else {
  276. Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
  277. KThread* server_thread = GetCurrentThreadPointer(m_kernel);
  278. KProcess& src_process = *client_thread->GetOwnerProcess();
  279. KProcess& dst_process = *server_thread->GetOwnerProcess();
  280. UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
  281. auto* src_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
  282. auto* dst_msg_buffer = memory.GetPointer<u32>(client_message);
  283. std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
  284. // Translate special header ad-hoc.
  285. MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
  286. MessageBuffer::MessageHeader src_header(src_msg);
  287. MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
  288. if (src_header.GetHasSpecialHeader()) {
  289. MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
  290. result = ProcessMessageSpecialData<true>(dst_process, src_process, *server_thread,
  291. dst_msg, src_msg, src_special_header);
  292. if (R_FAILED(result)) {
  293. CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
  294. }
  295. }
  296. }
  297. } else {
  298. result = ResultSessionClosed;
  299. }
  300. // Select a result for the client.
  301. Result client_result = result;
  302. if (closed && R_SUCCEEDED(result)) {
  303. result = ResultSessionClosed;
  304. client_result = ResultSessionClosed;
  305. } else {
  306. result = ResultSuccess;
  307. }
  308. // If there's a client thread, update it.
  309. if (client_thread != nullptr) {
  310. if (event != nullptr) {
  311. // // Get the client process/page table.
  312. // KProcess *client_process = client_thread->GetOwnerProcess();
  313. // KProcessPageTable *client_page_table = std::addressof(client_process->PageTable());
  314. // // If we need to, reply with an async error.
  315. // if (R_FAILED(client_result)) {
  316. // ReplyAsyncError(client_process, client_message, client_buffer_size,
  317. // client_result);
  318. // }
  319. // // Unlock the client buffer.
  320. // // NOTE: Nintendo does not check the result of this.
  321. // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
  322. // Signal the event.
  323. event->Signal();
  324. } else {
  325. // End the client thread's wait.
  326. KScopedSchedulerLock sl{m_kernel};
  327. if (!client_thread->IsTerminationRequested()) {
  328. client_thread->EndWait(client_result);
  329. }
  330. }
  331. }
  332. R_RETURN(result);
  333. }
  334. Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context,
  335. std::weak_ptr<Service::SessionRequestManager> manager) {
  336. // Lock the session.
  337. KScopedLightLock lk{m_lock};
  338. // Get the request and client thread.
  339. KSessionRequest* request;
  340. KThread* client_thread;
  341. {
  342. KScopedSchedulerLock sl{m_kernel};
  343. // Ensure that we can service the request.
  344. R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed);
  345. // Ensure we aren't already servicing a request.
  346. R_UNLESS(m_current_request == nullptr, ResultNotFound);
  347. // Ensure we have a request to service.
  348. R_UNLESS(!m_request_list.empty(), ResultNotFound);
  349. // Pop the first request from the list.
  350. request = std::addressof(m_request_list.front());
  351. m_request_list.pop_front();
  352. // Get the thread for the request.
  353. client_thread = request->GetThread();
  354. R_UNLESS(client_thread != nullptr, ResultSessionClosed);
  355. // Open the client thread.
  356. client_thread->Open();
  357. }
  358. SCOPE_EXIT({ client_thread->Close(); });
  359. // Set the request as our current.
  360. m_current_request = request;
  361. // Get the client address.
  362. uintptr_t client_message = request->GetAddress();
  363. size_t client_buffer_size = request->GetSize();
  364. // bool recv_list_broken = false;
  365. if (!client_message) {
  366. client_message = GetInteger(client_thread->GetTlsAddress());
  367. client_buffer_size = MessageBufferSize;
  368. }
  369. // Receive the message.
  370. Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
  371. if (out_context != nullptr) {
  372. // HLE request.
  373. u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))};
  374. *out_context =
  375. std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread);
  376. (*out_context)->SetSessionRequestManager(manager);
  377. (*out_context)
  378. ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
  379. cmd_buf);
  380. } else {
  381. KThread* server_thread = GetCurrentThreadPointer(m_kernel);
  382. KProcess& src_process = *client_thread->GetOwnerProcess();
  383. KProcess& dst_process = *server_thread->GetOwnerProcess();
  384. UNIMPLEMENTED_IF(client_thread->GetOwnerProcess() != server_thread->GetOwnerProcess());
  385. auto* src_msg_buffer = memory.GetPointer<u32>(client_message);
  386. auto* dst_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
  387. std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
  388. // Translate special header ad-hoc.
  389. // TODO: fix this mess
  390. MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
  391. MessageBuffer::MessageHeader src_header(src_msg);
  392. MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
  393. if (src_header.GetHasSpecialHeader()) {
  394. MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
  395. Result res = ProcessMessageSpecialData<false>(dst_process, src_process, *client_thread,
  396. dst_msg, src_msg, src_special_header);
  397. if (R_FAILED(res)) {
  398. CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
  399. }
  400. }
  401. }
  402. // We succeeded.
  403. R_SUCCEED();
  404. }
  405. void KServerSession::CleanupRequests() {
  406. KScopedLightLock lk(m_lock);
  407. // Clean up any pending requests.
  408. while (true) {
  409. // Get the next request.
  410. KSessionRequest* request = nullptr;
  411. {
  412. KScopedSchedulerLock sl{m_kernel};
  413. if (m_current_request) {
  414. // Choose the current request if we have one.
  415. request = m_current_request;
  416. m_current_request = nullptr;
  417. } else if (!m_request_list.empty()) {
  418. // Pop the request from the front of the list.
  419. request = std::addressof(m_request_list.front());
  420. m_request_list.pop_front();
  421. }
  422. }
  423. // If there's no request, we're done.
  424. if (request == nullptr) {
  425. break;
  426. }
  427. // Close a reference to the request once it's cleaned up.
  428. SCOPE_EXIT({ request->Close(); });
  429. // Extract relevant information from the request.
  430. // const uintptr_t client_message = request->GetAddress();
  431. // const size_t client_buffer_size = request->GetSize();
  432. KThread* client_thread = request->GetThread();
  433. KEvent* event = request->GetEvent();
  434. // KProcess *server_process = request->GetServerProcess();
  435. // KProcess *client_process = (client_thread != nullptr) ?
  436. // client_thread->GetOwnerProcess() : nullptr;
  437. // KProcessPageTable *client_page_table = (client_process != nullptr) ?
  438. // std::addressof(client_process->GetPageTable())
  439. // : nullptr;
  440. // Cleanup the mappings.
  441. // Result result = CleanupMap(request, server_process, client_page_table);
  442. // If there's a client thread, update it.
  443. if (client_thread != nullptr) {
  444. if (event != nullptr) {
  445. // // We need to reply async.
  446. // ReplyAsyncError(client_process, client_message, client_buffer_size,
  447. // (R_SUCCEEDED(result) ? ResultSessionClosed : result));
  448. // // Unlock the client buffer.
  449. // NOTE: Nintendo does not check the result of this.
  450. // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
  451. // Signal the event.
  452. event->Signal();
  453. } else {
  454. // End the client thread's wait.
  455. KScopedSchedulerLock sl{m_kernel};
  456. if (!client_thread->IsTerminationRequested()) {
  457. client_thread->EndWait(ResultSessionClosed);
  458. }
  459. }
  460. }
  461. }
  462. }
  463. } // namespace Kernel