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.cpp107
-rw-r--r--src/core/hle/kernel/hle_ipc.h39
2 files changed, 72 insertions, 74 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index ac81dbf3f..518e44f33 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -37,20 +37,6 @@ HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_ses
37 37
38HLERequestContext::~HLERequestContext() = default; 38HLERequestContext::~HLERequestContext() = default;
39 39
40SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const {
41 ASSERT(id_from_cmdbuf < request_handles.size());
42 return request_handles[id_from_cmdbuf];
43}
44
45u32 HLERequestContext::AddOutgoingHandle(SharedPtr<Object> object) {
46 request_handles.push_back(std::move(object));
47 return static_cast<u32>(request_handles.size() - 1);
48}
49
50void HLERequestContext::ClearIncomingObjects() {
51 request_handles.clear();
52}
53
54void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { 40void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
55 IPC::RequestParser rp(src_cmdbuf); 41 IPC::RequestParser rp(src_cmdbuf);
56 command_header = std::make_unique<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); 42 command_header = std::make_unique<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>());
@@ -95,7 +81,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
95 // If this is an incoming message, only CommandType "Request" has a domain header 81 // If this is an incoming message, only CommandType "Request" has a domain header
96 // All outgoing domain messages have the domain header 82 // All outgoing domain messages have the domain header
97 domain_message_header = 83 domain_message_header =
98 std::make_unique<IPC::DomainRequestMessageHeader>(rp.PopRaw<IPC::DomainRequestMessageHeader>()); 84 std::make_unique<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>());
99 } 85 }
100 86
101 data_payload_header = 87 data_payload_header =
@@ -107,61 +93,78 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
107 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); 93 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
108 } 94 }
109 95
96 data_payload_offset = rp.GetCurrentOffset();
110 command = rp.Pop<u32_le>(); 97 command = rp.Pop<u32_le>();
111 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. 98 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
112 data_payload_offset = rp.GetCurrentOffset();
113} 99}
114 100
115ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, 101ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf,
116 Process& src_process, 102 Process& src_process,
117 HandleTable& src_table) { 103 HandleTable& src_table) {
118 ParseCommandBuffer(src_cmdbuf, true); 104 ParseCommandBuffer(src_cmdbuf, true);
119 size_t untranslated_size = data_payload_offset + command_header->data_size; 105 // The data_size already includes the payload header, the padding and the domain header.
120 std::copy_n(src_cmdbuf, untranslated_size, cmd_buf.begin()); 106 size_t size = data_payload_offset + command_header->data_size -
107 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
108 if (domain_message_header)
109 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
110 std::copy_n(src_cmdbuf, size, cmd_buf.begin());
121 return RESULT_SUCCESS; 111 return RESULT_SUCCESS;
122} 112}
123 113
124ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, 114ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
125 HandleTable& dst_table) { 115 HandleTable& dst_table) {
126 ParseCommandBuffer(&cmd_buf[0], false); 116 // The header was already built in the internal command buffer. Attempt to parse it to verify
127 size_t untranslated_size = data_payload_offset + command_header->data_size; 117 // the integrity and then copy it over to the target command buffer.
128 std::copy_n(cmd_buf.begin(), untranslated_size, dst_cmdbuf); 118 ParseCommandBuffer(cmd_buf.data(), false);
119
120 // The data_size already includes the payload header, the padding and the domain header.
121 size_t size = data_payload_offset + command_header->data_size -
122 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
123 if (domain_message_header)
124 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
125
126 std::copy_n(cmd_buf.begin(), size, dst_cmdbuf);
129 127
130 if (command_header->enable_handle_descriptor) { 128 if (command_header->enable_handle_descriptor) {
131 size_t command_size = untranslated_size + handle_descriptor_header->num_handles_to_copy + 129 ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(),
132 handle_descriptor_header->num_handles_to_move; 130 "Handle descriptor bit set but no handles to translate");
133 ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); 131 // We write the translated handles at a specific offset in the command buffer, this space
134 132 // was already reserved when writing the header.
135 size_t untranslated_index = untranslated_size; 133 size_t current_offset =
136 size_t handle_write_offset = 3; 134 (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32);
137 while (untranslated_index < command_size) { 135 ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented");
138 u32 descriptor = cmd_buf[untranslated_index]; 136
139 untranslated_index += 1; 137 ASSERT_MSG(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
140 138 ASSERT_MSG(move_objects.size() == handle_descriptor_header->num_handles_to_move);
141 switch (IPC::GetDescriptorType(descriptor)) { 139
142 case IPC::DescriptorType::CopyHandle: 140 // We don't make a distinction between copy and move handles when translating since HLE
143 case IPC::DescriptorType::MoveHandle: { 141 // services don't deal with handles directly. However, the guest applications might check
144 // HLE services don't use handles, so we treat both CopyHandle and MoveHandle 142 // for specific values in each of these descriptors.
145 // equally 143 for (auto& object : copy_objects) {
146 u32 num_handles = IPC::HandleNumberFromDesc(descriptor); 144 ASSERT(object != nullptr);
147 for (u32 j = 0; j < num_handles; ++j) { 145 dst_cmdbuf[current_offset++] = Kernel::g_handle_table.Create(object).Unwrap();
148 SharedPtr<Object> object = GetIncomingHandle(cmd_buf[untranslated_index]); 146 }
149 Handle handle = 0; 147
150 if (object != nullptr) { 148 for (auto& object : move_objects) {
151 // TODO(yuriks): Figure out the proper error handling for if this fails 149 ASSERT(object != nullptr);
152 handle = dst_table.Create(object).Unwrap(); 150 dst_cmdbuf[current_offset++] = Kernel::g_handle_table.Create(object).Unwrap();
153 }
154 dst_cmdbuf[handle_write_offset++] = handle;
155 untranslated_index++;
156 }
157 break;
158 }
159 default:
160 UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor);
161 }
162 } 151 }
163 } 152 }
164 153
154 // TODO(Subv): Translate the X/A/B/W buffers.
155
156 if (IsDomain()) {
157 ASSERT(domain_message_header->num_objects == domain_objects.size());
158 // Write the domain objects to the command buffer, these go after the raw untranslated data.
159 // TODO(Subv): This completely ignores C buffers.
160 size_t domain_offset = size - domain_message_header->num_objects;
161 auto& request_handlers = domain->request_handlers;
162
163 for (auto& object : domain_objects) {
164 request_handlers.emplace_back(object);
165 dst_cmdbuf[domain_offset++] = request_handlers.size();
166 }
167 }
165 return RESULT_SUCCESS; 168 return RESULT_SUCCESS;
166} 169}
167 170
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index b5649931d..48730a2b2 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -110,25 +110,6 @@ public:
110 return server_session; 110 return server_session;
111 } 111 }
112 112
113 /**
114 * Resolves a object id from the request command buffer into a pointer to an object. See the
115 * "HLE handle protocol" section in the class documentation for more details.
116 */
117 SharedPtr<Object> GetIncomingHandle(u32 id_from_cmdbuf) const;
118
119 /**
120 * Adds an outgoing object to the response, returning the id which should be used to reference
121 * it. See the "HLE handle protocol" section in the class documentation for more details.
122 */
123 u32 AddOutgoingHandle(SharedPtr<Object> object);
124
125 /**
126 * Discards all Objects from the context, invalidating all ids. This may be called after reading
127 * out all incoming objects, so that the buffer memory can be re-used for outgoing handles, but
128 * this is not required.
129 */
130 void ClearIncomingObjects();
131
132 void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming); 113 void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
133 114
134 /// Populates this context with data from the requesting process/thread. 115 /// Populates this context with data from the requesting process/thread.
@@ -158,7 +139,7 @@ public:
158 return buffer_a_desciptors; 139 return buffer_a_desciptors;
159 } 140 }
160 141
161 const std::unique_ptr<IPC::DomainRequestMessageHeader>& GetDomainMessageHeader() const { 142 const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const {
162 return domain_message_header; 143 return domain_message_header;
163 } 144 }
164 145
@@ -166,17 +147,31 @@ public:
166 return domain != nullptr; 147 return domain != nullptr;
167 } 148 }
168 149
150 void AddMoveObject(SharedPtr<Object> object) {
151 move_objects.emplace_back(std::move(object));
152 }
153
154 void AddCopyObject(SharedPtr<Object> object) {
155 copy_objects.emplace_back(std::move(object));
156 }
157
158 void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) {
159 domain_objects.emplace_back(std::move(object));
160 }
161
169private: 162private:
170 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 163 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
171 SharedPtr<Kernel::Domain> domain; 164 SharedPtr<Kernel::Domain> domain;
172 SharedPtr<Kernel::ServerSession> server_session; 165 SharedPtr<Kernel::ServerSession> server_session;
173 // TODO(yuriks): Check common usage of this and optimize size accordingly 166 // TODO(yuriks): Check common usage of this and optimize size accordingly
174 boost::container::small_vector<SharedPtr<Object>, 8> request_handles; 167 boost::container::small_vector<SharedPtr<Object>, 8> move_objects;
168 boost::container::small_vector<SharedPtr<Object>, 8> copy_objects;
169 boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
175 170
176 std::unique_ptr<IPC::CommandHeader> command_header; 171 std::unique_ptr<IPC::CommandHeader> command_header;
177 std::unique_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header; 172 std::unique_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header;
178 std::unique_ptr<IPC::DataPayloadHeader> data_payload_header; 173 std::unique_ptr<IPC::DataPayloadHeader> data_payload_header;
179 std::unique_ptr<IPC::DomainRequestMessageHeader> domain_message_header; 174 std::unique_ptr<IPC::DomainMessageHeader> domain_message_header;
180 std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; 175 std::vector<IPC::BufferDescriptorX> buffer_x_desciptors;
181 std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; 176 std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors;
182 std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; 177 std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors;