diff options
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 152 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 25 |
2 files changed, 107 insertions, 70 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 6020e9764..b7070af03 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <boost/range/algorithm_ext/erase.hpp> | 5 | #include <boost/range/algorithm_ext/erase.hpp> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "core/hle/ipc_helpers.h" | ||
| 8 | #include "core/hle/kernel/handle_table.h" | 9 | #include "core/hle/kernel/handle_table.h" |
| 9 | #include "core/hle/kernel/hle_ipc.h" | 10 | #include "core/hle/kernel/hle_ipc.h" |
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| @@ -44,88 +45,103 @@ void HLERequestContext::ClearIncomingObjects() { | |||
| 44 | request_handles.clear(); | 45 | request_handles.clear(); |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, | 48 | void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf) { |
| 48 | Process& src_process, | 49 | IPC::RequestParser rp(src_cmdbuf); |
| 49 | HandleTable& src_table) { | 50 | command_header = std::make_unique<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); |
| 50 | IPC::Header header{src_cmdbuf[0]}; | ||
| 51 | 51 | ||
| 52 | size_t untranslated_size = 1u + header.normal_params_size; | 52 | // If handle descriptor is present, add size of it |
| 53 | size_t command_size = untranslated_size + header.translate_params_size; | 53 | if (command_header->enable_handle_descriptor) { |
| 54 | ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); // TODO(yuriks): Return error | 54 | handle_descriptor_header = |
| 55 | std::make_unique<IPC::HandleDescriptorHeader>(rp.PopRaw<IPC::HandleDescriptorHeader>()); | ||
| 56 | if (handle_descriptor_header->send_current_pid) { | ||
| 57 | rp.Skip(2, false); | ||
| 58 | } | ||
| 59 | rp.Skip(handle_descriptor_header->num_handles_to_copy, false); | ||
| 60 | rp.Skip(handle_descriptor_header->num_handles_to_move, false); | ||
| 61 | } | ||
| 55 | 62 | ||
| 56 | std::copy_n(src_cmdbuf, untranslated_size, cmd_buf.begin()); | 63 | // Padding to align to 16 bytes |
| 64 | rp.AlignWithPadding(); | ||
| 57 | 65 | ||
| 58 | size_t i = untranslated_size; | 66 | if (command_header->num_buf_x_descriptors) { |
| 59 | while (i < command_size) { | 67 | UNIMPLEMENTED(); |
| 60 | u32 descriptor = cmd_buf[i] = src_cmdbuf[i]; | 68 | } |
| 61 | i += 1; | 69 | if (command_header->num_buf_a_descriptors) { |
| 62 | 70 | UNIMPLEMENTED(); | |
| 63 | switch (IPC::GetDescriptorType(descriptor)) { | 71 | } |
| 64 | case IPC::DescriptorType::CopyHandle: | 72 | if (command_header->num_buf_b_descriptors) { |
| 65 | case IPC::DescriptorType::MoveHandle: { | 73 | UNIMPLEMENTED(); |
| 66 | u32 num_handles = IPC::HandleNumberFromDesc(descriptor); | 74 | } |
| 67 | ASSERT(i + num_handles <= command_size); // TODO(yuriks): Return error | 75 | if (command_header->num_buf_w_descriptors) { |
| 68 | for (u32 j = 0; j < num_handles; ++j) { | 76 | UNIMPLEMENTED(); |
| 69 | Handle handle = src_cmdbuf[i]; | 77 | } |
| 70 | SharedPtr<Object> object = nullptr; | 78 | if (command_header->buf_c_descriptor_flags != |
| 71 | if (handle != 0) { | 79 | IPC::CommandHeader::BufferDescriptorCFlag::Disabled) { |
| 72 | object = src_table.GetGeneric(handle); | 80 | UNIMPLEMENTED(); |
| 73 | ASSERT(object != nullptr); // TODO(yuriks): Return error | 81 | } |
| 74 | if (descriptor == IPC::DescriptorType::MoveHandle) { | ||
| 75 | src_table.Close(handle); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | 82 | ||
| 79 | cmd_buf[i++] = AddOutgoingHandle(std::move(object)); | 83 | data_payload_header = |
| 80 | } | 84 | std::make_unique<IPC::DataPayloadHeader>(rp.PopRaw<IPC::DataPayloadHeader>()); |
| 81 | break; | 85 | ASSERT(data_payload_header->magic == 0x49434653 || data_payload_header->magic == 0x4F434653); |
| 82 | } | 86 | |
| 83 | case IPC::DescriptorType::CallingPid: { | 87 | data_payload_offset = rp.GetCurrentOffset(); |
| 84 | cmd_buf[i++] = src_process.process_id; | 88 | command = rp.Pop<u32_le>(); |
| 85 | break; | 89 | } |
| 86 | } | 90 | |
| 87 | default: | 91 | ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, |
| 88 | UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | 92 | Process& src_process, |
| 93 | HandleTable& src_table) { | ||
| 94 | ParseCommandBuffer(src_cmdbuf); | ||
| 95 | size_t untranslated_size = data_payload_offset + command_header->data_size; | ||
| 96 | std::copy_n(src_cmdbuf, untranslated_size, cmd_buf.begin()); | ||
| 97 | |||
| 98 | if (command_header->enable_handle_descriptor) { | ||
| 99 | if (handle_descriptor_header->num_handles_to_copy || | ||
| 100 | handle_descriptor_header->num_handles_to_move) { | ||
| 101 | UNIMPLEMENTED(); | ||
| 89 | } | 102 | } |
| 90 | } | 103 | } |
| 91 | |||
| 92 | return RESULT_SUCCESS; | 104 | return RESULT_SUCCESS; |
| 93 | } | 105 | } |
| 94 | 106 | ||
| 95 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, | 107 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, |
| 96 | HandleTable& dst_table) const { | 108 | HandleTable& dst_table) { |
| 97 | IPC::Header header{cmd_buf[0]}; | 109 | ParseCommandBuffer(&cmd_buf[0]); |
| 98 | 110 | size_t untranslated_size = data_payload_offset + command_header->data_size; | |
| 99 | size_t untranslated_size = 1u + header.normal_params_size; | ||
| 100 | size_t command_size = untranslated_size + header.translate_params_size; | ||
| 101 | ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); | ||
| 102 | |||
| 103 | std::copy_n(cmd_buf.begin(), untranslated_size, dst_cmdbuf); | 111 | std::copy_n(cmd_buf.begin(), untranslated_size, dst_cmdbuf); |
| 104 | 112 | ||
| 105 | size_t i = untranslated_size; | 113 | if (command_header->enable_handle_descriptor) { |
| 106 | while (i < command_size) { | 114 | size_t command_size = untranslated_size + handle_descriptor_header->num_handles_to_copy + |
| 107 | u32 descriptor = dst_cmdbuf[i] = cmd_buf[i]; | 115 | handle_descriptor_header->num_handles_to_move; |
| 108 | i += 1; | 116 | ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); |
| 109 | 117 | ||
| 110 | switch (IPC::GetDescriptorType(descriptor)) { | 118 | size_t untranslated_index = untranslated_size; |
| 111 | case IPC::DescriptorType::CopyHandle: | 119 | size_t handle_write_offset = 3; |
| 112 | case IPC::DescriptorType::MoveHandle: { | 120 | while (untranslated_index < command_size) { |
| 113 | // HLE services don't use handles, so we treat both CopyHandle and MoveHandle equally | 121 | u32 descriptor = cmd_buf[untranslated_index]; |
| 114 | u32 num_handles = IPC::HandleNumberFromDesc(descriptor); | 122 | untranslated_index += 1; |
| 115 | ASSERT(i + num_handles <= command_size); | 123 | |
| 116 | for (u32 j = 0; j < num_handles; ++j) { | 124 | switch (IPC::GetDescriptorType(descriptor)) { |
| 117 | SharedPtr<Object> object = GetIncomingHandle(cmd_buf[i]); | 125 | case IPC::DescriptorType::CopyHandle: |
| 118 | Handle handle = 0; | 126 | case IPC::DescriptorType::MoveHandle: { |
| 119 | if (object != nullptr) { | 127 | // HLE services don't use handles, so we treat both CopyHandle and MoveHandle |
| 120 | // TODO(yuriks): Figure out the proper error handling for if this fails | 128 | // equally |
| 121 | handle = dst_table.Create(object).Unwrap(); | 129 | u32 num_handles = IPC::HandleNumberFromDesc(descriptor); |
| 130 | for (u32 j = 0; j < num_handles; ++j) { | ||
| 131 | SharedPtr<Object> object = GetIncomingHandle(cmd_buf[untranslated_index]); | ||
| 132 | Handle handle = 0; | ||
| 133 | if (object != nullptr) { | ||
| 134 | // TODO(yuriks): Figure out the proper error handling for if this fails | ||
| 135 | handle = dst_table.Create(object).Unwrap(); | ||
| 136 | } | ||
| 137 | dst_cmdbuf[handle_write_offset++] = handle; | ||
| 138 | untranslated_index++; | ||
| 122 | } | 139 | } |
| 123 | dst_cmdbuf[i++] = handle; | 140 | break; |
| 141 | } | ||
| 142 | default: | ||
| 143 | UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | ||
| 124 | } | 144 | } |
| 125 | break; | ||
| 126 | } | ||
| 127 | default: | ||
| 128 | UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | ||
| 129 | } | 145 | } |
| 130 | } | 146 | } |
| 131 | 147 | ||
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 35795fc1d..32a528968 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -119,18 +119,39 @@ public: | |||
| 119 | */ | 119 | */ |
| 120 | void ClearIncomingObjects(); | 120 | void ClearIncomingObjects(); |
| 121 | 121 | ||
| 122 | void ParseCommandBuffer(u32_le* src_cmdbuf); | ||
| 123 | |||
| 122 | /// Populates this context with data from the requesting process/thread. | 124 | /// Populates this context with data from the requesting process/thread. |
| 123 | ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, | 125 | ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, |
| 124 | HandleTable& src_table); | 126 | HandleTable& src_table); |
| 125 | /// Writes data from this context back to the requesting process/thread. | 127 | /// Writes data from this context back to the requesting process/thread. |
| 126 | ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, | 128 | ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, |
| 127 | HandleTable& dst_table) const; | 129 | HandleTable& dst_table); |
| 130 | |||
| 131 | u32_le GetCommand() const { | ||
| 132 | return command; | ||
| 133 | } | ||
| 134 | |||
| 135 | IPC::CommandType GetCommandType() const { | ||
| 136 | return command_header->type; | ||
| 137 | } | ||
| 138 | |||
| 139 | unsigned GetDataPayloadOffset() const { | ||
| 140 | return data_payload_offset; | ||
| 141 | } | ||
| 128 | 142 | ||
| 129 | private: | 143 | private: |
| 130 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; | 144 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; |
| 131 | SharedPtr<ServerSession> session; | 145 | SharedPtr<ServerSession> session; |
| 132 | // TODO(yuriks): Check common usage of this and optimize size accordingly | 146 | // TODO(yuriks): Check common usage of this and optimize size accordingly |
| 133 | boost::container::small_vector<SharedPtr<Object>, 8> request_handles; | 147 | boost::container::small_vector<SharedPtr<Object>, 8> request_handles; |
| 148 | |||
| 149 | std::unique_ptr<IPC::CommandHeader> command_header; | ||
| 150 | std::unique_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header; | ||
| 151 | std::unique_ptr<IPC::DataPayloadHeader> data_payload_header; | ||
| 152 | |||
| 153 | unsigned data_payload_offset{}; | ||
| 154 | u32_le command{}; | ||
| 134 | }; | 155 | }; |
| 135 | 156 | ||
| 136 | } // namespace Kernel | 157 | } // namespace Kernel |