From 226786f0b05405b4c0287786f106ae2e08feefec Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Sat, 6 Jan 2018 21:14:14 -0500
Subject: [PATCH] IPC: Use the correct size when pushing raw data to the
 command buffer and fixed pushing domain objects.

Domain object ids are always stored immediately after the raw data.
---
 src/core/hle/ipc.h              | 10 ++++++++--
 src/core/hle/ipc_helpers.h      | 19 ++++++++++++++-----
 src/core/hle/kernel/hle_ipc.cpp |  2 +-
 src/core/hle/kernel/hle_ipc.h   |  8 ++++++--
 4 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index 4dc8937c32..4c21f5024a 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -143,7 +143,7 @@ struct DataPayloadHeader {
 };
 static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadRequest size is incorrect");
 
-struct DomainMessageHeader {
+struct DomainRequestMessageHeader {
     union {
         BitField<0, 8, u32_le> command;
         BitField<16, 16, u32_le> size;
@@ -151,7 +151,13 @@ struct DomainMessageHeader {
     u32_le object_id;
     INSERT_PADDING_WORDS(2);
 };
-static_assert(sizeof(DomainMessageHeader) == 16, "DomainMessageHeader size is incorrect");
+static_assert(sizeof(DomainRequestMessageHeader) == 16, "DomainRequestMessageHeader size is incorrect");
+
+struct DomainResponseMessageHeader {
+    u32_le num_objects;
+    INSERT_PADDING_WORDS(3);
+};
+static_assert(sizeof(DomainResponseMessageHeader) == 16, "DomainResponseMessageHeader size is incorrect");
 
 enum DescriptorType : u32 {
     // Buffer related desciptors types (mask : 0x0F)
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 28a2b8545d..705943e6b3 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -58,14 +58,20 @@ public:
     RequestBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {}
 
     RequestBuilder(Kernel::HLERequestContext& context, unsigned normal_params_size,
-                   u32 num_handles_to_copy = 0, u32 num_handles_to_move = 0)
+                   u32 num_handles_to_copy = 0, u32 num_handles_to_move = 0, u32 num_domain_objects = 0)
         : RequestHelperBase(context) {
         memset(cmdbuf, 0, 64);
 
         context.ClearIncomingObjects();
 
         IPC::CommandHeader header{};
-        header.data_size.Assign(normal_params_size * sizeof(u32));
+
+        // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory padding.
+        u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
+        if (context.IsDomain())
+            raw_data_size += sizeof(DomainResponseMessageHeader) / 4 + num_domain_objects;
+
+        header.data_size.Assign(raw_data_size);
         if (num_handles_to_copy || num_handles_to_move) {
             header.enable_handle_descriptor.Assign(1);
         }
@@ -82,7 +88,9 @@ public:
         AlignWithPadding();
 
         if (context.IsDomain()) {
-            PushRaw(IPC::DomainMessageHeader{});
+            IPC::DomainResponseMessageHeader domain_header{};
+            domain_header.num_objects = num_domain_objects;
+            PushRaw(domain_header);
         }
 
         IPC::DataPayloadHeader data_payload_header{};
@@ -93,9 +101,10 @@ public:
     template <class T>
     void PushIpcInterface() {
         auto& request_handlers = context->Domain()->request_handlers;
-        request_handlers.push_back(std::move(std::make_shared<T>()->shared_from_this()));
+        request_handlers.emplace_back(std::make_shared<T>());
         Push(RESULT_SUCCESS);
-        AlignWithPadding();
+        Push<u32>(0); // The error code is the lower word of an u64, so we fill the rest with 0.
+        // Now push the id of the newly-added object.
         Push<u32>(static_cast<u32>(request_handlers.size()));
     }
 
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 85dd801590..e784d59cc6 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -95,7 +95,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
         // If this is an incoming message, only CommandType "Request" has a domain header
         // All outgoing domain messages have the domain header
         domain_message_header =
-            std::make_unique<IPC::DomainMessageHeader>(rp.PopRaw<IPC::DomainMessageHeader>());
+            std::make_unique<IPC::DomainRequestMessageHeader>(rp.PopRaw<IPC::DomainRequestMessageHeader>());
     }
 
     data_payload_header =
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 7de13b36be..b5649931d7 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -154,7 +154,11 @@ public:
         return buffer_x_desciptors;
     }
 
-    const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const {
+    const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const {
+        return buffer_a_desciptors;
+    }
+
+    const std::unique_ptr<IPC::DomainRequestMessageHeader>& GetDomainMessageHeader() const {
         return domain_message_header;
     }
 
@@ -172,7 +176,7 @@ private:
     std::unique_ptr<IPC::CommandHeader> command_header;
     std::unique_ptr<IPC::HandleDescriptorHeader> handle_descriptor_header;
     std::unique_ptr<IPC::DataPayloadHeader> data_payload_header;
-    std::unique_ptr<IPC::DomainMessageHeader> domain_message_header;
+    std::unique_ptr<IPC::DomainRequestMessageHeader> domain_message_header;
     std::vector<IPC::BufferDescriptorX> buffer_x_desciptors;
     std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors;
     std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors;