diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index e0367e774c..635db0e29e 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -187,7 +188,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { buffer_w_descriptors.push_back(rp.PopRaw()); } - const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; + buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; if (!command_header->IsTipc()) { // Padding to align to 16 bytes @@ -294,7 +295,15 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer() { } // Write the domain objects to the command buffer, these go after the raw untranslated data. - // TODO(Subv): This completely ignores C buffers. + + if (buffer_c_offset != 0 && !buffer_c_descriptors.empty()) { + constexpr u32 WORDS_PER_DESCRIPTOR = sizeof(IPC::BufferDescriptorC) / sizeof(u32); + u32 descriptor_offset = buffer_c_offset; + for (const auto& descriptor : buffer_c_descriptors) { + std::memcpy(&cmd_buf[descriptor_offset], &descriptor, sizeof(descriptor)); + descriptor_offset += WORDS_PER_DESCRIPTOR; + } + } if (GetManager()->IsDomain()) { current_offset = domain_offset - static_cast(outgoing_domain_objects.size()); @@ -393,10 +402,14 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && BufferDescriptorB()[buffer_index].Size()}; const std::size_t buffer_size{GetWriteBufferSize(buffer_index)}; + if (buffer_size == 0) { + LOG_WARNING(Core, "WriteBuffer target index {} has zero capacity", buffer_index); + return 0; + } if (size > buffer_size) { - LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, - buffer_size); - size = buffer_size; // TODO(bunnei): This needs to be HW tested + LOG_WARNING(Core, "size ({:016X}) is greater than buffer_size ({:016X}); clamping", + size, buffer_size); + size = buffer_size; } if (is_buffer_b) { @@ -418,15 +431,25 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, std::size_t HLERequestContext::WriteBufferB(const void* buffer, std::size_t size, std::size_t buffer_index) const { - if (buffer_index >= BufferDescriptorB().size() || size == 0) { + if (buffer_index >= BufferDescriptorB().size()) { + LOG_WARNING(Core, "WriteBufferB invalid buffer index {}", buffer_index); + return 0; + } + + if (size == 0) { + LOG_WARNING(Core, "skip empty buffer write (B)"); return 0; } const auto buffer_size{BufferDescriptorB()[buffer_index].Size()}; + if (buffer_size == 0) { + LOG_WARNING(Core, "WriteBufferB target index {} has zero capacity", buffer_index); + return 0; + } if (size > buffer_size) { - LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, - buffer_size); - size = buffer_size; // TODO(bunnei): This needs to be HW tested + LOG_WARNING(Core, "size ({:016X}) is greater than buffer_size ({:016X}); clamping", + size, buffer_size); + size = buffer_size; } memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); @@ -435,15 +458,25 @@ std::size_t HLERequestContext::WriteBufferB(const void* buffer, std::size_t size std::size_t HLERequestContext::WriteBufferC(const void* buffer, std::size_t size, std::size_t buffer_index) const { - if (buffer_index >= BufferDescriptorC().size() || size == 0) { + if (buffer_index >= BufferDescriptorC().size()) { + LOG_WARNING(Core, "WriteBufferC invalid buffer index {}", buffer_index); + return 0; + } + + if (size == 0) { + LOG_WARNING(Core, "skip empty buffer write (C)"); return 0; } const auto buffer_size{BufferDescriptorC()[buffer_index].Size()}; + if (buffer_size == 0) { + LOG_WARNING(Core, "WriteBufferC target index {} has zero capacity", buffer_index); + return 0; + } if (size > buffer_size) { - LOG_CRITICAL(Core, "size ({:016X}) is greater than buffer_size ({:016X})", size, - buffer_size); - size = buffer_size; // TODO(bunnei): This needs to be HW tested + LOG_WARNING(Core, "size ({:016X}) is greater than buffer_size ({:016X}); clamping", + size, buffer_size); + size = buffer_size; } memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); @@ -473,12 +506,20 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons ASSERT_OR_EXECUTE_MSG( BufferDescriptorB().size() > buffer_index, { return 0; }, "BufferDescriptorB invalid buffer_index {}", buffer_index); - return BufferDescriptorB()[buffer_index].Size(); + const auto size = BufferDescriptorB()[buffer_index].Size(); + if (size == 0) { + LOG_WARNING(Core, "BufferDescriptorB index {} has zero size", buffer_index); + } + return size; } else { ASSERT_OR_EXECUTE_MSG( BufferDescriptorC().size() > buffer_index, { return 0; }, "BufferDescriptorC invalid buffer_index {}", buffer_index); - return BufferDescriptorC()[buffer_index].Size(); + const auto size = BufferDescriptorC()[buffer_index].Size(); + if (size == 0) { + LOG_WARNING(Core, "BufferDescriptorC index {} has zero size", buffer_index); + } + return size; } return 0; } diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index c2e0e5e8c4..82e893a24e 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h @@ -422,6 +422,7 @@ private: u32 data_payload_offset{}; u32 handles_offset{}; u32 domain_offset{}; + u32 buffer_c_offset{}; std::weak_ptr manager{}; bool is_deferred{false};