diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 160 |
1 files changed, 88 insertions, 72 deletions
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 6089c39c7..68508caba 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -50,9 +50,9 @@ public: | |||
| 50 | template <typename T> | 50 | template <typename T> |
| 51 | void Push(T value); | 51 | void Push(T value); |
| 52 | 52 | ||
| 53 | template <> | 53 | void Push(u32 value) { |
| 54 | void Push(u32); | 54 | cmdbuf[index++] = value; |
| 55 | 55 | } | |
| 56 | template <typename First, class... Other> | 56 | template <typename First, class... Other> |
| 57 | void Push(First first_value, const Other&... other_values) { | 57 | void Push(First first_value, const Other&... other_values) { |
| 58 | Push(first_value); | 58 | Push(first_value); |
| @@ -86,7 +86,7 @@ public: | |||
| 86 | 86 | ||
| 87 | void PushCurrentPIDHandle() { | 87 | void PushCurrentPIDHandle() { |
| 88 | Push(CallingPidDesc()); | 88 | Push(CallingPidDesc()); |
| 89 | Push<u32>(0); | 89 | Push(u32(0)); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) { | 92 | void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) { |
| @@ -100,6 +100,24 @@ public: | |||
| 100 | } | 100 | } |
| 101 | }; | 101 | }; |
| 102 | 102 | ||
| 103 | /// Push /// | ||
| 104 | |||
| 105 | template <> | ||
| 106 | inline void RequestBuilder::Push<u32>(u32 value) { | ||
| 107 | Push(value); | ||
| 108 | } | ||
| 109 | |||
| 110 | template <> | ||
| 111 | inline void RequestBuilder::Push<u64>(u64 value) { | ||
| 112 | Push(static_cast<u32>(value)); | ||
| 113 | Push(static_cast<u32>(value >> 32)); | ||
| 114 | } | ||
| 115 | |||
| 116 | template <> | ||
| 117 | inline void RequestBuilder::Push<ResultCode>(ResultCode value) { | ||
| 118 | Push(value.raw); | ||
| 119 | } | ||
| 120 | |||
| 103 | class RequestParser : public RequestHelperBase { | 121 | class RequestParser : public RequestHelperBase { |
| 104 | public: | 122 | public: |
| 105 | RequestParser(u32* command_buffer, Header command_header) | 123 | RequestParser(u32* command_buffer, Header command_header) |
| @@ -123,39 +141,16 @@ public: | |||
| 123 | template <typename T> | 141 | template <typename T> |
| 124 | T Pop(); | 142 | T Pop(); |
| 125 | 143 | ||
| 126 | template <> | ||
| 127 | u32 Pop<u32>(); | ||
| 128 | |||
| 129 | template <typename T> | 144 | template <typename T> |
| 130 | void Pop(T& value) { | 145 | void Pop(T& value); |
| 131 | value = Pop<T>(); | ||
| 132 | } | ||
| 133 | 146 | ||
| 134 | template <typename First, class... Other> | 147 | template <typename First, class... Other> |
| 135 | void Pop(First& first_value, Other&... other_values) { | 148 | void Pop(First& first_value, Other&... other_values); |
| 136 | first_value = Pop<First>(); | ||
| 137 | Pop(other_values...); | ||
| 138 | } | ||
| 139 | 149 | ||
| 140 | Kernel::Handle PopHandle() { | 150 | Kernel::Handle PopHandle(); |
| 141 | const u32 handle_descriptor = Pop<u32>(); | ||
| 142 | DEBUG_ASSERT_MSG(IsHandleDescriptor(handle_descriptor), | ||
| 143 | "Tried to pop handle(s) but the descriptor is not a handle descriptor"); | ||
| 144 | DEBUG_ASSERT_MSG(HandleNumberFromDesc(handle_descriptor) == 1, | ||
| 145 | "Descriptor indicates that there isn't exactly one handle"); | ||
| 146 | return Pop<Kernel::Handle>(); | ||
| 147 | } | ||
| 148 | 151 | ||
| 149 | template <typename... H> | 152 | template <typename... H> |
| 150 | void PopHandles(H&... handles) { | 153 | void PopHandles(H&... handles); |
| 151 | const u32 handle_descriptor = Pop<u32>(); | ||
| 152 | const int handles_number = sizeof...(H); | ||
| 153 | DEBUG_ASSERT_MSG(IsHandleDescriptor(handle_descriptor), | ||
| 154 | "Tried to pop handle(s) but the descriptor is not a handle descriptor"); | ||
| 155 | DEBUG_ASSERT_MSG(handles_number == HandleNumberFromDesc(handle_descriptor), | ||
| 156 | "Number of handles doesn't match the descriptor"); | ||
| 157 | Pop(static_cast<Kernel::Handle&>(handles)...); | ||
| 158 | } | ||
| 159 | 154 | ||
| 160 | /** | 155 | /** |
| 161 | * @brief Pops the static buffer vaddr | 156 | * @brief Pops the static buffer vaddr |
| @@ -171,22 +166,7 @@ public: | |||
| 171 | * buffer information | 166 | * buffer information |
| 172 | * Please note that the setup uses virtual addresses. | 167 | * Please note that the setup uses virtual addresses. |
| 173 | */ | 168 | */ |
| 174 | VAddr PopStaticBuffer(size_t* data_size = nullptr, bool useStaticBuffersToGetVaddr = false) { | 169 | VAddr PopStaticBuffer(size_t* data_size = nullptr, bool useStaticBuffersToGetVaddr = false); |
| 175 | const u32 sbuffer_descriptor = Pop<u32>(); | ||
| 176 | StaticBufferDescInfo bufferInfo{sbuffer_descriptor}; | ||
| 177 | if (data_size != nullptr) | ||
| 178 | *data_size = bufferInfo.size; | ||
| 179 | if (!useStaticBuffersToGetVaddr) | ||
| 180 | return Pop<VAddr>(); | ||
| 181 | else { | ||
| 182 | ASSERT_MSG(0, "remove the assert if multiprocess/IPC translation are implemented."); | ||
| 183 | // The buffer has already been copied to the static buffer by the kernel during | ||
| 184 | // translation | ||
| 185 | Pop<VAddr>(); // Pop the calling process buffer address | ||
| 186 | // and get the vaddr from the static buffers | ||
| 187 | return cmdbuf[(0x100 >> 2) + bufferInfo.buffer_id * 2 + 1]; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | 170 | ||
| 191 | /** | 171 | /** |
| 192 | * @brief Pops the mapped buffer vaddr | 172 | * @brief Pops the mapped buffer vaddr |
| @@ -197,26 +177,14 @@ public: | |||
| 197 | * buffer | 177 | * buffer |
| 198 | */ | 178 | */ |
| 199 | VAddr PopMappedBuffer(size_t* data_size = nullptr, | 179 | VAddr PopMappedBuffer(size_t* data_size = nullptr, |
| 200 | MappedBufferPermissions* buffer_perms = nullptr) { | 180 | MappedBufferPermissions* buffer_perms = nullptr); |
| 201 | const u32 sbuffer_descriptor = Pop<u32>(); | ||
| 202 | MappedBufferDescInfo bufferInfo{sbuffer_descriptor}; | ||
| 203 | if (data_size != nullptr) | ||
| 204 | *data_size = bufferInfo.size; | ||
| 205 | if (buffer_perms != nullptr) | ||
| 206 | *buffer_perms = bufferInfo.perms; | ||
| 207 | return Pop<VAddr>(); | ||
| 208 | } | ||
| 209 | 181 | ||
| 210 | /** | 182 | /** |
| 211 | * @brief Reads the next normal parameters as a struct, by copying it | 183 | * @brief Reads the next normal parameters as a struct, by copying it |
| 212 | * @note: The output class must be correctly packed/padded to fit hardware layout. | 184 | * @note: The output class must be correctly packed/padded to fit hardware layout. |
| 213 | */ | 185 | */ |
| 214 | template <typename T> | 186 | template <typename T> |
| 215 | void PopRaw(T& value) { | 187 | void PopRaw(T& value); |
| 216 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 217 | std::memcpy(&value, cmdbuf + index, sizeof(T)); | ||
| 218 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 219 | } | ||
| 220 | }; | 188 | }; |
| 221 | 189 | ||
| 222 | /// Pop /// | 190 | /// Pop /// |
| @@ -238,22 +206,70 @@ inline ResultCode RequestParser::Pop<ResultCode>() { | |||
| 238 | return ResultCode{Pop<u32>()}; | 206 | return ResultCode{Pop<u32>()}; |
| 239 | } | 207 | } |
| 240 | 208 | ||
| 241 | /// Push /// | 209 | template <typename T> |
| 210 | void RequestParser::Pop(T& value) { | ||
| 211 | value = Pop<T>(); | ||
| 212 | } | ||
| 242 | 213 | ||
| 243 | template <> | 214 | template <typename First, class... Other> |
| 244 | inline void RequestBuilder::Push<u32>(u32 value) { | 215 | void RequestParser::Pop(First& first_value, Other&... other_values) { |
| 245 | cmdbuf[index++] = value; | 216 | first_value = Pop<First>(); |
| 217 | Pop(other_values...); | ||
| 246 | } | 218 | } |
| 247 | 219 | ||
| 248 | template <> | 220 | inline Kernel::Handle RequestParser::PopHandle() { |
| 249 | inline void RequestBuilder::Push<u64>(u64 value) { | 221 | const u32 handle_descriptor = Pop<u32>(); |
| 250 | Push(static_cast<u32>(value)); | 222 | DEBUG_ASSERT_MSG(IsHandleDescriptor(handle_descriptor), |
| 251 | Push(static_cast<u32>(value >> 32)); | 223 | "Tried to pop handle(s) but the descriptor is not a handle descriptor"); |
| 224 | DEBUG_ASSERT_MSG(HandleNumberFromDesc(handle_descriptor) == 1, | ||
| 225 | "Descriptor indicates that there isn't exactly one handle"); | ||
| 226 | return Pop<Kernel::Handle>(); | ||
| 252 | } | 227 | } |
| 253 | 228 | ||
| 254 | template <> | 229 | template <typename... H> |
| 255 | inline void RequestBuilder::Push<ResultCode>(ResultCode value) { | 230 | void RequestParser::PopHandles(H&... handles) { |
| 256 | Push(value.raw); | 231 | const u32 handle_descriptor = Pop<u32>(); |
| 232 | const int handles_number = sizeof...(H); | ||
| 233 | DEBUG_ASSERT_MSG(IsHandleDescriptor(handle_descriptor), | ||
| 234 | "Tried to pop handle(s) but the descriptor is not a handle descriptor"); | ||
| 235 | DEBUG_ASSERT_MSG(handles_number == HandleNumberFromDesc(handle_descriptor), | ||
| 236 | "Number of handles doesn't match the descriptor"); | ||
| 237 | Pop(static_cast<Kernel::Handle&>(handles)...); | ||
| 238 | } | ||
| 239 | |||
| 240 | inline VAddr RequestParser::PopStaticBuffer(size_t* data_size, bool useStaticBuffersToGetVaddr) { | ||
| 241 | const u32 sbuffer_descriptor = Pop<u32>(); | ||
| 242 | StaticBufferDescInfo bufferInfo{sbuffer_descriptor}; | ||
| 243 | if (data_size != nullptr) | ||
| 244 | *data_size = bufferInfo.size; | ||
| 245 | if (!useStaticBuffersToGetVaddr) | ||
| 246 | return Pop<VAddr>(); | ||
| 247 | else { | ||
| 248 | ASSERT_MSG(0, "remove the assert if multiprocess/IPC translation are implemented."); | ||
| 249 | // The buffer has already been copied to the static buffer by the kernel during | ||
| 250 | // translation | ||
| 251 | Pop<VAddr>(); // Pop the calling process buffer address | ||
| 252 | // and get the vaddr from the static buffers | ||
| 253 | return cmdbuf[(0x100 >> 2) + bufferInfo.buffer_id * 2 + 1]; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | inline VAddr RequestParser::PopMappedBuffer(size_t* data_size, | ||
| 258 | MappedBufferPermissions* buffer_perms) { | ||
| 259 | const u32 sbuffer_descriptor = Pop<u32>(); | ||
| 260 | MappedBufferDescInfo bufferInfo{sbuffer_descriptor}; | ||
| 261 | if (data_size != nullptr) | ||
| 262 | *data_size = bufferInfo.size; | ||
| 263 | if (buffer_perms != nullptr) | ||
| 264 | *buffer_perms = bufferInfo.perms; | ||
| 265 | return Pop<VAddr>(); | ||
| 266 | } | ||
| 267 | |||
| 268 | template <typename T> | ||
| 269 | void RequestParser::PopRaw(T& value) { | ||
| 270 | static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable"); | ||
| 271 | std::memcpy(&value, cmdbuf + index, sizeof(T)); | ||
| 272 | index += (sizeof(T) + 3) / 4; // round up to word length | ||
| 257 | } | 273 | } |
| 258 | 274 | ||
| 259 | } // namespace IPC | 275 | } // namespace IPC |