diff options
| author | 2023-07-11 16:49:24 -0700 | |
|---|---|---|
| committer | 2023-07-11 16:49:24 -0700 | |
| commit | 28598c9090bca460714dcbda86c829e57da2888d (patch) | |
| tree | 069313aa26282c7e9f9d9694049baa9576ff5d45 | |
| parent | Merge pull request #11070 from t895/home-setting-warning (diff) | |
| parent | k_server_session: translate special header for non-HLE requests (diff) | |
| download | yuzu-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.txt | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 165 | ||||
| -rw-r--r-- | src/core/hle/kernel/message_buffer.h | 612 |
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 | ||
| 27 | namespace Kernel { | 28 | namespace Kernel { |
| 28 | 29 | ||
| 30 | namespace { | ||
| 31 | |||
| 32 | template <bool MoveHandleAllowed> | ||
| 33 | Result 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 | |||
| 113 | void 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 | |||
| 29 | using ThreadQueueImplForKServerSessionRequest = KThreadQueue; | 149 | using ThreadQueueImplForKServerSessionRequest = KThreadQueue; |
| 30 | 150 | ||
| 31 | KServerSession::KServerSession(KernelCore& kernel) | 151 | KServerSession::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 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | constexpr inline size_t MessageBufferSize = 0x100; | ||
| 13 | |||
| 14 | class MessageBuffer { | ||
| 15 | public: | ||
| 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 | |||
| 418 | private: | ||
| 419 | u32* m_buffer; | ||
| 420 | size_t m_size; | ||
| 421 | |||
| 422 | public: | ||
| 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 | ||