diff options
Diffstat (limited to 'src/core/hle/ipc_helpers.h')
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 115 |
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 | ||
| 63 | class RequestBuilder : public RequestHelperBase { | 57 | class ResponseBuilder : public RequestHelperBase { |
| 64 | public: | 58 | public: |
| 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 | ||
| 157 | template <> | 193 | template <> |
| 158 | inline void RequestBuilder::Push(u32 value) { | 194 | inline void ResponseBuilder::Push(u32 value) { |
| 159 | cmdbuf[index++] = value; | 195 | cmdbuf[index++] = value; |
| 160 | } | 196 | } |
| 161 | 197 | ||
| 162 | template <typename T> | 198 | template <typename T> |
| 163 | void RequestBuilder::PushRaw(const T& value) { | 199 | void 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 | ||
| 168 | template <> | 204 | template <> |
| 169 | inline void RequestBuilder::Push(ResultCode value) { | 205 | inline 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 | ||
| 175 | template <> | 211 | template <> |
| 176 | inline void RequestBuilder::Push(u8 value) { | 212 | inline void ResponseBuilder::Push(u8 value) { |
| 177 | PushRaw(value); | 213 | PushRaw(value); |
| 178 | } | 214 | } |
| 179 | 215 | ||
| 180 | template <> | 216 | template <> |
| 181 | inline void RequestBuilder::Push(u16 value) { | 217 | inline void ResponseBuilder::Push(u16 value) { |
| 182 | PushRaw(value); | 218 | PushRaw(value); |
| 183 | } | 219 | } |
| 184 | 220 | ||
| 185 | template <> | 221 | template <> |
| 186 | inline void RequestBuilder::Push(u64 value) { | 222 | inline 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 | ||
| 191 | template <> | 227 | template <> |
| 192 | inline void RequestBuilder::Push(bool value) { | 228 | inline void ResponseBuilder::Push(bool value) { |
| 193 | Push(static_cast<u8>(value)); | 229 | Push(static_cast<u8>(value)); |
| 194 | } | 230 | } |
| 195 | 231 | ||
| 196 | template <typename First, typename... Other> | 232 | template <typename First, typename... Other> |
| 197 | void RequestBuilder::Push(const First& first_value, const Other&... other_values) { | 233 | void 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 | ||
| 202 | template <typename... O> | 238 | template <typename... O> |
| 203 | inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) { | 239 | inline 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 | ||
| 210 | template <typename... O> | 246 | template <typename... O> |
| 211 | inline void RequestBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) { | 247 | inline 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> |