summaryrefslogtreecommitdiff
path: root/src/core/hle/ipc_helpers.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/ipc_helpers.h')
-rw-r--r--src/core/hle/ipc_helpers.h115
1 files changed, 73 insertions, 42 deletions
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index ab479b49b..6066d8a18 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -11,7 +11,6 @@
11#include "core/hle/ipc.h" 11#include "core/hle/ipc.h"
12#include "core/hle/kernel/client_port.h" 12#include "core/hle/kernel/client_port.h"
13#include "core/hle/kernel/client_session.h" 13#include "core/hle/kernel/client_session.h"
14#include "core/hle/kernel/domain.h"
15#include "core/hle/kernel/handle_table.h" 14#include "core/hle/kernel/handle_table.h"
16#include "core/hle/kernel/hle_ipc.h" 15#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/kernel.h"
@@ -31,11 +30,6 @@ public:
31 RequestHelperBase(Kernel::HLERequestContext& context) 30 RequestHelperBase(Kernel::HLERequestContext& context)
32 : context(&context), cmdbuf(context.CommandBuffer()) {} 31 : context(&context), cmdbuf(context.CommandBuffer()) {}
33 32
34 void ValidateHeader() {
35 // DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)",
36 // header.raw);
37 }
38
39 void Skip(unsigned size_in_words, bool set_to_null) { 33 void Skip(unsigned size_in_words, bool set_to_null) {
40 if (set_to_null) 34 if (set_to_null)
41 memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); 35 memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
@@ -60,14 +54,30 @@ public:
60 } 54 }
61}; 55};
62 56
63class RequestBuilder : public RequestHelperBase { 57class ResponseBuilder : public RequestHelperBase {
64public: 58public:
65 RequestBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {} 59 ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {}
60
61 u32 normal_params_size{};
62 u32 num_handles_to_copy{};
63 u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
64 std::ptrdiff_t datapayload_index{};
65
66 /// Flags used for customizing the behavior of ResponseBuilder
67 enum class Flags : u32 {
68 None = 0,
69 /// Uses move handles to move objects in the response, even when in a domain. This is
70 /// required when PushMoveObjects is used.
71 AlwaysMoveHandles = 1,
72 };
73
74 ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size,
75 u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0,
76 Flags flags = Flags::None)
77
78 : RequestHelperBase(context), normal_params_size(normal_params_size),
79 num_handles_to_copy(num_handles_to_copy), num_objects_to_move(num_objects_to_move) {
66 80
67 RequestBuilder(Kernel::HLERequestContext& context, unsigned normal_params_size,
68 u32 num_handles_to_copy = 0, u32 num_handles_to_move = 0,
69 u32 num_domain_objects = 0)
70 : RequestHelperBase(context) {
71 memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); 81 memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
72 82
73 context.ClearIncomingObjects(); 83 context.ClearIncomingObjects();
@@ -77,12 +87,19 @@ public:
77 // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory 87 // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
78 // padding. 88 // padding.
79 u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; 89 u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
80 if (context.IsDomain()) { 90
81 raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; 91 u32 num_handles_to_move{};
92 u32 num_domain_objects{};
93 const bool always_move_handles{
94 (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
95 if (!context.Session()->IsDomain() || always_move_handles) {
96 num_handles_to_move = num_objects_to_move;
82 } else { 97 } else {
83 // If we're not in a domain, turn the domain object parameters into move handles. 98 num_domain_objects = num_objects_to_move;
84 num_handles_to_move += num_domain_objects; 99 }
85 num_domain_objects = 0; 100
101 if (context.Session()->IsDomain()) {
102 raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
86 } 103 }
87 104
88 header.data_size.Assign(raw_data_size); 105 header.data_size.Assign(raw_data_size);
@@ -101,7 +118,7 @@ public:
101 118
102 AlignWithPadding(); 119 AlignWithPadding();
103 120
104 if (context.IsDomain()) { 121 if (context.Session()->IsDomain()) {
105 IPC::DomainMessageHeader domain_header{}; 122 IPC::DomainMessageHeader domain_header{};
106 domain_header.num_objects = num_domain_objects; 123 domain_header.num_objects = num_domain_objects;
107 PushRaw(domain_header); 124 PushRaw(domain_header);
@@ -110,12 +127,13 @@ public:
110 IPC::DataPayloadHeader data_payload_header{}; 127 IPC::DataPayloadHeader data_payload_header{};
111 data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O'); 128 data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
112 PushRaw(data_payload_header); 129 PushRaw(data_payload_header);
130
131 datapayload_index = index;
113 } 132 }
114 133
115 template <class T, class... Args> 134 template <class T>
116 void PushIpcInterface(Args&&... args) { 135 void PushIpcInterface(std::shared_ptr<T> iface) {
117 auto iface = std::make_shared<T>(std::forward<Args>(args)...); 136 if (context->Session()->IsDomain()) {
118 if (context->IsDomain()) {
119 context->AddDomainObject(std::move(iface)); 137 context->AddDomainObject(std::move(iface));
120 } else { 138 } else {
121 auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName()); 139 auto sessions = Kernel::ServerSession::CreateSessionPair(iface->GetServiceName());
@@ -126,8 +144,26 @@ public:
126 } 144 }
127 } 145 }
128 146
147 template <class T, class... Args>
148 void PushIpcInterface(Args&&... args) {
149 PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...));
150 }
151
152 void ValidateHeader() {
153 const size_t num_domain_objects = context->NumDomainObjects();
154 const size_t num_move_objects = context->NumMoveObjects();
155 ASSERT_MSG(!num_domain_objects || !num_move_objects,
156 "cannot move normal handles and domain objects");
157 ASSERT_MSG((index - datapayload_index) == normal_params_size,
158 "normal_params_size value is incorrect");
159 ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move,
160 "num_objects_to_move value is incorrect");
161 ASSERT_MSG(context->NumCopyObjects() == num_handles_to_copy,
162 "num_handles_to_copy value is incorrect");
163 }
164
129 // Validate on destruction, as there shouldn't be any case where we don't want it 165 // Validate on destruction, as there shouldn't be any case where we don't want it
130 ~RequestBuilder() { 166 ~ResponseBuilder() {
131 ValidateHeader(); 167 ValidateHeader();
132 } 168 }
133 169
@@ -155,52 +191,52 @@ public:
155/// Push /// 191/// Push ///
156 192
157template <> 193template <>
158inline void RequestBuilder::Push(u32 value) { 194inline void ResponseBuilder::Push(u32 value) {
159 cmdbuf[index++] = value; 195 cmdbuf[index++] = value;
160} 196}
161 197
162template <typename T> 198template <typename T>
163void RequestBuilder::PushRaw(const T& value) { 199void ResponseBuilder::PushRaw(const T& value) {
164 std::memcpy(cmdbuf + index, &value, sizeof(T)); 200 std::memcpy(cmdbuf + index, &value, sizeof(T));
165 index += (sizeof(T) + 3) / 4; // round up to word length 201 index += (sizeof(T) + 3) / 4; // round up to word length
166} 202}
167 203
168template <> 204template <>
169inline void RequestBuilder::Push(ResultCode value) { 205inline void ResponseBuilder::Push(ResultCode value) {
170 // Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded. 206 // Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded.
171 Push(value.raw); 207 Push(value.raw);
172 Push<u32>(0); 208 Push<u32>(0);
173} 209}
174 210
175template <> 211template <>
176inline void RequestBuilder::Push(u8 value) { 212inline void ResponseBuilder::Push(u8 value) {
177 PushRaw(value); 213 PushRaw(value);
178} 214}
179 215
180template <> 216template <>
181inline void RequestBuilder::Push(u16 value) { 217inline void ResponseBuilder::Push(u16 value) {
182 PushRaw(value); 218 PushRaw(value);
183} 219}
184 220
185template <> 221template <>
186inline void RequestBuilder::Push(u64 value) { 222inline void ResponseBuilder::Push(u64 value) {
187 Push(static_cast<u32>(value)); 223 Push(static_cast<u32>(value));
188 Push(static_cast<u32>(value >> 32)); 224 Push(static_cast<u32>(value >> 32));
189} 225}
190 226
191template <> 227template <>
192inline void RequestBuilder::Push(bool value) { 228inline void ResponseBuilder::Push(bool value) {
193 Push(static_cast<u8>(value)); 229 Push(static_cast<u8>(value));
194} 230}
195 231
196template <typename First, typename... Other> 232template <typename First, typename... Other>
197void RequestBuilder::Push(const First& first_value, const Other&... other_values) { 233void ResponseBuilder::Push(const First& first_value, const Other&... other_values) {
198 Push(first_value); 234 Push(first_value);
199 Push(other_values...); 235 Push(other_values...);
200} 236}
201 237
202template <typename... O> 238template <typename... O>
203inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) { 239inline void ResponseBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
204 auto objects = {pointers...}; 240 auto objects = {pointers...};
205 for (auto& object : objects) { 241 for (auto& object : objects) {
206 context->AddCopyObject(std::move(object)); 242 context->AddCopyObject(std::move(object));
@@ -208,7 +244,7 @@ inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
208} 244}
209 245
210template <typename... O> 246template <typename... O>
211inline void RequestBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) { 247inline void ResponseBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) {
212 auto objects = {pointers...}; 248 auto objects = {pointers...};
213 for (auto& object : objects) { 249 for (auto& object : objects) {
214 context->AddMoveObject(std::move(object)); 250 context->AddMoveObject(std::move(object));
@@ -227,15 +263,10 @@ public:
227 Skip(CommandIdSize, false); 263 Skip(CommandIdSize, false);
228 } 264 }
229 265
230 RequestBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy, 266 ResponseBuilder MakeBuilder(u32 normal_params_size, u32 num_handles_to_copy,
231 u32 num_handles_to_move, u32 num_domain_objects, 267 u32 num_handles_to_move,
232 bool validate_header = true) { 268 ResponseBuilder::Flags flags = ResponseBuilder::Flags::None) {
233 if (validate_header) { 269 return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move, flags};
234 ValidateHeader();
235 }
236
237 return {*context, normal_params_size, num_handles_to_copy, num_handles_to_move,
238 num_domain_objects};
239 } 270 }
240 271
241 template <typename T> 272 template <typename T>