diff options
| author | 2023-03-03 22:51:17 -0500 | |
|---|---|---|
| committer | 2023-03-03 22:51:17 -0500 | |
| commit | ce8f4da63834be0179d98a7720dee47d65f3ec06 (patch) | |
| tree | a9a9303a532d374db9ae8255e5f3f2487e370f84 /src/core/hle/kernel | |
| parent | Merge pull request #9855 from liamwhite/kern-16-support (diff) | |
| parent | nvnflinger: fix name (diff) | |
| download | yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.tar.gz yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.tar.xz yuzu-ce8f4da63834be0179d98a7720dee47d65f3ec06.zip | |
Merge pull request #9884 from liamwhite/service-cleanup
service: miscellaneous cleanups
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 531 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 421 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_port.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_port.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_session.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_port.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.h | 12 |
8 files changed, 13 insertions, 966 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp deleted file mode 100644 index 876fbbe53..000000000 --- a/src/core/hle/kernel/hle_ipc.cpp +++ /dev/null | |||
| @@ -1,531 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <array> | ||
| 6 | #include <sstream> | ||
| 7 | |||
| 8 | #include <boost/range/algorithm_ext/erase.hpp> | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/common_funcs.h" | ||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "common/scratch_buffer.h" | ||
| 15 | #include "core/hle/ipc_helpers.h" | ||
| 16 | #include "core/hle/kernel/hle_ipc.h" | ||
| 17 | #include "core/hle/kernel/k_auto_object.h" | ||
| 18 | #include "core/hle/kernel/k_handle_table.h" | ||
| 19 | #include "core/hle/kernel/k_process.h" | ||
| 20 | #include "core/hle/kernel/k_server_port.h" | ||
| 21 | #include "core/hle/kernel/k_server_session.h" | ||
| 22 | #include "core/hle/kernel/k_thread.h" | ||
| 23 | #include "core/hle/kernel/kernel.h" | ||
| 24 | #include "core/memory.h" | ||
| 25 | |||
| 26 | namespace Kernel { | ||
| 27 | |||
| 28 | SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_) | ||
| 29 | : kernel{kernel_} {} | ||
| 30 | |||
| 31 | SessionRequestHandler::~SessionRequestHandler() = default; | ||
| 32 | |||
| 33 | SessionRequestManager::SessionRequestManager(KernelCore& kernel_, | ||
| 34 | Service::ServerManager& server_manager_) | ||
| 35 | : kernel{kernel_}, server_manager{server_manager_} {} | ||
| 36 | |||
| 37 | SessionRequestManager::~SessionRequestManager() = default; | ||
| 38 | |||
| 39 | bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& context) const { | ||
| 40 | if (IsDomain() && context.HasDomainMessageHeader()) { | ||
| 41 | const auto& message_header = context.GetDomainMessageHeader(); | ||
| 42 | const auto object_id = message_header.object_id; | ||
| 43 | |||
| 44 | if (object_id > DomainHandlerCount()) { | ||
| 45 | LOG_CRITICAL(IPC, "object_id {} is too big!", object_id); | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | return !DomainHandler(object_id - 1).expired(); | ||
| 49 | } else { | ||
| 50 | return session_handler != nullptr; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | Result SessionRequestManager::CompleteSyncRequest(KServerSession* server_session, | ||
| 55 | HLERequestContext& context) { | ||
| 56 | Result result = ResultSuccess; | ||
| 57 | |||
| 58 | // If the session has been converted to a domain, handle the domain request | ||
| 59 | if (this->HasSessionRequestHandler(context)) { | ||
| 60 | if (IsDomain() && context.HasDomainMessageHeader()) { | ||
| 61 | result = HandleDomainSyncRequest(server_session, context); | ||
| 62 | // If there is no domain header, the regular session handler is used | ||
| 63 | } else if (this->HasSessionHandler()) { | ||
| 64 | // If this manager has an associated HLE handler, forward the request to it. | ||
| 65 | result = this->SessionHandler().HandleSyncRequest(*server_session, context); | ||
| 66 | } | ||
| 67 | } else { | ||
| 68 | ASSERT_MSG(false, "Session handler is invalid, stubbing response!"); | ||
| 69 | IPC::ResponseBuilder rb(context, 2); | ||
| 70 | rb.Push(ResultSuccess); | ||
| 71 | } | ||
| 72 | |||
| 73 | if (convert_to_domain) { | ||
| 74 | ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance."); | ||
| 75 | this->ConvertToDomain(); | ||
| 76 | convert_to_domain = false; | ||
| 77 | } | ||
| 78 | |||
| 79 | return result; | ||
| 80 | } | ||
| 81 | |||
| 82 | Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_session, | ||
| 83 | HLERequestContext& context) { | ||
| 84 | if (!context.HasDomainMessageHeader()) { | ||
| 85 | return ResultSuccess; | ||
| 86 | } | ||
| 87 | |||
| 88 | // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs | ||
| 89 | ASSERT(context.GetManager().get() == this); | ||
| 90 | |||
| 91 | // If there is a DomainMessageHeader, then this is CommandType "Request" | ||
| 92 | const auto& domain_message_header = context.GetDomainMessageHeader(); | ||
| 93 | const u32 object_id{domain_message_header.object_id}; | ||
| 94 | switch (domain_message_header.command) { | ||
| 95 | case IPC::DomainMessageHeader::CommandType::SendMessage: | ||
| 96 | if (object_id > this->DomainHandlerCount()) { | ||
| 97 | LOG_CRITICAL(IPC, | ||
| 98 | "object_id {} is too big! This probably means a recent service call " | ||
| 99 | "needed to return a new interface!", | ||
| 100 | object_id); | ||
| 101 | ASSERT(false); | ||
| 102 | return ResultSuccess; // Ignore error if asserts are off | ||
| 103 | } | ||
| 104 | if (auto strong_ptr = this->DomainHandler(object_id - 1).lock()) { | ||
| 105 | return strong_ptr->HandleSyncRequest(*server_session, context); | ||
| 106 | } else { | ||
| 107 | ASSERT(false); | ||
| 108 | return ResultSuccess; | ||
| 109 | } | ||
| 110 | |||
| 111 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | ||
| 112 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); | ||
| 113 | |||
| 114 | this->CloseDomainHandler(object_id - 1); | ||
| 115 | |||
| 116 | IPC::ResponseBuilder rb{context, 2}; | ||
| 117 | rb.Push(ResultSuccess); | ||
| 118 | return ResultSuccess; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value()); | ||
| 123 | ASSERT(false); | ||
| 124 | return ResultSuccess; | ||
| 125 | } | ||
| 126 | |||
| 127 | HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, | ||
| 128 | KServerSession* server_session_, KThread* thread_) | ||
| 129 | : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} { | ||
| 130 | cmd_buf[0] = 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | HLERequestContext::~HLERequestContext() = default; | ||
| 134 | |||
| 135 | void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, | ||
| 136 | bool incoming) { | ||
| 137 | IPC::RequestParser rp(src_cmdbuf); | ||
| 138 | command_header = rp.PopRaw<IPC::CommandHeader>(); | ||
| 139 | |||
| 140 | if (command_header->IsCloseCommand()) { | ||
| 141 | // Close does not populate the rest of the IPC header | ||
| 142 | return; | ||
| 143 | } | ||
| 144 | |||
| 145 | // If handle descriptor is present, add size of it | ||
| 146 | if (command_header->enable_handle_descriptor) { | ||
| 147 | handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); | ||
| 148 | if (handle_descriptor_header->send_current_pid) { | ||
| 149 | pid = rp.Pop<u64>(); | ||
| 150 | } | ||
| 151 | if (incoming) { | ||
| 152 | // Populate the object lists with the data in the IPC request. | ||
| 153 | incoming_copy_handles.reserve(handle_descriptor_header->num_handles_to_copy); | ||
| 154 | incoming_move_handles.reserve(handle_descriptor_header->num_handles_to_move); | ||
| 155 | |||
| 156 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { | ||
| 157 | incoming_copy_handles.push_back(rp.Pop<Handle>()); | ||
| 158 | } | ||
| 159 | for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { | ||
| 160 | incoming_move_handles.push_back(rp.Pop<Handle>()); | ||
| 161 | } | ||
| 162 | } else { | ||
| 163 | // For responses we just ignore the handles, they're empty and will be populated when | ||
| 164 | // translating the response. | ||
| 165 | rp.Skip(handle_descriptor_header->num_handles_to_copy, false); | ||
| 166 | rp.Skip(handle_descriptor_header->num_handles_to_move, false); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); | ||
| 171 | buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); | ||
| 172 | buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); | ||
| 173 | buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); | ||
| 174 | |||
| 175 | for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { | ||
| 176 | buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); | ||
| 177 | } | ||
| 178 | for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { | ||
| 179 | buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | ||
| 180 | } | ||
| 181 | for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { | ||
| 182 | buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | ||
| 183 | } | ||
| 184 | for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { | ||
| 185 | buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); | ||
| 186 | } | ||
| 187 | |||
| 188 | const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; | ||
| 189 | |||
| 190 | if (!command_header->IsTipc()) { | ||
| 191 | // Padding to align to 16 bytes | ||
| 192 | rp.AlignWithPadding(); | ||
| 193 | |||
| 194 | if (GetManager()->IsDomain() && | ||
| 195 | ((command_header->type == IPC::CommandType::Request || | ||
| 196 | command_header->type == IPC::CommandType::RequestWithContext) || | ||
| 197 | !incoming)) { | ||
| 198 | // If this is an incoming message, only CommandType "Request" has a domain header | ||
| 199 | // All outgoing domain messages have the domain header, if only incoming has it | ||
| 200 | if (incoming || domain_message_header) { | ||
| 201 | domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); | ||
| 202 | } else { | ||
| 203 | if (GetManager()->IsDomain()) { | ||
| 204 | LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>(); | ||
| 210 | |||
| 211 | data_payload_offset = rp.GetCurrentOffset(); | ||
| 212 | |||
| 213 | if (domain_message_header && | ||
| 214 | domain_message_header->command == | ||
| 215 | IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) { | ||
| 216 | // CloseVirtualHandle command does not have SFC* or any data | ||
| 217 | return; | ||
| 218 | } | ||
| 219 | |||
| 220 | if (incoming) { | ||
| 221 | ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I')); | ||
| 222 | } else { | ||
| 223 | ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | rp.SetCurrentOffset(buffer_c_offset); | ||
| 228 | |||
| 229 | // For Inline buffers, the response data is written directly to buffer_c_offset | ||
| 230 | // and in this case we don't have any BufferDescriptorC on the request. | ||
| 231 | if (command_header->buf_c_descriptor_flags > | ||
| 232 | IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { | ||
| 233 | if (command_header->buf_c_descriptor_flags == | ||
| 234 | IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { | ||
| 235 | buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); | ||
| 236 | } else { | ||
| 237 | u32 num_buf_c_descriptors = | ||
| 238 | static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; | ||
| 239 | |||
| 240 | // This is used to detect possible underflows, in case something is broken | ||
| 241 | // with the two ifs above and the flags value is == 0 || == 1. | ||
| 242 | ASSERT(num_buf_c_descriptors < 14); | ||
| 243 | |||
| 244 | for (u32 i = 0; i < num_buf_c_descriptors; ++i) { | ||
| 245 | buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | rp.SetCurrentOffset(data_payload_offset); | ||
| 251 | |||
| 252 | command = rp.Pop<u32_le>(); | ||
| 253 | rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. | ||
| 254 | } | ||
| 255 | |||
| 256 | Result HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, | ||
| 257 | u32_le* src_cmdbuf) { | ||
| 258 | ParseCommandBuffer(handle_table, src_cmdbuf, true); | ||
| 259 | |||
| 260 | if (command_header->IsCloseCommand()) { | ||
| 261 | // Close does not populate the rest of the IPC header | ||
| 262 | return ResultSuccess; | ||
| 263 | } | ||
| 264 | |||
| 265 | std::copy_n(src_cmdbuf, IPC::COMMAND_BUFFER_LENGTH, cmd_buf.begin()); | ||
| 266 | |||
| 267 | return ResultSuccess; | ||
| 268 | } | ||
| 269 | |||
| 270 | Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) { | ||
| 271 | auto current_offset = handles_offset; | ||
| 272 | auto& owner_process = *requesting_thread.GetOwnerProcess(); | ||
| 273 | auto& handle_table = owner_process.GetHandleTable(); | ||
| 274 | |||
| 275 | for (auto& object : outgoing_copy_objects) { | ||
| 276 | Handle handle{}; | ||
| 277 | if (object) { | ||
| 278 | R_TRY(handle_table.Add(&handle, object)); | ||
| 279 | } | ||
| 280 | cmd_buf[current_offset++] = handle; | ||
| 281 | } | ||
| 282 | for (auto& object : outgoing_move_objects) { | ||
| 283 | Handle handle{}; | ||
| 284 | if (object) { | ||
| 285 | R_TRY(handle_table.Add(&handle, object)); | ||
| 286 | |||
| 287 | // Close our reference to the object, as it is being moved to the caller. | ||
| 288 | object->Close(); | ||
| 289 | } | ||
| 290 | cmd_buf[current_offset++] = handle; | ||
| 291 | } | ||
| 292 | |||
| 293 | // Write the domain objects to the command buffer, these go after the raw untranslated data. | ||
| 294 | // TODO(Subv): This completely ignores C buffers. | ||
| 295 | |||
| 296 | if (GetManager()->IsDomain()) { | ||
| 297 | current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); | ||
| 298 | for (auto& object : outgoing_domain_objects) { | ||
| 299 | GetManager()->AppendDomainHandler(std::move(object)); | ||
| 300 | cmd_buf[current_offset++] = static_cast<u32_le>(GetManager()->DomainHandlerCount()); | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | // Copy the translated command buffer back into the thread's command buffer area. | ||
| 305 | memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), | ||
| 306 | write_size * sizeof(u32)); | ||
| 307 | |||
| 308 | return ResultSuccess; | ||
| 309 | } | ||
| 310 | |||
| 311 | std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) const { | ||
| 312 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && | ||
| 313 | BufferDescriptorA()[buffer_index].Size()}; | ||
| 314 | if (is_buffer_a) { | ||
| 315 | ASSERT_OR_EXECUTE_MSG( | ||
| 316 | BufferDescriptorA().size() > buffer_index, { return {}; }, | ||
| 317 | "BufferDescriptorA invalid buffer_index {}", buffer_index); | ||
| 318 | std::vector<u8> buffer(BufferDescriptorA()[buffer_index].Size()); | ||
| 319 | memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); | ||
| 320 | return buffer; | ||
| 321 | } else { | ||
| 322 | ASSERT_OR_EXECUTE_MSG( | ||
| 323 | BufferDescriptorX().size() > buffer_index, { return {}; }, | ||
| 324 | "BufferDescriptorX invalid buffer_index {}", buffer_index); | ||
| 325 | std::vector<u8> buffer(BufferDescriptorX()[buffer_index].Size()); | ||
| 326 | memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); | ||
| 327 | return buffer; | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { | ||
| 332 | static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a; | ||
| 333 | static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x; | ||
| 334 | |||
| 335 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && | ||
| 336 | BufferDescriptorA()[buffer_index].Size()}; | ||
| 337 | if (is_buffer_a) { | ||
| 338 | ASSERT_OR_EXECUTE_MSG( | ||
| 339 | BufferDescriptorA().size() > buffer_index, { return {}; }, | ||
| 340 | "BufferDescriptorA invalid buffer_index {}", buffer_index); | ||
| 341 | auto& read_buffer = read_buffer_a[buffer_index]; | ||
| 342 | read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size()); | ||
| 343 | memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(), | ||
| 344 | read_buffer.size()); | ||
| 345 | return read_buffer; | ||
| 346 | } else { | ||
| 347 | ASSERT_OR_EXECUTE_MSG( | ||
| 348 | BufferDescriptorX().size() > buffer_index, { return {}; }, | ||
| 349 | "BufferDescriptorX invalid buffer_index {}", buffer_index); | ||
| 350 | auto& read_buffer = read_buffer_x[buffer_index]; | ||
| 351 | read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size()); | ||
| 352 | memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(), | ||
| 353 | read_buffer.size()); | ||
| 354 | return read_buffer; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, | ||
| 359 | std::size_t buffer_index) const { | ||
| 360 | if (size == 0) { | ||
| 361 | LOG_WARNING(Core, "skip empty buffer write"); | ||
| 362 | return 0; | ||
| 363 | } | ||
| 364 | |||
| 365 | const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && | ||
| 366 | BufferDescriptorB()[buffer_index].Size()}; | ||
| 367 | const std::size_t buffer_size{GetWriteBufferSize(buffer_index)}; | ||
| 368 | if (size > buffer_size) { | ||
| 369 | LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, | ||
| 370 | buffer_size); | ||
| 371 | size = buffer_size; // TODO(bunnei): This needs to be HW tested | ||
| 372 | } | ||
| 373 | |||
| 374 | if (is_buffer_b) { | ||
| 375 | ASSERT_OR_EXECUTE_MSG( | ||
| 376 | BufferDescriptorB().size() > buffer_index && | ||
| 377 | BufferDescriptorB()[buffer_index].Size() >= size, | ||
| 378 | { return 0; }, "BufferDescriptorB is invalid, index={}, size={}", buffer_index, size); | ||
| 379 | WriteBufferB(buffer, size, buffer_index); | ||
| 380 | } else { | ||
| 381 | ASSERT_OR_EXECUTE_MSG( | ||
| 382 | BufferDescriptorC().size() > buffer_index && | ||
| 383 | BufferDescriptorC()[buffer_index].Size() >= size, | ||
| 384 | { return 0; }, "BufferDescriptorC is invalid, index={}, size={}", buffer_index, size); | ||
| 385 | WriteBufferC(buffer, size, buffer_index); | ||
| 386 | } | ||
| 387 | |||
| 388 | return size; | ||
| 389 | } | ||
| 390 | |||
| 391 | std::size_t HLERequestContext::WriteBufferB(const void* buffer, std::size_t size, | ||
| 392 | std::size_t buffer_index) const { | ||
| 393 | if (buffer_index >= BufferDescriptorB().size() || size == 0) { | ||
| 394 | return 0; | ||
| 395 | } | ||
| 396 | |||
| 397 | const auto buffer_size{BufferDescriptorB()[buffer_index].Size()}; | ||
| 398 | if (size > buffer_size) { | ||
| 399 | LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, | ||
| 400 | buffer_size); | ||
| 401 | size = buffer_size; // TODO(bunnei): This needs to be HW tested | ||
| 402 | } | ||
| 403 | |||
| 404 | memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); | ||
| 405 | return size; | ||
| 406 | } | ||
| 407 | |||
| 408 | std::size_t HLERequestContext::WriteBufferC(const void* buffer, std::size_t size, | ||
| 409 | std::size_t buffer_index) const { | ||
| 410 | if (buffer_index >= BufferDescriptorC().size() || size == 0) { | ||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | |||
| 414 | const auto buffer_size{BufferDescriptorC()[buffer_index].Size()}; | ||
| 415 | if (size > buffer_size) { | ||
| 416 | LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, | ||
| 417 | buffer_size); | ||
| 418 | size = buffer_size; // TODO(bunnei): This needs to be HW tested | ||
| 419 | } | ||
| 420 | |||
| 421 | memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); | ||
| 422 | return size; | ||
| 423 | } | ||
| 424 | |||
| 425 | std::size_t HLERequestContext::GetReadBufferSize(std::size_t buffer_index) const { | ||
| 426 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && | ||
| 427 | BufferDescriptorA()[buffer_index].Size()}; | ||
| 428 | if (is_buffer_a) { | ||
| 429 | ASSERT_OR_EXECUTE_MSG( | ||
| 430 | BufferDescriptorA().size() > buffer_index, { return 0; }, | ||
| 431 | "BufferDescriptorA invalid buffer_index {}", buffer_index); | ||
| 432 | return BufferDescriptorA()[buffer_index].Size(); | ||
| 433 | } else { | ||
| 434 | ASSERT_OR_EXECUTE_MSG( | ||
| 435 | BufferDescriptorX().size() > buffer_index, { return 0; }, | ||
| 436 | "BufferDescriptorX invalid buffer_index {}", buffer_index); | ||
| 437 | return BufferDescriptorX()[buffer_index].Size(); | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) const { | ||
| 442 | const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && | ||
| 443 | BufferDescriptorB()[buffer_index].Size()}; | ||
| 444 | if (is_buffer_b) { | ||
| 445 | ASSERT_OR_EXECUTE_MSG( | ||
| 446 | BufferDescriptorB().size() > buffer_index, { return 0; }, | ||
| 447 | "BufferDescriptorB invalid buffer_index {}", buffer_index); | ||
| 448 | return BufferDescriptorB()[buffer_index].Size(); | ||
| 449 | } else { | ||
| 450 | ASSERT_OR_EXECUTE_MSG( | ||
| 451 | BufferDescriptorC().size() > buffer_index, { return 0; }, | ||
| 452 | "BufferDescriptorC invalid buffer_index {}", buffer_index); | ||
| 453 | return BufferDescriptorC()[buffer_index].Size(); | ||
| 454 | } | ||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | bool HLERequestContext::CanReadBuffer(std::size_t buffer_index) const { | ||
| 459 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && | ||
| 460 | BufferDescriptorA()[buffer_index].Size()}; | ||
| 461 | |||
| 462 | if (is_buffer_a) { | ||
| 463 | return BufferDescriptorA().size() > buffer_index; | ||
| 464 | } else { | ||
| 465 | return BufferDescriptorX().size() > buffer_index; | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 469 | bool HLERequestContext::CanWriteBuffer(std::size_t buffer_index) const { | ||
| 470 | const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && | ||
| 471 | BufferDescriptorB()[buffer_index].Size()}; | ||
| 472 | |||
| 473 | if (is_buffer_b) { | ||
| 474 | return BufferDescriptorB().size() > buffer_index; | ||
| 475 | } else { | ||
| 476 | return BufferDescriptorC().size() > buffer_index; | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | std::string HLERequestContext::Description() const { | ||
| 481 | if (!command_header) { | ||
| 482 | return "No command header available"; | ||
| 483 | } | ||
| 484 | std::ostringstream s; | ||
| 485 | s << "IPC::CommandHeader: Type:" << static_cast<u32>(command_header->type.Value()); | ||
| 486 | s << ", X(Pointer):" << command_header->num_buf_x_descriptors; | ||
| 487 | if (command_header->num_buf_x_descriptors) { | ||
| 488 | s << '['; | ||
| 489 | for (u64 i = 0; i < command_header->num_buf_x_descriptors; ++i) { | ||
| 490 | s << "0x" << std::hex << BufferDescriptorX()[i].Size(); | ||
| 491 | if (i < command_header->num_buf_x_descriptors - 1) | ||
| 492 | s << ", "; | ||
| 493 | } | ||
| 494 | s << ']'; | ||
| 495 | } | ||
| 496 | s << ", A(Send):" << command_header->num_buf_a_descriptors; | ||
| 497 | if (command_header->num_buf_a_descriptors) { | ||
| 498 | s << '['; | ||
| 499 | for (u64 i = 0; i < command_header->num_buf_a_descriptors; ++i) { | ||
| 500 | s << "0x" << std::hex << BufferDescriptorA()[i].Size(); | ||
| 501 | if (i < command_header->num_buf_a_descriptors - 1) | ||
| 502 | s << ", "; | ||
| 503 | } | ||
| 504 | s << ']'; | ||
| 505 | } | ||
| 506 | s << ", B(Receive):" << command_header->num_buf_b_descriptors; | ||
| 507 | if (command_header->num_buf_b_descriptors) { | ||
| 508 | s << '['; | ||
| 509 | for (u64 i = 0; i < command_header->num_buf_b_descriptors; ++i) { | ||
| 510 | s << "0x" << std::hex << BufferDescriptorB()[i].Size(); | ||
| 511 | if (i < command_header->num_buf_b_descriptors - 1) | ||
| 512 | s << ", "; | ||
| 513 | } | ||
| 514 | s << ']'; | ||
| 515 | } | ||
| 516 | s << ", C(ReceiveList):" << BufferDescriptorC().size(); | ||
| 517 | if (!BufferDescriptorC().empty()) { | ||
| 518 | s << '['; | ||
| 519 | for (u64 i = 0; i < BufferDescriptorC().size(); ++i) { | ||
| 520 | s << "0x" << std::hex << BufferDescriptorC()[i].Size(); | ||
| 521 | if (i < BufferDescriptorC().size() - 1) | ||
| 522 | s << ", "; | ||
| 523 | } | ||
| 524 | s << ']'; | ||
| 525 | } | ||
| 526 | s << ", data_size:" << command_header->data_size.Value(); | ||
| 527 | |||
| 528 | return s.str(); | ||
| 529 | } | ||
| 530 | |||
| 531 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h deleted file mode 100644 index b4364f984..000000000 --- a/src/core/hle/kernel/hle_ipc.h +++ /dev/null | |||
| @@ -1,421 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <functional> | ||
| 8 | #include <memory> | ||
| 9 | #include <optional> | ||
| 10 | #include <span> | ||
| 11 | #include <string> | ||
| 12 | #include <type_traits> | ||
| 13 | #include <vector> | ||
| 14 | |||
| 15 | #include "common/assert.h" | ||
| 16 | #include "common/common_types.h" | ||
| 17 | #include "common/concepts.h" | ||
| 18 | #include "common/swap.h" | ||
| 19 | #include "core/hle/ipc.h" | ||
| 20 | #include "core/hle/kernel/svc_common.h" | ||
| 21 | |||
| 22 | union Result; | ||
| 23 | |||
| 24 | namespace Core::Memory { | ||
| 25 | class Memory; | ||
| 26 | } | ||
| 27 | |||
| 28 | namespace IPC { | ||
| 29 | class ResponseBuilder; | ||
| 30 | } | ||
| 31 | |||
| 32 | namespace Service { | ||
| 33 | class ServiceFrameworkBase; | ||
| 34 | class ServerManager; | ||
| 35 | } // namespace Service | ||
| 36 | |||
| 37 | namespace Kernel { | ||
| 38 | |||
| 39 | class Domain; | ||
| 40 | class HLERequestContext; | ||
| 41 | class KAutoObject; | ||
| 42 | class KernelCore; | ||
| 43 | class KEvent; | ||
| 44 | class KHandleTable; | ||
| 45 | class KServerPort; | ||
| 46 | class KProcess; | ||
| 47 | class KServerSession; | ||
| 48 | class KThread; | ||
| 49 | class KReadableEvent; | ||
| 50 | class KSession; | ||
| 51 | class SessionRequestManager; | ||
| 52 | |||
| 53 | /** | ||
| 54 | * Interface implemented by HLE Session handlers. | ||
| 55 | * This can be provided to a ServerSession in order to hook into several relevant events | ||
| 56 | * (such as a new connection or a SyncRequest) so they can be implemented in the emulator. | ||
| 57 | */ | ||
| 58 | class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> { | ||
| 59 | public: | ||
| 60 | SessionRequestHandler(KernelCore& kernel_, const char* service_name_); | ||
| 61 | virtual ~SessionRequestHandler(); | ||
| 62 | |||
| 63 | /** | ||
| 64 | * Handles a sync request from the emulated application. | ||
| 65 | * @param server_session The ServerSession that was triggered for this sync request, | ||
| 66 | * it should be used to differentiate which client (As in ClientSession) we're answering to. | ||
| 67 | * TODO(Subv): Use a wrapper structure to hold all the information relevant to | ||
| 68 | * this request (ServerSession, Originator thread, Translated command buffer, etc). | ||
| 69 | * @returns Result the result code of the translate operation. | ||
| 70 | */ | ||
| 71 | virtual Result HandleSyncRequest(Kernel::KServerSession& session, | ||
| 72 | Kernel::HLERequestContext& context) = 0; | ||
| 73 | |||
| 74 | protected: | ||
| 75 | KernelCore& kernel; | ||
| 76 | }; | ||
| 77 | |||
| 78 | using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>; | ||
| 79 | using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Manages the underlying HLE requests for a session, and whether (or not) the session should be | ||
| 83 | * treated as a domain. This is managed separately from server sessions, as this state is shared | ||
| 84 | * when objects are cloned. | ||
| 85 | */ | ||
| 86 | class SessionRequestManager final { | ||
| 87 | public: | ||
| 88 | explicit SessionRequestManager(KernelCore& kernel, Service::ServerManager& server_manager); | ||
| 89 | ~SessionRequestManager(); | ||
| 90 | |||
| 91 | bool IsDomain() const { | ||
| 92 | return is_domain; | ||
| 93 | } | ||
| 94 | |||
| 95 | void ConvertToDomain() { | ||
| 96 | domain_handlers = {session_handler}; | ||
| 97 | is_domain = true; | ||
| 98 | } | ||
| 99 | |||
| 100 | void ConvertToDomainOnRequestEnd() { | ||
| 101 | convert_to_domain = true; | ||
| 102 | } | ||
| 103 | |||
| 104 | std::size_t DomainHandlerCount() const { | ||
| 105 | return domain_handlers.size(); | ||
| 106 | } | ||
| 107 | |||
| 108 | bool HasSessionHandler() const { | ||
| 109 | return session_handler != nullptr; | ||
| 110 | } | ||
| 111 | |||
| 112 | SessionRequestHandler& SessionHandler() { | ||
| 113 | return *session_handler; | ||
| 114 | } | ||
| 115 | |||
| 116 | const SessionRequestHandler& SessionHandler() const { | ||
| 117 | return *session_handler; | ||
| 118 | } | ||
| 119 | |||
| 120 | void CloseDomainHandler(std::size_t index) { | ||
| 121 | if (index < DomainHandlerCount()) { | ||
| 122 | domain_handlers[index] = nullptr; | ||
| 123 | } else { | ||
| 124 | ASSERT_MSG(false, "Unexpected handler index {}", index); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | SessionRequestHandlerWeakPtr DomainHandler(std::size_t index) const { | ||
| 129 | ASSERT_MSG(index < DomainHandlerCount(), "Unexpected handler index {}", index); | ||
| 130 | return domain_handlers.at(index); | ||
| 131 | } | ||
| 132 | |||
| 133 | void AppendDomainHandler(SessionRequestHandlerPtr&& handler) { | ||
| 134 | domain_handlers.emplace_back(std::move(handler)); | ||
| 135 | } | ||
| 136 | |||
| 137 | void SetSessionHandler(SessionRequestHandlerPtr&& handler) { | ||
| 138 | session_handler = std::move(handler); | ||
| 139 | } | ||
| 140 | |||
| 141 | bool HasSessionRequestHandler(const HLERequestContext& context) const; | ||
| 142 | |||
| 143 | Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context); | ||
| 144 | Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context); | ||
| 145 | |||
| 146 | Service::ServerManager& GetServerManager() { | ||
| 147 | return server_manager; | ||
| 148 | } | ||
| 149 | |||
| 150 | // TODO: remove this when sm: is implemented with the proper IUserInterface | ||
| 151 | // abstraction, creating a new C++ handler object for each session: | ||
| 152 | |||
| 153 | bool GetIsInitializedForSm() const { | ||
| 154 | return is_initialized_for_sm; | ||
| 155 | } | ||
| 156 | |||
| 157 | void SetIsInitializedForSm() { | ||
| 158 | is_initialized_for_sm = true; | ||
| 159 | } | ||
| 160 | |||
| 161 | private: | ||
| 162 | bool convert_to_domain{}; | ||
| 163 | bool is_domain{}; | ||
| 164 | bool is_initialized_for_sm{}; | ||
| 165 | SessionRequestHandlerPtr session_handler; | ||
| 166 | std::vector<SessionRequestHandlerPtr> domain_handlers; | ||
| 167 | |||
| 168 | private: | ||
| 169 | KernelCore& kernel; | ||
| 170 | Service::ServerManager& server_manager; | ||
| 171 | }; | ||
| 172 | |||
| 173 | /** | ||
| 174 | * Class containing information about an in-flight IPC request being handled by an HLE service | ||
| 175 | * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and | ||
| 176 | * when possible use the APIs in this class to service the request. | ||
| 177 | * | ||
| 178 | * HLE handle protocol | ||
| 179 | * =================== | ||
| 180 | * | ||
| 181 | * To avoid needing HLE services to keep a separate handle table, or having to directly modify the | ||
| 182 | * requester's table, a tweaked protocol is used to receive and send handles in requests. The kernel | ||
| 183 | * will decode the incoming handles into object pointers and insert a id in the buffer where the | ||
| 184 | * handle would normally be. The service then calls GetIncomingHandle() with that id to get the | ||
| 185 | * pointer to the object. Similarly, instead of inserting a handle into the command buffer, the | ||
| 186 | * service calls AddOutgoingHandle() and stores the returned id where the handle would normally go. | ||
| 187 | * | ||
| 188 | * The end result is similar to just giving services their own real handle tables, but since these | ||
| 189 | * ids are local to a specific context, it avoids requiring services to manage handles for objects | ||
| 190 | * across multiple calls and ensuring that unneeded handles are cleaned up. | ||
| 191 | */ | ||
| 192 | class HLERequestContext { | ||
| 193 | public: | ||
| 194 | explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, | ||
| 195 | KServerSession* session, KThread* thread); | ||
| 196 | ~HLERequestContext(); | ||
| 197 | |||
| 198 | /// Returns a pointer to the IPC command buffer for this request. | ||
| 199 | [[nodiscard]] u32* CommandBuffer() { | ||
| 200 | return cmd_buf.data(); | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * Returns the session through which this request was made. This can be used as a map key to | ||
| 205 | * access per-client data on services. | ||
| 206 | */ | ||
| 207 | [[nodiscard]] Kernel::KServerSession* Session() { | ||
| 208 | return server_session; | ||
| 209 | } | ||
| 210 | |||
| 211 | /// Populates this context with data from the requesting process/thread. | ||
| 212 | Result PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf); | ||
| 213 | |||
| 214 | /// Writes data from this context back to the requesting process/thread. | ||
| 215 | Result WriteToOutgoingCommandBuffer(KThread& requesting_thread); | ||
| 216 | |||
| 217 | [[nodiscard]] u32_le GetHipcCommand() const { | ||
| 218 | return command; | ||
| 219 | } | ||
| 220 | |||
| 221 | [[nodiscard]] u32_le GetTipcCommand() const { | ||
| 222 | return static_cast<u32_le>(command_header->type.Value()) - | ||
| 223 | static_cast<u32_le>(IPC::CommandType::TIPC_CommandRegion); | ||
| 224 | } | ||
| 225 | |||
| 226 | [[nodiscard]] u32_le GetCommand() const { | ||
| 227 | return command_header->IsTipc() ? GetTipcCommand() : GetHipcCommand(); | ||
| 228 | } | ||
| 229 | |||
| 230 | [[nodiscard]] bool IsTipc() const { | ||
| 231 | return command_header->IsTipc(); | ||
| 232 | } | ||
| 233 | |||
| 234 | [[nodiscard]] IPC::CommandType GetCommandType() const { | ||
| 235 | return command_header->type; | ||
| 236 | } | ||
| 237 | |||
| 238 | [[nodiscard]] u64 GetPID() const { | ||
| 239 | return pid; | ||
| 240 | } | ||
| 241 | |||
| 242 | [[nodiscard]] u32 GetDataPayloadOffset() const { | ||
| 243 | return data_payload_offset; | ||
| 244 | } | ||
| 245 | |||
| 246 | [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { | ||
| 247 | return buffer_x_desciptors; | ||
| 248 | } | ||
| 249 | |||
| 250 | [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { | ||
| 251 | return buffer_a_desciptors; | ||
| 252 | } | ||
| 253 | |||
| 254 | [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { | ||
| 255 | return buffer_b_desciptors; | ||
| 256 | } | ||
| 257 | |||
| 258 | [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { | ||
| 259 | return buffer_c_desciptors; | ||
| 260 | } | ||
| 261 | |||
| 262 | [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { | ||
| 263 | return domain_message_header.value(); | ||
| 264 | } | ||
| 265 | |||
| 266 | [[nodiscard]] bool HasDomainMessageHeader() const { | ||
| 267 | return domain_message_header.has_value(); | ||
| 268 | } | ||
| 269 | |||
| 270 | /// Helper function to get a span of a buffer using the appropriate buffer descriptor | ||
| 271 | [[nodiscard]] std::span<const u8> ReadBuffer(std::size_t buffer_index = 0) const; | ||
| 272 | |||
| 273 | /// Helper function to read a copy of a buffer using the appropriate buffer descriptor | ||
| 274 | [[nodiscard]] std::vector<u8> ReadBufferCopy(std::size_t buffer_index = 0) const; | ||
| 275 | |||
| 276 | /// Helper function to write a buffer using the appropriate buffer descriptor | ||
| 277 | std::size_t WriteBuffer(const void* buffer, std::size_t size, | ||
| 278 | std::size_t buffer_index = 0) const; | ||
| 279 | |||
| 280 | /// Helper function to write buffer B | ||
| 281 | std::size_t WriteBufferB(const void* buffer, std::size_t size, | ||
| 282 | std::size_t buffer_index = 0) const; | ||
| 283 | |||
| 284 | /// Helper function to write buffer C | ||
| 285 | std::size_t WriteBufferC(const void* buffer, std::size_t size, | ||
| 286 | std::size_t buffer_index = 0) const; | ||
| 287 | |||
| 288 | /* Helper function to write a buffer using the appropriate buffer descriptor | ||
| 289 | * | ||
| 290 | * @tparam T an arbitrary container that satisfies the | ||
| 291 | * ContiguousContainer concept in the C++ standard library or a trivially copyable type. | ||
| 292 | * | ||
| 293 | * @param data The container/data to write into a buffer. | ||
| 294 | * @param buffer_index The buffer in particular to write to. | ||
| 295 | */ | ||
| 296 | template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>> | ||
| 297 | std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const { | ||
| 298 | if constexpr (Common::IsContiguousContainer<T>) { | ||
| 299 | using ContiguousType = typename T::value_type; | ||
| 300 | static_assert(std::is_trivially_copyable_v<ContiguousType>, | ||
| 301 | "Container to WriteBuffer must contain trivially copyable objects"); | ||
| 302 | return WriteBuffer(std::data(data), std::size(data) * sizeof(ContiguousType), | ||
| 303 | buffer_index); | ||
| 304 | } else { | ||
| 305 | static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); | ||
| 306 | return WriteBuffer(&data, sizeof(T), buffer_index); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | /// Helper function to get the size of the input buffer | ||
| 311 | [[nodiscard]] std::size_t GetReadBufferSize(std::size_t buffer_index = 0) const; | ||
| 312 | |||
| 313 | /// Helper function to get the size of the output buffer | ||
| 314 | [[nodiscard]] std::size_t GetWriteBufferSize(std::size_t buffer_index = 0) const; | ||
| 315 | |||
| 316 | /// Helper function to derive the number of elements able to be contained in the read buffer | ||
| 317 | template <typename T> | ||
| 318 | [[nodiscard]] std::size_t GetReadBufferNumElements(std::size_t buffer_index = 0) const { | ||
| 319 | return GetReadBufferSize(buffer_index) / sizeof(T); | ||
| 320 | } | ||
| 321 | |||
| 322 | /// Helper function to derive the number of elements able to be contained in the write buffer | ||
| 323 | template <typename T> | ||
| 324 | [[nodiscard]] std::size_t GetWriteBufferNumElements(std::size_t buffer_index = 0) const { | ||
| 325 | return GetWriteBufferSize(buffer_index) / sizeof(T); | ||
| 326 | } | ||
| 327 | |||
| 328 | /// Helper function to test whether the input buffer at buffer_index can be read | ||
| 329 | [[nodiscard]] bool CanReadBuffer(std::size_t buffer_index = 0) const; | ||
| 330 | |||
| 331 | /// Helper function to test whether the output buffer at buffer_index can be written | ||
| 332 | [[nodiscard]] bool CanWriteBuffer(std::size_t buffer_index = 0) const; | ||
| 333 | |||
| 334 | [[nodiscard]] Handle GetCopyHandle(std::size_t index) const { | ||
| 335 | return incoming_copy_handles.at(index); | ||
| 336 | } | ||
| 337 | |||
| 338 | [[nodiscard]] Handle GetMoveHandle(std::size_t index) const { | ||
| 339 | return incoming_move_handles.at(index); | ||
| 340 | } | ||
| 341 | |||
| 342 | void AddMoveObject(KAutoObject* object) { | ||
| 343 | outgoing_move_objects.emplace_back(object); | ||
| 344 | } | ||
| 345 | |||
| 346 | void AddCopyObject(KAutoObject* object) { | ||
| 347 | outgoing_copy_objects.emplace_back(object); | ||
| 348 | } | ||
| 349 | |||
| 350 | void AddDomainObject(SessionRequestHandlerPtr object) { | ||
| 351 | outgoing_domain_objects.emplace_back(std::move(object)); | ||
| 352 | } | ||
| 353 | |||
| 354 | template <typename T> | ||
| 355 | std::shared_ptr<T> GetDomainHandler(std::size_t index) const { | ||
| 356 | return std::static_pointer_cast<T>(GetManager()->DomainHandler(index).lock()); | ||
| 357 | } | ||
| 358 | |||
| 359 | void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) { | ||
| 360 | manager = manager_; | ||
| 361 | } | ||
| 362 | |||
| 363 | [[nodiscard]] std::string Description() const; | ||
| 364 | |||
| 365 | [[nodiscard]] KThread& GetThread() { | ||
| 366 | return *thread; | ||
| 367 | } | ||
| 368 | |||
| 369 | [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { | ||
| 370 | return manager.lock(); | ||
| 371 | } | ||
| 372 | |||
| 373 | bool GetIsDeferred() const { | ||
| 374 | return is_deferred; | ||
| 375 | } | ||
| 376 | |||
| 377 | void SetIsDeferred(bool is_deferred_ = true) { | ||
| 378 | is_deferred = is_deferred_; | ||
| 379 | } | ||
| 380 | |||
| 381 | private: | ||
| 382 | friend class IPC::ResponseBuilder; | ||
| 383 | |||
| 384 | void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); | ||
| 385 | |||
| 386 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; | ||
| 387 | Kernel::KServerSession* server_session{}; | ||
| 388 | KThread* thread; | ||
| 389 | |||
| 390 | std::vector<Handle> incoming_move_handles; | ||
| 391 | std::vector<Handle> incoming_copy_handles; | ||
| 392 | |||
| 393 | std::vector<KAutoObject*> outgoing_move_objects; | ||
| 394 | std::vector<KAutoObject*> outgoing_copy_objects; | ||
| 395 | std::vector<SessionRequestHandlerPtr> outgoing_domain_objects; | ||
| 396 | |||
| 397 | std::optional<IPC::CommandHeader> command_header; | ||
| 398 | std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; | ||
| 399 | std::optional<IPC::DataPayloadHeader> data_payload_header; | ||
| 400 | std::optional<IPC::DomainMessageHeader> domain_message_header; | ||
| 401 | std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; | ||
| 402 | std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; | ||
| 403 | std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; | ||
| 404 | std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; | ||
| 405 | std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; | ||
| 406 | |||
| 407 | u32_le command{}; | ||
| 408 | u64 pid{}; | ||
| 409 | u32 write_size{}; | ||
| 410 | u32 data_payload_offset{}; | ||
| 411 | u32 handles_offset{}; | ||
| 412 | u32 domain_offset{}; | ||
| 413 | |||
| 414 | std::weak_ptr<SessionRequestManager> manager{}; | ||
| 415 | bool is_deferred{false}; | ||
| 416 | |||
| 417 | KernelCore& kernel; | ||
| 418 | Core::Memory::Memory& memory; | ||
| 419 | }; | ||
| 420 | |||
| 421 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index c72a91a76..700ae71e3 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/scope_exit.h" | 4 | #include "common/scope_exit.h" |
| 5 | #include "core/hle/kernel/hle_ipc.h" | ||
| 6 | #include "core/hle/kernel/k_client_port.h" | 5 | #include "core/hle/kernel/k_client_port.h" |
| 7 | #include "core/hle/kernel/k_port.h" | 6 | #include "core/hle/kernel/k_port.h" |
| 8 | #include "core/hle/kernel/k_scheduler.h" | 7 | #include "core/hle/kernel/k_scheduler.h" |
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index 81046fb86..a757cf9cd 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h | |||
| @@ -15,7 +15,6 @@ namespace Kernel { | |||
| 15 | class KClientSession; | 15 | class KClientSession; |
| 16 | class KernelCore; | 16 | class KernelCore; |
| 17 | class KPort; | 17 | class KPort; |
| 18 | class SessionRequestManager; | ||
| 19 | 18 | ||
| 20 | class KClientPort final : public KSynchronizationObject { | 19 | class KClientPort final : public KSynchronizationObject { |
| 21 | KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); | 20 | KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject); |
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp index b4197a8d5..da0c9ac8c 100644 --- a/src/core/hle/kernel/k_client_session.cpp +++ b/src/core/hle/kernel/k_client_session.cpp | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/scope_exit.h" | 4 | #include "common/scope_exit.h" |
| 5 | #include "core/hle/kernel/hle_ipc.h" | ||
| 6 | #include "core/hle/kernel/k_client_session.h" | 5 | #include "core/hle/kernel/k_client_session.h" |
| 7 | #include "core/hle/kernel/k_server_session.h" | 6 | #include "core/hle/kernel/k_server_session.h" |
| 8 | #include "core/hle/kernel/k_session.h" | 7 | #include "core/hle/kernel/k_session.h" |
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index 77d00ae2c..0a45ffd57 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/kernel/hle_ipc.h" | ||
| 5 | #include "core/hle/kernel/k_port.h" | 4 | #include "core/hle/kernel/k_port.h" |
| 6 | #include "core/hle/kernel/k_scheduler.h" | 5 | #include "core/hle/kernel/k_scheduler.h" |
| 7 | #include "core/hle/kernel/svc_results.h" | 6 | #include "core/hle/kernel/svc_results.h" |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index aa1941f01..01591af5b 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -10,8 +10,6 @@ | |||
| 10 | #include "common/scope_exit.h" | 10 | #include "common/scope_exit.h" |
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/core_timing.h" | 12 | #include "core/core_timing.h" |
| 13 | #include "core/hle/ipc_helpers.h" | ||
| 14 | #include "core/hle/kernel/hle_ipc.h" | ||
| 15 | #include "core/hle/kernel/k_client_port.h" | 13 | #include "core/hle/kernel/k_client_port.h" |
| 16 | #include "core/hle/kernel/k_handle_table.h" | 14 | #include "core/hle/kernel/k_handle_table.h" |
| 17 | #include "core/hle/kernel/k_process.h" | 15 | #include "core/hle/kernel/k_process.h" |
| @@ -22,6 +20,8 @@ | |||
| 22 | #include "core/hle/kernel/k_thread.h" | 20 | #include "core/hle/kernel/k_thread.h" |
| 23 | #include "core/hle/kernel/k_thread_queue.h" | 21 | #include "core/hle/kernel/k_thread_queue.h" |
| 24 | #include "core/hle/kernel/kernel.h" | 22 | #include "core/hle/kernel/kernel.h" |
| 23 | #include "core/hle/service/hle_ipc.h" | ||
| 24 | #include "core/hle/service/ipc_helpers.h" | ||
| 25 | #include "core/memory.h" | 25 | #include "core/memory.h" |
| 26 | 26 | ||
| 27 | namespace Kernel { | 27 | namespace Kernel { |
| @@ -281,8 +281,8 @@ Result KServerSession::SendReply(bool is_hle) { | |||
| 281 | return result; | 281 | return result; |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context, | 284 | Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context, |
| 285 | std::weak_ptr<SessionRequestManager> manager) { | 285 | std::weak_ptr<Service::SessionRequestManager> manager) { |
| 286 | // Lock the session. | 286 | // Lock the session. |
| 287 | KScopedLightLock lk{m_lock}; | 287 | KScopedLightLock lk{m_lock}; |
| 288 | 288 | ||
| @@ -329,7 +329,8 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_co | |||
| 329 | if (out_context != nullptr) { | 329 | if (out_context != nullptr) { |
| 330 | // HLE request. | 330 | // HLE request. |
| 331 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))}; | 331 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))}; |
| 332 | *out_context = std::make_shared<HLERequestContext>(kernel, memory, this, client_thread); | 332 | *out_context = |
| 333 | std::make_shared<Service::HLERequestContext>(kernel, memory, this, client_thread); | ||
| 333 | (*out_context)->SetSessionRequestManager(manager); | 334 | (*out_context)->SetSessionRequestManager(manager); |
| 334 | (*out_context) | 335 | (*out_context) |
| 335 | ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), | 336 | ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), |
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 6e189af8b..33f380352 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h | |||
| @@ -10,18 +10,20 @@ | |||
| 10 | 10 | ||
| 11 | #include <boost/intrusive/list.hpp> | 11 | #include <boost/intrusive/list.hpp> |
| 12 | 12 | ||
| 13 | #include "core/hle/kernel/hle_ipc.h" | ||
| 14 | #include "core/hle/kernel/k_light_lock.h" | 13 | #include "core/hle/kernel/k_light_lock.h" |
| 15 | #include "core/hle/kernel/k_session_request.h" | 14 | #include "core/hle/kernel/k_session_request.h" |
| 16 | #include "core/hle/kernel/k_synchronization_object.h" | 15 | #include "core/hle/kernel/k_synchronization_object.h" |
| 17 | #include "core/hle/result.h" | 16 | #include "core/hle/result.h" |
| 18 | 17 | ||
| 18 | namespace Service { | ||
| 19 | class HLERequestContext; | ||
| 20 | class SessionRequestManager; | ||
| 21 | } // namespace Service | ||
| 22 | |||
| 19 | namespace Kernel { | 23 | namespace Kernel { |
| 20 | 24 | ||
| 21 | class HLERequestContext; | ||
| 22 | class KernelCore; | 25 | class KernelCore; |
| 23 | class KSession; | 26 | class KSession; |
| 24 | class SessionRequestManager; | ||
| 25 | class KThread; | 27 | class KThread; |
| 26 | 28 | ||
| 27 | class KServerSession final : public KSynchronizationObject, | 29 | class KServerSession final : public KSynchronizationObject, |
| @@ -52,8 +54,8 @@ public: | |||
| 52 | /// TODO: flesh these out to match the real kernel | 54 | /// TODO: flesh these out to match the real kernel |
| 53 | Result OnRequest(KSessionRequest* request); | 55 | Result OnRequest(KSessionRequest* request); |
| 54 | Result SendReply(bool is_hle = false); | 56 | Result SendReply(bool is_hle = false); |
| 55 | Result ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context = nullptr, | 57 | Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr, |
| 56 | std::weak_ptr<SessionRequestManager> manager = {}); | 58 | std::weak_ptr<Service::SessionRequestManager> manager = {}); |
| 57 | 59 | ||
| 58 | Result SendReplyHLE() { | 60 | Result SendReplyHLE() { |
| 59 | return SendReply(true); | 61 | return SendReply(true); |