From a5c50a5b28b3810069c629baf87d0445aaa2acce Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 17 Jan 2018 16:22:05 -0300 Subject: [PATCH] Add support for reading Buffer C Descriptors on hle_ipc --- src/core/hle/ipc_helpers.h | 4 ++++ src/core/hle/kernel/hle_ipc.cpp | 34 ++++++++++++++++++++++++++------- src/core/hle/kernel/hle_ipc.h | 2 ++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 25530a3c82..4c9b0de288 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -54,6 +54,10 @@ public: unsigned GetCurrentOffset() const { return static_cast(index); } + + void SetCurrentOffset(unsigned offset) { + index = static_cast(offset); + } }; class RequestBuilder : public RequestHelperBase { diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index ac62a0d5af..73bb6a8be6 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -81,13 +81,8 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) { buffer_w_desciptors.push_back(rp.PopRaw()); } - if (command_header->buf_c_descriptor_flags != - IPC::CommandHeader::BufferDescriptorCFlag::Disabled) { - if (command_header->buf_c_descriptor_flags != - IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { - UNIMPLEMENTED(); - } - } + + buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; // Padding to align to 16 bytes rp.AlignWithPadding(); @@ -117,6 +112,31 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); } + rp.SetCurrentOffset(buffer_c_offset); + + // For Inline buffers, the response data is written directly to buffer_c_offset + // and in this case we don't have any BufferDescriptorC on the request. + if (command_header->buf_c_descriptor_flags > + IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { + if (command_header->buf_c_descriptor_flags == + IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { + buffer_c_desciptors.push_back(rp.PopRaw()); + } else { + unsigned num_buf_c_descriptors = + static_cast(command_header->buf_c_descriptor_flags.Value()) - 2; + + // This is used to detect possible underflows, in case something is broken + // with the two ifs above and the flags value is == 0 || == 1. + ASSERT(num_buf_c_descriptors < 14); + + for (unsigned i = 0; i < num_buf_c_descriptors; ++i) { + buffer_c_desciptors.push_back(rp.PopRaw()); + } + } + } + + rp.SetCurrentOffset(data_payload_offset); + command = rp.Pop(); rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 6dceb766db..f4db2e0726 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -200,8 +200,10 @@ private: std::vector buffer_a_desciptors; std::vector buffer_b_desciptors; std::vector buffer_w_desciptors; + std::vector buffer_c_desciptors; unsigned data_payload_offset{}; + unsigned buffer_c_offset{}; u32_le command{}; };