summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp152
-rw-r--r--src/core/hle/kernel/hle_ipc.h25
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
47ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, 48void 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: 91ResultCode 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
95ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, 107ResultCode 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
129private: 143private:
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