summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2023-07-11 16:49:24 -0700
committerGravatar GitHub2023-07-11 16:49:24 -0700
commit28598c9090bca460714dcbda86c829e57da2888d (patch)
tree069313aa26282c7e9f9d9694049baa9576ff5d45
parentMerge pull request #11070 from t895/home-setting-warning (diff)
parentk_server_session: translate special header for non-HLE requests (diff)
downloadyuzu-28598c9090bca460714dcbda86c829e57da2888d.tar.gz
yuzu-28598c9090bca460714dcbda86c829e57da2888d.tar.xz
yuzu-28598c9090bca460714dcbda86c829e57da2888d.zip
Merge pull request #10985 from liamwhite/handle-translate
k_server_session: translate special header for non-HLE requests
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/hle/kernel/k_server_session.cpp165
-rw-r--r--src/core/hle/kernel/message_buffer.h612
3 files changed, 771 insertions, 7 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 3655b8478..28cb6f86f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -285,6 +285,7 @@ add_library(core STATIC
285 hle/kernel/kernel.cpp 285 hle/kernel/kernel.cpp
286 hle/kernel/kernel.h 286 hle/kernel/kernel.h
287 hle/kernel/memory_types.h 287 hle/kernel/memory_types.h
288 hle/kernel/message_buffer.h
288 hle/kernel/physical_core.cpp 289 hle/kernel/physical_core.cpp
289 hle/kernel/physical_core.h 290 hle/kernel/physical_core.h
290 hle/kernel/physical_memory.h 291 hle/kernel/physical_memory.h
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index c66aff501..c64ceb530 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -20,12 +20,132 @@
20#include "core/hle/kernel/k_thread.h" 20#include "core/hle/kernel/k_thread.h"
21#include "core/hle/kernel/k_thread_queue.h" 21#include "core/hle/kernel/k_thread_queue.h"
22#include "core/hle/kernel/kernel.h" 22#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/message_buffer.h"
23#include "core/hle/service/hle_ipc.h" 24#include "core/hle/service/hle_ipc.h"
24#include "core/hle/service/ipc_helpers.h" 25#include "core/hle/service/ipc_helpers.h"
25#include "core/memory.h" 26#include "core/memory.h"
26 27
27namespace Kernel { 28namespace Kernel {
28 29
30namespace {
31
32template <bool MoveHandleAllowed>
33Result ProcessMessageSpecialData(KProcess& dst_process, KProcess& src_process, KThread& src_thread,
34 MessageBuffer& dst_msg, const MessageBuffer& src_msg,
35 MessageBuffer::SpecialHeader& src_special_header) {
36 // Copy the special header to the destination.
37 s32 offset = dst_msg.Set(src_special_header);
38
39 // Copy the process ID.
40 if (src_special_header.GetHasProcessId()) {
41 offset = dst_msg.SetProcessId(offset, src_process.GetProcessId());
42 }
43
44 // Prepare to process handles.
45 auto& dst_handle_table = dst_process.GetHandleTable();
46 auto& src_handle_table = src_process.GetHandleTable();
47 Result result = ResultSuccess;
48
49 // Process copy handles.
50 for (auto i = 0; i < src_special_header.GetCopyHandleCount(); ++i) {
51 // Get the handles.
52 const Handle src_handle = src_msg.GetHandle(offset);
53 Handle dst_handle = Svc::InvalidHandle;
54
55 // If we're in a success state, try to move the handle to the new table.
56 if (R_SUCCEEDED(result) && src_handle != Svc::InvalidHandle) {
57 KScopedAutoObject obj =
58 src_handle_table.GetObjectForIpc(src_handle, std::addressof(src_thread));
59 if (obj.IsNotNull()) {
60 Result add_result =
61 dst_handle_table.Add(std::addressof(dst_handle), obj.GetPointerUnsafe());
62 if (R_FAILED(add_result)) {
63 result = add_result;
64 dst_handle = Svc::InvalidHandle;
65 }
66 } else {
67 result = ResultInvalidHandle;
68 }
69 }
70
71 // Set the handle.
72 offset = dst_msg.SetHandle(offset, dst_handle);
73 }
74
75 // Process move handles.
76 if constexpr (MoveHandleAllowed) {
77 for (auto i = 0; i < src_special_header.GetMoveHandleCount(); ++i) {
78 // Get the handles.
79 const Handle src_handle = src_msg.GetHandle(offset);
80 Handle dst_handle = Svc::InvalidHandle;
81
82 // Whether or not we've succeeded, we need to remove the handles from the source table.
83 if (src_handle != Svc::InvalidHandle) {
84 if (R_SUCCEEDED(result)) {
85 KScopedAutoObject obj =
86 src_handle_table.GetObjectForIpcWithoutPseudoHandle(src_handle);
87 if (obj.IsNotNull()) {
88 Result add_result = dst_handle_table.Add(std::addressof(dst_handle),
89 obj.GetPointerUnsafe());
90
91 src_handle_table.Remove(src_handle);
92
93 if (R_FAILED(add_result)) {
94 result = add_result;
95 dst_handle = Svc::InvalidHandle;
96 }
97 } else {
98 result = ResultInvalidHandle;
99 }
100 } else {
101 src_handle_table.Remove(src_handle);
102 }
103 }
104
105 // Set the handle.
106 offset = dst_msg.SetHandle(offset, dst_handle);
107 }
108 }
109
110 R_RETURN(result);
111}
112
113void CleanupSpecialData(KProcess& dst_process, u32* dst_msg_ptr, size_t dst_buffer_size) {
114 // Parse the message.
115 const MessageBuffer dst_msg(dst_msg_ptr, dst_buffer_size);
116 const MessageBuffer::MessageHeader dst_header(dst_msg);
117 const MessageBuffer::SpecialHeader dst_special_header(dst_msg, dst_header);
118
119 // Check that the size is big enough.
120 if (MessageBuffer::GetMessageBufferSize(dst_header, dst_special_header) > dst_buffer_size) {
121 return;
122 }
123
124 // Set the special header.
125 int offset = dst_msg.Set(dst_special_header);
126
127 // Clear the process id, if needed.
128 if (dst_special_header.GetHasProcessId()) {
129 offset = dst_msg.SetProcessId(offset, 0);
130 }
131
132 // Clear handles, as relevant.
133 auto& dst_handle_table = dst_process.GetHandleTable();
134 for (auto i = 0;
135 i < (dst_special_header.GetCopyHandleCount() + dst_special_header.GetMoveHandleCount());
136 ++i) {
137 const Handle handle = dst_msg.GetHandle(offset);
138
139 if (handle != Svc::InvalidHandle) {
140 dst_handle_table.Remove(handle);
141 }
142
143 offset = dst_msg.SetHandle(offset, Svc::InvalidHandle);
144 }
145}
146
147} // namespace
148
29using ThreadQueueImplForKServerSessionRequest = KThreadQueue; 149using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
30 150
31KServerSession::KServerSession(KernelCore& kernel) 151KServerSession::KServerSession(KernelCore& kernel)
@@ -223,12 +343,27 @@ Result KServerSession::SendReply(bool is_hle) {
223 // the reply has already been written in this case. 343 // the reply has already been written in this case.
224 } else { 344 } else {
225 Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; 345 Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
226 KThread* server_thread{GetCurrentThreadPointer(m_kernel)}; 346 KThread* server_thread = GetCurrentThreadPointer(m_kernel);
347 KProcess& src_process = *client_thread->GetOwnerProcess();
348 KProcess& dst_process = *server_thread->GetOwnerProcess();
227 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); 349 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
228 350
229 auto* src_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress()); 351 auto* src_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
230 auto* dst_msg_buffer = memory.GetPointer(client_message); 352 auto* dst_msg_buffer = memory.GetPointer<u32>(client_message);
231 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); 353 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
354
355 // Translate special header ad-hoc.
356 MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
357 MessageBuffer::MessageHeader src_header(src_msg);
358 MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
359 if (src_header.GetHasSpecialHeader()) {
360 MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
361 result = ProcessMessageSpecialData<true>(dst_process, src_process, *server_thread,
362 dst_msg, src_msg, src_special_header);
363 if (R_FAILED(result)) {
364 CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
365 }
366 }
232 } 367 }
233 } else { 368 } else {
234 result = ResultSessionClosed; 369 result = ResultSessionClosed;
@@ -330,12 +465,28 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
330 ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), 465 ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
331 cmd_buf); 466 cmd_buf);
332 } else { 467 } else {
333 KThread* server_thread{GetCurrentThreadPointer(m_kernel)}; 468 KThread* server_thread = GetCurrentThreadPointer(m_kernel);
334 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); 469 KProcess& src_process = *client_thread->GetOwnerProcess();
470 KProcess& dst_process = *server_thread->GetOwnerProcess();
471 UNIMPLEMENTED_IF(client_thread->GetOwnerProcess() != server_thread->GetOwnerProcess());
335 472
336 auto* src_msg_buffer = memory.GetPointer(client_message); 473 auto* src_msg_buffer = memory.GetPointer<u32>(client_message);
337 auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress()); 474 auto* dst_msg_buffer = memory.GetPointer<u32>(server_thread->GetTlsAddress());
338 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); 475 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
476
477 // Translate special header ad-hoc.
478 // TODO: fix this mess
479 MessageBuffer src_msg(src_msg_buffer, client_buffer_size);
480 MessageBuffer::MessageHeader src_header(src_msg);
481 MessageBuffer::SpecialHeader src_special_header(src_msg, src_header);
482 if (src_header.GetHasSpecialHeader()) {
483 MessageBuffer dst_msg(dst_msg_buffer, client_buffer_size);
484 Result res = ProcessMessageSpecialData<false>(dst_process, src_process, *client_thread,
485 dst_msg, src_msg, src_special_header);
486 if (R_FAILED(res)) {
487 CleanupSpecialData(dst_process, dst_msg_buffer, client_buffer_size);
488 }
489 }
339 } 490 }
340 491
341 // We succeeded. 492 // We succeeded.
diff --git a/src/core/hle/kernel/message_buffer.h b/src/core/hle/kernel/message_buffer.h
new file mode 100644
index 000000000..75b275310
--- /dev/null
+++ b/src/core/hle/kernel/message_buffer.h
@@ -0,0 +1,612 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/alignment.h"
7#include "common/bit_field.h"
8#include "core/hle/kernel/k_thread.h"
9
10namespace Kernel {
11
12constexpr inline size_t MessageBufferSize = 0x100;
13
14class MessageBuffer {
15public:
16 class MessageHeader {
17 private:
18 static constexpr inline u64 NullTag = 0;
19
20 public:
21 enum class ReceiveListCountType : u32 {
22 None = 0,
23 ToMessageBuffer = 1,
24 ToSingleBuffer = 2,
25
26 CountOffset = 2,
27 CountMax = 13,
28 };
29
30 private:
31 union {
32 std::array<u32, 2> raw;
33
34 struct {
35 // Define fields for the first header word.
36 union {
37 BitField<0, 16, u16> tag;
38 BitField<16, 4, u32> pointer_count;
39 BitField<20, 4, u32> send_count;
40 BitField<24, 4, u32> receive_count;
41 BitField<28, 4, u32> exchange_count;
42 };
43
44 // Define fields for the second header word.
45 union {
46 BitField<0, 10, u32> raw_count;
47 BitField<10, 4, ReceiveListCountType> receive_list_count;
48 BitField<14, 6, u32> reserved0;
49 BitField<20, 11, u32> receive_list_offset;
50 BitField<31, 1, u32> has_special_header;
51 };
52 };
53 } m_header;
54
55 public:
56 constexpr MessageHeader() : m_header{} {}
57
58 constexpr MessageHeader(u16 tag, bool special, s32 ptr, s32 send, s32 recv, s32 exch,
59 s32 raw, ReceiveListCountType recv_list)
60 : m_header{} {
61 m_header.raw[0] = 0;
62 m_header.raw[1] = 0;
63
64 m_header.tag.Assign(tag);
65 m_header.pointer_count.Assign(ptr);
66 m_header.send_count.Assign(send);
67 m_header.receive_count.Assign(recv);
68 m_header.exchange_count.Assign(exch);
69
70 m_header.raw_count.Assign(raw);
71 m_header.receive_list_count.Assign(recv_list);
72 m_header.has_special_header.Assign(special);
73 }
74
75 explicit MessageHeader(const MessageBuffer& buf) : m_header{} {
76 buf.Get(0, m_header.raw.data(), 2);
77 }
78
79 explicit MessageHeader(const u32* msg) : m_header{{msg[0], msg[1]}} {}
80
81 constexpr u16 GetTag() const {
82 return m_header.tag;
83 }
84
85 constexpr s32 GetPointerCount() const {
86 return m_header.pointer_count;
87 }
88
89 constexpr s32 GetSendCount() const {
90 return m_header.send_count;
91 }
92
93 constexpr s32 GetReceiveCount() const {
94 return m_header.receive_count;
95 }
96
97 constexpr s32 GetExchangeCount() const {
98 return m_header.exchange_count;
99 }
100
101 constexpr s32 GetMapAliasCount() const {
102 return this->GetSendCount() + this->GetReceiveCount() + this->GetExchangeCount();
103 }
104
105 constexpr s32 GetRawCount() const {
106 return m_header.raw_count;
107 }
108
109 constexpr ReceiveListCountType GetReceiveListCount() const {
110 return m_header.receive_list_count;
111 }
112
113 constexpr s32 GetReceiveListOffset() const {
114 return m_header.receive_list_offset;
115 }
116
117 constexpr bool GetHasSpecialHeader() const {
118 return m_header.has_special_header.Value() != 0;
119 }
120
121 constexpr void SetReceiveListCount(ReceiveListCountType recv_list) {
122 m_header.receive_list_count.Assign(recv_list);
123 }
124
125 constexpr const u32* GetData() const {
126 return m_header.raw.data();
127 }
128
129 static constexpr size_t GetDataSize() {
130 return sizeof(m_header);
131 }
132 };
133
134 class SpecialHeader {
135 private:
136 union {
137 std::array<u32, 1> raw;
138
139 // Define fields for the header word.
140 BitField<0, 1, u32> has_process_id;
141 BitField<1, 4, u32> copy_handle_count;
142 BitField<5, 4, u32> move_handle_count;
143 } m_header;
144 bool m_has_header;
145
146 public:
147 constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move)
148 : m_header{}, m_has_header(true) {
149 m_header.has_process_id.Assign(pid);
150 m_header.copy_handle_count.Assign(copy);
151 m_header.move_handle_count.Assign(move);
152 }
153
154 constexpr explicit SpecialHeader(bool pid, s32 copy, s32 move, bool _has_header)
155 : m_header{}, m_has_header(_has_header) {
156 m_header.has_process_id.Assign(pid);
157 m_header.copy_handle_count.Assign(copy);
158 m_header.move_handle_count.Assign(move);
159 }
160
161 explicit SpecialHeader(const MessageBuffer& buf, const MessageHeader& hdr)
162 : m_header{}, m_has_header(hdr.GetHasSpecialHeader()) {
163 if (m_has_header) {
164 buf.Get(static_cast<s32>(MessageHeader::GetDataSize() / sizeof(u32)),
165 m_header.raw.data(), sizeof(m_header) / sizeof(u32));
166 }
167 }
168
169 constexpr bool GetHasProcessId() const {
170 return m_header.has_process_id.Value() != 0;
171 }
172
173 constexpr s32 GetCopyHandleCount() const {
174 return m_header.copy_handle_count;
175 }
176
177 constexpr s32 GetMoveHandleCount() const {
178 return m_header.move_handle_count;
179 }
180
181 constexpr const u32* GetHeader() const {
182 return m_header.raw.data();
183 }
184
185 constexpr size_t GetHeaderSize() const {
186 if (m_has_header) {
187 return sizeof(m_header);
188 } else {
189 return 0;
190 }
191 }
192
193 constexpr size_t GetDataSize() const {
194 if (m_has_header) {
195 return (this->GetHasProcessId() ? sizeof(u64) : 0) +
196 (this->GetCopyHandleCount() * sizeof(Handle)) +
197 (this->GetMoveHandleCount() * sizeof(Handle));
198 } else {
199 return 0;
200 }
201 }
202 };
203
204 class MapAliasDescriptor {
205 public:
206 enum class Attribute : u32 {
207 Ipc = 0,
208 NonSecureIpc = 1,
209 NonDeviceIpc = 3,
210 };
211
212 private:
213 static constexpr u32 SizeLowCount = 32;
214 static constexpr u32 SizeHighCount = 4;
215 static constexpr u32 AddressLowCount = 32;
216 static constexpr u32 AddressMidCount = 4;
217
218 constexpr u32 GetAddressMid(u64 address) {
219 return static_cast<u32>(address >> AddressLowCount) & ((1U << AddressMidCount) - 1);
220 }
221
222 constexpr u32 GetAddressHigh(u64 address) {
223 return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
224 }
225
226 private:
227 union {
228 std::array<u32, 3> raw;
229
230 struct {
231 // Define fields for the first two words.
232 u32 size_low;
233 u32 address_low;
234
235 // Define fields for the packed descriptor word.
236 union {
237 BitField<0, 2, Attribute> attributes;
238 BitField<2, 3, u32> address_high;
239 BitField<5, 19, u32> reserved;
240 BitField<24, 4, u32> size_high;
241 BitField<28, 4, u32> address_mid;
242 };
243 };
244 } m_data;
245
246 public:
247 constexpr MapAliasDescriptor() : m_data{} {}
248
249 MapAliasDescriptor(const void* buffer, size_t _size, Attribute attr = Attribute::Ipc)
250 : m_data{} {
251 const u64 address = reinterpret_cast<u64>(buffer);
252 const u64 size = static_cast<u64>(_size);
253 m_data.size_low = static_cast<u32>(size);
254 m_data.address_low = static_cast<u32>(address);
255 m_data.attributes.Assign(attr);
256 m_data.address_mid.Assign(GetAddressMid(address));
257 m_data.size_high.Assign(static_cast<u32>(size >> SizeLowCount));
258 m_data.address_high.Assign(GetAddressHigh(address));
259 }
260
261 MapAliasDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
262 buf.Get(index, m_data.raw.data(), 3);
263 }
264
265 constexpr uintptr_t GetAddress() const {
266 return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
267 << AddressLowCount) |
268 m_data.address_low;
269 }
270
271 constexpr uintptr_t GetSize() const {
272 return (static_cast<u64>(m_data.size_high) << SizeLowCount) | m_data.size_low;
273 }
274
275 constexpr Attribute GetAttribute() const {
276 return m_data.attributes;
277 }
278
279 constexpr const u32* GetData() const {
280 return m_data.raw.data();
281 }
282
283 static constexpr size_t GetDataSize() {
284 return sizeof(m_data);
285 }
286 };
287
288 class PointerDescriptor {
289 private:
290 static constexpr u32 AddressLowCount = 32;
291 static constexpr u32 AddressMidCount = 4;
292
293 constexpr u32 GetAddressMid(u64 address) {
294 return static_cast<u32>(address >> AddressLowCount) & ((1u << AddressMidCount) - 1);
295 }
296
297 constexpr u32 GetAddressHigh(u64 address) {
298 return static_cast<u32>(address >> (AddressLowCount + AddressMidCount));
299 }
300
301 private:
302 union {
303 std::array<u32, 2> raw;
304
305 struct {
306 // Define fields for the packed descriptor word.
307 union {
308 BitField<0, 4, u32> index;
309 BitField<4, 2, u32> reserved0;
310 BitField<6, 3, u32> address_high;
311 BitField<9, 3, u32> reserved1;
312 BitField<12, 4, u32> address_mid;
313 BitField<16, 16, u32> size;
314 };
315
316 // Define fields for the second word.
317 u32 address_low;
318 };
319 } m_data;
320
321 public:
322 constexpr PointerDescriptor() : m_data{} {}
323
324 PointerDescriptor(const void* buffer, size_t size, s32 index) : m_data{} {
325 const u64 address = reinterpret_cast<u64>(buffer);
326
327 m_data.index.Assign(index);
328 m_data.address_high.Assign(GetAddressHigh(address));
329 m_data.address_mid.Assign(GetAddressMid(address));
330 m_data.size.Assign(static_cast<u32>(size));
331
332 m_data.address_low = static_cast<u32>(address);
333 }
334
335 PointerDescriptor(const MessageBuffer& buf, s32 index) : m_data{} {
336 buf.Get(index, m_data.raw.data(), 2);
337 }
338
339 constexpr s32 GetIndex() const {
340 return m_data.index;
341 }
342
343 constexpr uintptr_t GetAddress() const {
344 return (static_cast<u64>((m_data.address_high << AddressMidCount) | m_data.address_mid)
345 << AddressLowCount) |
346 m_data.address_low;
347 }
348
349 constexpr size_t GetSize() const {
350 return m_data.size;
351 }
352
353 constexpr const u32* GetData() const {
354 return m_data.raw.data();
355 }
356
357 static constexpr size_t GetDataSize() {
358 return sizeof(m_data);
359 }
360 };
361
362 class ReceiveListEntry {
363 private:
364 static constexpr u32 AddressLowCount = 32;
365
366 constexpr u32 GetAddressHigh(u64 address) {
367 return static_cast<u32>(address >> (AddressLowCount));
368 }
369
370 private:
371 union {
372 std::array<u32, 2> raw;
373
374 struct {
375 // Define fields for the first word.
376 u32 address_low;
377
378 // Define fields for the packed descriptor word.
379 union {
380 BitField<0, 7, u32> address_high;
381 BitField<7, 9, u32> reserved;
382 BitField<16, 16, u32> size;
383 };
384 };
385 } m_data;
386
387 public:
388 constexpr ReceiveListEntry() : m_data{} {}
389
390 ReceiveListEntry(const void* buffer, size_t size) : m_data{} {
391 const u64 address = reinterpret_cast<u64>(buffer);
392
393 m_data.address_low = static_cast<u32>(address);
394
395 m_data.address_high.Assign(GetAddressHigh(address));
396 m_data.size.Assign(static_cast<u32>(size));
397 }
398
399 ReceiveListEntry(u32 a, u32 b) : m_data{{a, b}} {}
400
401 constexpr uintptr_t GetAddress() const {
402 return (static_cast<u64>(m_data.address_high) << AddressLowCount) | m_data.address_low;
403 }
404
405 constexpr size_t GetSize() const {
406 return m_data.size;
407 }
408
409 constexpr const u32* GetData() const {
410 return m_data.raw.data();
411 }
412
413 static constexpr size_t GetDataSize() {
414 return sizeof(m_data);
415 }
416 };
417
418private:
419 u32* m_buffer;
420 size_t m_size;
421
422public:
423 constexpr MessageBuffer(u32* b, size_t sz) : m_buffer(b), m_size(sz) {}
424 constexpr explicit MessageBuffer(u32* b) : m_buffer(b), m_size(MessageBufferSize) {}
425
426 constexpr void* GetBufferForDebug() const {
427 return m_buffer;
428 }
429
430 constexpr size_t GetBufferSize() const {
431 return m_size;
432 }
433
434 void Get(s32 index, u32* dst, size_t count) const {
435 // Ensure that this doesn't get re-ordered.
436 std::atomic_thread_fence(std::memory_order_seq_cst);
437
438 // Get the words.
439 static_assert(sizeof(*dst) == sizeof(*m_buffer));
440
441 memcpy(dst, m_buffer + index, count * sizeof(*dst));
442 }
443
444 s32 Set(s32 index, u32* src, size_t count) const {
445 // Ensure that this doesn't get re-ordered.
446 std::atomic_thread_fence(std::memory_order_seq_cst);
447
448 // Set the words.
449 memcpy(m_buffer + index, src, count * sizeof(*src));
450
451 // Ensure that this doesn't get re-ordered.
452 std::atomic_thread_fence(std::memory_order_seq_cst);
453
454 return static_cast<s32>(index + count);
455 }
456
457 template <typename T>
458 const T& GetRaw(s32 index) const {
459 return *reinterpret_cast<const T*>(m_buffer + index);
460 }
461
462 template <typename T>
463 s32 SetRaw(s32 index, const T& val) const {
464 *reinterpret_cast<const T*>(m_buffer + index) = val;
465 return index + (Common::AlignUp(sizeof(val), sizeof(*m_buffer)) / sizeof(*m_buffer));
466 }
467
468 void GetRawArray(s32 index, void* dst, size_t len) const {
469 memcpy(dst, m_buffer + index, len);
470 }
471
472 void SetRawArray(s32 index, const void* src, size_t len) const {
473 memcpy(m_buffer + index, src, len);
474 }
475
476 void SetNull() const {
477 this->Set(MessageHeader());
478 }
479
480 s32 Set(const MessageHeader& hdr) const {
481 memcpy(m_buffer, hdr.GetData(), hdr.GetDataSize());
482 return static_cast<s32>(hdr.GetDataSize() / sizeof(*m_buffer));
483 }
484
485 s32 Set(const SpecialHeader& spc) const {
486 const s32 index = static_cast<s32>(MessageHeader::GetDataSize() / sizeof(*m_buffer));
487 memcpy(m_buffer + index, spc.GetHeader(), spc.GetHeaderSize());
488 return static_cast<s32>(index + (spc.GetHeaderSize() / sizeof(*m_buffer)));
489 }
490
491 s32 SetHandle(s32 index, const Handle& hnd) const {
492 memcpy(m_buffer + index, std::addressof(hnd), sizeof(hnd));
493 return static_cast<s32>(index + (sizeof(hnd) / sizeof(*m_buffer)));
494 }
495
496 s32 SetProcessId(s32 index, const u64 pid) const {
497 memcpy(m_buffer + index, std::addressof(pid), sizeof(pid));
498 return static_cast<s32>(index + (sizeof(pid) / sizeof(*m_buffer)));
499 }
500
501 s32 Set(s32 index, const MapAliasDescriptor& desc) const {
502 memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
503 return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
504 }
505
506 s32 Set(s32 index, const PointerDescriptor& desc) const {
507 memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
508 return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
509 }
510
511 s32 Set(s32 index, const ReceiveListEntry& desc) const {
512 memcpy(m_buffer + index, desc.GetData(), desc.GetDataSize());
513 return static_cast<s32>(index + (desc.GetDataSize() / sizeof(*m_buffer)));
514 }
515
516 s32 Set(s32 index, const u32 val) const {
517 memcpy(m_buffer + index, std::addressof(val), sizeof(val));
518 return static_cast<s32>(index + (sizeof(val) / sizeof(*m_buffer)));
519 }
520
521 Result GetAsyncResult() const {
522 MessageHeader hdr(m_buffer);
523 MessageHeader null{};
524 if (memcmp(hdr.GetData(), null.GetData(), MessageHeader::GetDataSize()) != 0) [[unlikely]] {
525 R_SUCCEED();
526 }
527 return Result(m_buffer[MessageHeader::GetDataSize() / sizeof(*m_buffer)]);
528 }
529
530 void SetAsyncResult(Result res) const {
531 const s32 index = this->Set(MessageHeader());
532 const auto value = res.raw;
533 memcpy(m_buffer + index, std::addressof(value), sizeof(value));
534 }
535
536 u32 Get32(s32 index) const {
537 return m_buffer[index];
538 }
539
540 u64 Get64(s32 index) const {
541 u64 value;
542 memcpy(std::addressof(value), m_buffer + index, sizeof(value));
543 return value;
544 }
545
546 u64 GetProcessId(s32 index) const {
547 return this->Get64(index);
548 }
549
550 Handle GetHandle(s32 index) const {
551 static_assert(sizeof(Handle) == sizeof(*m_buffer));
552 return Handle(m_buffer[index]);
553 }
554
555 static constexpr s32 GetSpecialDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
556 return static_cast<s32>((MessageHeader::GetDataSize() / sizeof(u32)) +
557 (spc.GetHeaderSize() / sizeof(u32)));
558 }
559
560 static constexpr s32 GetPointerDescriptorIndex(const MessageHeader& hdr,
561 const SpecialHeader& spc) {
562 return static_cast<s32>(GetSpecialDataIndex(hdr, spc) + (spc.GetDataSize() / sizeof(u32)));
563 }
564
565 static constexpr s32 GetMapAliasDescriptorIndex(const MessageHeader& hdr,
566 const SpecialHeader& spc) {
567 return GetPointerDescriptorIndex(hdr, spc) +
568 static_cast<s32>(hdr.GetPointerCount() * PointerDescriptor::GetDataSize() /
569 sizeof(u32));
570 }
571
572 static constexpr s32 GetRawDataIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
573 return GetMapAliasDescriptorIndex(hdr, spc) +
574 static_cast<s32>(hdr.GetMapAliasCount() * MapAliasDescriptor::GetDataSize() /
575 sizeof(u32));
576 }
577
578 static constexpr s32 GetReceiveListIndex(const MessageHeader& hdr, const SpecialHeader& spc) {
579 if (const s32 recv_list_index = hdr.GetReceiveListOffset()) {
580 return recv_list_index;
581 } else {
582 return GetRawDataIndex(hdr, spc) + hdr.GetRawCount();
583 }
584 }
585
586 static constexpr size_t GetMessageBufferSize(const MessageHeader& hdr,
587 const SpecialHeader& spc) {
588 // Get the size of the plain message.
589 size_t msg_size = GetReceiveListIndex(hdr, spc) * sizeof(u32);
590
591 // Add the size of the receive list.
592 const auto count = hdr.GetReceiveListCount();
593 switch (count) {
594 case MessageHeader::ReceiveListCountType::None:
595 break;
596 case MessageHeader::ReceiveListCountType::ToMessageBuffer:
597 break;
598 case MessageHeader::ReceiveListCountType::ToSingleBuffer:
599 msg_size += ReceiveListEntry::GetDataSize();
600 break;
601 default:
602 msg_size += (static_cast<s32>(count) -
603 static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) *
604 ReceiveListEntry::GetDataSize();
605 break;
606 }
607
608 return msg_size;
609 }
610};
611
612} // namespace Kernel