hle_ipc.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <boost/range/algorithm_ext/erase.hpp>
  5. #include "common/assert.h"
  6. #include "common/common_funcs.h"
  7. #include "common/common_types.h"
  8. #include "core/hle/ipc_helpers.h"
  9. #include "core/hle/kernel/domain.h"
  10. #include "core/hle/kernel/handle_table.h"
  11. #include "core/hle/kernel/hle_ipc.h"
  12. #include "core/hle/kernel/kernel.h"
  13. #include "core/hle/kernel/process.h"
  14. #include "core/hle/kernel/server_session.h"
  15. namespace Kernel {
  16. void SessionRequestHandler::ClientConnected(SharedPtr<ServerSession> server_session) {
  17. server_session->SetHleHandler(shared_from_this());
  18. connected_sessions.push_back(server_session);
  19. }
  20. void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_session) {
  21. server_session->SetHleHandler(nullptr);
  22. boost::range::remove_erase(connected_sessions, server_session);
  23. }
  24. HLERequestContext::HLERequestContext(SharedPtr<Kernel::Domain> domain) : domain(std::move(domain)) {
  25. cmd_buf[0] = 0;
  26. }
  27. HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
  28. : server_session(std::move(server_session)) {
  29. cmd_buf[0] = 0;
  30. }
  31. HLERequestContext::~HLERequestContext() = default;
  32. SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const {
  33. ASSERT(id_from_cmdbuf < request_handles.size());
  34. return request_handles[id_from_cmdbuf];
  35. }
  36. u32 HLERequestContext::AddOutgoingHandle(SharedPtr<Object> object) {
  37. request_handles.push_back(std::move(object));
  38. return static_cast<u32>(request_handles.size() - 1);
  39. }
  40. void HLERequestContext::ClearIncomingObjects() {
  41. request_handles.clear();
  42. }
  43. void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
  44. IPC::RequestParser rp(src_cmdbuf);
  45. command_header = std::make_unique<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>());
  46. if (command_header->type == IPC::CommandType::Close) {
  47. // Close does not populate the rest of the IPC header
  48. return;
  49. }
  50. // If handle descriptor is present, add size of it
  51. if (command_header->enable_handle_descriptor) {
  52. handle_descriptor_header =
  53. std::make_unique<IPC::HandleDescriptorHeader>(rp.PopRaw<IPC::HandleDescriptorHeader>());
  54. if (handle_descriptor_header->send_current_pid) {
  55. rp.Skip(2, false);
  56. }
  57. rp.Skip(handle_descriptor_header->num_handles_to_copy, false);
  58. rp.Skip(handle_descriptor_header->num_handles_to_move, false);
  59. }
  60. for (unsigned i = 0; i < command_header->num_buf_x_descriptors; ++i) {
  61. buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
  62. }
  63. for (unsigned i = 0; i < command_header->num_buf_a_descriptors; ++i) {
  64. buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
  65. }
  66. for (unsigned i = 0; i < command_header->num_buf_b_descriptors; ++i) {
  67. buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
  68. }
  69. for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) {
  70. buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
  71. }
  72. if (command_header->buf_c_descriptor_flags !=
  73. IPC::CommandHeader::BufferDescriptorCFlag::Disabled) {
  74. UNIMPLEMENTED();
  75. }
  76. // Padding to align to 16 bytes
  77. rp.AlignWithPadding();
  78. if (IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {
  79. // If this is an incoming message, only CommandType "Request" has a domain header
  80. // All outgoing domain messages have the domain header
  81. domain_message_header =
  82. std::make_unique<IPC::DomainRequestMessageHeader>(rp.PopRaw<IPC::DomainRequestMessageHeader>());
  83. }
  84. data_payload_header =
  85. std::make_unique<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>());
  86. if (incoming) {
  87. ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I'));
  88. } else {
  89. ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
  90. }
  91. data_payload_offset = rp.GetCurrentOffset();
  92. command = rp.Pop<u32_le>();
  93. }
  94. ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf,
  95. Process& src_process,
  96. HandleTable& src_table) {
  97. ParseCommandBuffer(src_cmdbuf, true);
  98. size_t untranslated_size = data_payload_offset + command_header->data_size;
  99. std::copy_n(src_cmdbuf, untranslated_size, cmd_buf.begin());
  100. return RESULT_SUCCESS;
  101. }
  102. ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
  103. HandleTable& dst_table) {
  104. ParseCommandBuffer(&cmd_buf[0], false);
  105. size_t untranslated_size = data_payload_offset + command_header->data_size;
  106. std::copy_n(cmd_buf.begin(), untranslated_size, dst_cmdbuf);
  107. if (command_header->enable_handle_descriptor) {
  108. size_t command_size = untranslated_size + handle_descriptor_header->num_handles_to_copy +
  109. handle_descriptor_header->num_handles_to_move;
  110. ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH);
  111. size_t untranslated_index = untranslated_size;
  112. size_t handle_write_offset = 3;
  113. while (untranslated_index < command_size) {
  114. u32 descriptor = cmd_buf[untranslated_index];
  115. untranslated_index += 1;
  116. switch (IPC::GetDescriptorType(descriptor)) {
  117. case IPC::DescriptorType::CopyHandle:
  118. case IPC::DescriptorType::MoveHandle: {
  119. // HLE services don't use handles, so we treat both CopyHandle and MoveHandle
  120. // equally
  121. u32 num_handles = IPC::HandleNumberFromDesc(descriptor);
  122. for (u32 j = 0; j < num_handles; ++j) {
  123. SharedPtr<Object> object = GetIncomingHandle(cmd_buf[untranslated_index]);
  124. Handle handle = 0;
  125. if (object != nullptr) {
  126. // TODO(yuriks): Figure out the proper error handling for if this fails
  127. handle = dst_table.Create(object).Unwrap();
  128. }
  129. dst_cmdbuf[handle_write_offset++] = handle;
  130. untranslated_index++;
  131. }
  132. break;
  133. }
  134. default:
  135. UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor);
  136. }
  137. }
  138. }
  139. return RESULT_SUCCESS;
  140. }
  141. } // namespace Kernel