svc_ipc.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/scope_exit.h"
  4. #include "core/core.h"
  5. #include "core/hle/kernel/k_client_session.h"
  6. #include "core/hle/kernel/k_process.h"
  7. #include "core/hle/kernel/k_server_session.h"
  8. #include "core/hle/kernel/svc.h"
  9. namespace Kernel::Svc {
  10. /// Makes a blocking IPC call to a service.
  11. Result SendSyncRequest(Core::System& system, Handle handle) {
  12. // Get the client session from its handle.
  13. KScopedAutoObject session =
  14. GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KClientSession>(handle);
  15. R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
  16. LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle);
  17. R_RETURN(session->SendSyncRequest());
  18. }
  19. Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer,
  20. uint64_t message_buffer_size, Handle session_handle) {
  21. UNIMPLEMENTED();
  22. R_THROW(ResultNotImplemented);
  23. }
  24. Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle,
  25. uint64_t message_buffer, uint64_t message_buffer_size,
  26. Handle session_handle) {
  27. UNIMPLEMENTED();
  28. R_THROW(ResultNotImplemented);
  29. }
  30. Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles,
  31. Handle reply_target, s64 timeout_ns) {
  32. auto& kernel = system.Kernel();
  33. auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
  34. R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
  35. R_UNLESS(system.Memory().IsValidVirtualAddressRange(
  36. handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
  37. ResultInvalidPointer);
  38. std::vector<Handle> handles(num_handles);
  39. system.Memory().ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles);
  40. // Convert handle list to object table.
  41. std::vector<KSynchronizationObject*> objs(num_handles);
  42. R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(),
  43. num_handles),
  44. ResultInvalidHandle);
  45. // Ensure handles are closed when we're done.
  46. SCOPE_EXIT({
  47. for (auto i = 0; i < num_handles; ++i) {
  48. objs[i]->Close();
  49. }
  50. });
  51. // Reply to the target, if one is specified.
  52. if (reply_target != InvalidHandle) {
  53. KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target);
  54. R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
  55. // If we fail to reply, we want to set the output index to -1.
  56. ON_RESULT_FAILURE {
  57. *out_index = -1;
  58. };
  59. // Send the reply.
  60. R_TRY(session->SendReply());
  61. }
  62. // Wait for a message.
  63. while (true) {
  64. // Wait for an object.
  65. s32 index;
  66. Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(),
  67. static_cast<s32>(objs.size()), timeout_ns);
  68. if (result == ResultTimedOut) {
  69. R_RETURN(result);
  70. }
  71. // Receive the request.
  72. if (R_SUCCEEDED(result)) {
  73. KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
  74. if (session != nullptr) {
  75. result = session->ReceiveRequest();
  76. if (result == ResultNotFound) {
  77. continue;
  78. }
  79. }
  80. }
  81. *out_index = index;
  82. R_RETURN(result);
  83. }
  84. }
  85. Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index,
  86. uint64_t message_buffer, uint64_t message_buffer_size,
  87. uint64_t handles, int32_t num_handles, Handle reply_target,
  88. int64_t timeout_ns) {
  89. UNIMPLEMENTED();
  90. R_THROW(ResultNotImplemented);
  91. }
  92. Result SendSyncRequest64(Core::System& system, Handle session_handle) {
  93. R_RETURN(SendSyncRequest(system, session_handle));
  94. }
  95. Result SendSyncRequestWithUserBuffer64(Core::System& system, uint64_t message_buffer,
  96. uint64_t message_buffer_size, Handle session_handle) {
  97. R_RETURN(
  98. SendSyncRequestWithUserBuffer(system, message_buffer, message_buffer_size, session_handle));
  99. }
  100. Result SendAsyncRequestWithUserBuffer64(Core::System& system, Handle* out_event_handle,
  101. uint64_t message_buffer, uint64_t message_buffer_size,
  102. Handle session_handle) {
  103. R_RETURN(SendAsyncRequestWithUserBuffer(system, out_event_handle, message_buffer,
  104. message_buffer_size, session_handle));
  105. }
  106. Result ReplyAndReceive64(Core::System& system, int32_t* out_index, uint64_t handles,
  107. int32_t num_handles, Handle reply_target, int64_t timeout_ns) {
  108. R_RETURN(ReplyAndReceive(system, out_index, handles, num_handles, reply_target, timeout_ns));
  109. }
  110. Result ReplyAndReceiveWithUserBuffer64(Core::System& system, int32_t* out_index,
  111. uint64_t message_buffer, uint64_t message_buffer_size,
  112. uint64_t handles, int32_t num_handles, Handle reply_target,
  113. int64_t timeout_ns) {
  114. R_RETURN(ReplyAndReceiveWithUserBuffer(system, out_index, message_buffer, message_buffer_size,
  115. handles, num_handles, reply_target, timeout_ns));
  116. }
  117. Result SendSyncRequest64From32(Core::System& system, Handle session_handle) {
  118. R_RETURN(SendSyncRequest(system, session_handle));
  119. }
  120. Result SendSyncRequestWithUserBuffer64From32(Core::System& system, uint32_t message_buffer,
  121. uint32_t message_buffer_size, Handle session_handle) {
  122. R_RETURN(
  123. SendSyncRequestWithUserBuffer(system, message_buffer, message_buffer_size, session_handle));
  124. }
  125. Result SendAsyncRequestWithUserBuffer64From32(Core::System& system, Handle* out_event_handle,
  126. uint32_t message_buffer, uint32_t message_buffer_size,
  127. Handle session_handle) {
  128. R_RETURN(SendAsyncRequestWithUserBuffer(system, out_event_handle, message_buffer,
  129. message_buffer_size, session_handle));
  130. }
  131. Result ReplyAndReceive64From32(Core::System& system, int32_t* out_index, uint32_t handles,
  132. int32_t num_handles, Handle reply_target, int64_t timeout_ns) {
  133. R_RETURN(ReplyAndReceive(system, out_index, handles, num_handles, reply_target, timeout_ns));
  134. }
  135. Result ReplyAndReceiveWithUserBuffer64From32(Core::System& system, int32_t* out_index,
  136. uint32_t message_buffer, uint32_t message_buffer_size,
  137. uint32_t handles, int32_t num_handles,
  138. Handle reply_target, int64_t timeout_ns) {
  139. R_RETURN(ReplyAndReceiveWithUserBuffer(system, out_index, message_buffer, message_buffer_size,
  140. handles, num_handles, reply_target, timeout_ns));
  141. }
  142. } // namespace Kernel::Svc