diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/cmif_serialization.h | 337 | ||||
| -rw-r--r-- | src/core/hle/service/cmif_types.h | 234 | ||||
| -rw-r--r-- | src/core/hle/service/hle_ipc.cpp | 16 | ||||
| -rw-r--r-- | src/core/hle/service/hle_ipc.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/jit/jit.cpp | 283 | ||||
| -rw-r--r-- | src/core/hle/service/ro/ro.cpp | 192 | ||||
| -rw-r--r-- | src/core/hle/service/service.h | 16 |
8 files changed, 729 insertions, 353 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f75b5e10a..45a0d8746 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -472,6 +472,8 @@ add_library(core STATIC | |||
| 472 | hle/service/caps/caps_types.h | 472 | hle/service/caps/caps_types.h |
| 473 | hle/service/caps/caps_u.cpp | 473 | hle/service/caps/caps_u.cpp |
| 474 | hle/service/caps/caps_u.h | 474 | hle/service/caps/caps_u.h |
| 475 | hle/service/cmif_serialization.h | ||
| 476 | hle/service/cmif_types.h | ||
| 475 | hle/service/erpt/erpt.cpp | 477 | hle/service/erpt/erpt.cpp |
| 476 | hle/service/erpt/erpt.h | 478 | hle/service/erpt/erpt.h |
| 477 | hle/service/es/es.cpp | 479 | hle/service/es/es.cpp |
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h new file mode 100644 index 000000000..8e8cf2507 --- /dev/null +++ b/src/core/hle/service/cmif_serialization.h | |||
| @@ -0,0 +1,337 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/div_ceil.h" | ||
| 7 | |||
| 8 | #include "core/hle/service/cmif_types.h" | ||
| 9 | #include "core/hle/service/ipc_helpers.h" | ||
| 10 | #include "core/hle/service/service.h" | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | |||
| 14 | // clang-format off | ||
| 15 | struct RequestLayout { | ||
| 16 | u32 copy_handle_count; | ||
| 17 | u32 move_handle_count; | ||
| 18 | u32 cmif_raw_data_size; | ||
| 19 | u32 domain_interface_count; | ||
| 20 | }; | ||
| 21 | |||
| 22 | template <ArgumentType Type1, ArgumentType Type2, typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0> | ||
| 23 | constexpr u32 GetArgumentRawDataSize() { | ||
| 24 | if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) { | ||
| 25 | return static_cast<u32>(DataOffset); | ||
| 26 | } else { | ||
| 27 | using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; | ||
| 28 | |||
| 29 | if constexpr (ArgumentTraits<ArgType>::Type == Type1 || ArgumentTraits<ArgType>::Type == Type2) { | ||
| 30 | constexpr size_t ArgAlign = alignof(ArgType); | ||
| 31 | constexpr size_t ArgSize = sizeof(ArgType); | ||
| 32 | |||
| 33 | static_assert(PrevAlign <= ArgAlign, "Input argument is not ordered by alignment"); | ||
| 34 | |||
| 35 | constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); | ||
| 36 | constexpr size_t ArgEnd = ArgOffset + ArgSize; | ||
| 37 | |||
| 38 | return GetArgumentRawDataSize<Type1, Type2, MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>(); | ||
| 39 | } else { | ||
| 40 | return GetArgumentRawDataSize<Type1, Type2, MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>(); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | template <ArgumentType DataType, typename MethodArguments, size_t ArgCount = 0, size_t ArgIndex = 0> | ||
| 46 | constexpr u32 GetArgumentTypeCount() { | ||
| 47 | if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) { | ||
| 48 | return static_cast<u32>(ArgCount); | ||
| 49 | } else { | ||
| 50 | using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; | ||
| 51 | |||
| 52 | if constexpr (ArgumentTraits<ArgType>::Type == DataType) { | ||
| 53 | return GetArgumentTypeCount<DataType, MethodArguments, ArgCount + 1, ArgIndex + 1>(); | ||
| 54 | } else { | ||
| 55 | return GetArgumentTypeCount<DataType, MethodArguments, ArgCount, ArgIndex + 1>(); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | template <typename MethodArguments> | ||
| 61 | constexpr RequestLayout GetNonDomainReplyInLayout() { | ||
| 62 | return RequestLayout{ | ||
| 63 | .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), | ||
| 64 | .move_handle_count = 0, | ||
| 65 | .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), | ||
| 66 | .domain_interface_count = 0, | ||
| 67 | }; | ||
| 68 | } | ||
| 69 | |||
| 70 | template <typename MethodArguments> | ||
| 71 | constexpr RequestLayout GetDomainReplyInLayout() { | ||
| 72 | return RequestLayout{ | ||
| 73 | .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), | ||
| 74 | .move_handle_count = 0, | ||
| 75 | .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), | ||
| 76 | .domain_interface_count = GetArgumentTypeCount<ArgumentType::InInterface, MethodArguments>(), | ||
| 77 | }; | ||
| 78 | } | ||
| 79 | |||
| 80 | template <typename MethodArguments> | ||
| 81 | constexpr RequestLayout GetNonDomainReplyOutLayout() { | ||
| 82 | return RequestLayout{ | ||
| 83 | .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), | ||
| 84 | .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>() + GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), | ||
| 85 | .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), | ||
| 86 | .domain_interface_count = 0, | ||
| 87 | }; | ||
| 88 | } | ||
| 89 | |||
| 90 | template <typename MethodArguments> | ||
| 91 | constexpr RequestLayout GetDomainReplyOutLayout() { | ||
| 92 | return RequestLayout{ | ||
| 93 | .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), | ||
| 94 | .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>(), | ||
| 95 | .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), | ||
| 96 | .domain_interface_count = GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), | ||
| 97 | }; | ||
| 98 | } | ||
| 99 | |||
| 100 | template <bool Domain, typename MethodArguments> | ||
| 101 | constexpr RequestLayout GetReplyInLayout() { | ||
| 102 | return Domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>(); | ||
| 103 | } | ||
| 104 | |||
| 105 | template <bool Domain, typename MethodArguments> | ||
| 106 | constexpr RequestLayout GetReplyOutLayout() { | ||
| 107 | return Domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>(); | ||
| 108 | } | ||
| 109 | |||
| 110 | using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>; | ||
| 111 | |||
| 112 | template <bool Domain, typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t HandleIndex = 0, size_t InBufferIndex = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> | ||
| 113 | void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { | ||
| 114 | if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { | ||
| 115 | return; | ||
| 116 | } else { | ||
| 117 | using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; | ||
| 118 | |||
| 119 | if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InData || ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) { | ||
| 120 | constexpr size_t ArgAlign = alignof(ArgType); | ||
| 121 | constexpr size_t ArgSize = sizeof(ArgType); | ||
| 122 | |||
| 123 | static_assert(PrevAlign <= ArgAlign, "Input argument is not ordered by alignment"); | ||
| 124 | static_assert(!RawDataFinished, "All input interface arguments must appear after raw data"); | ||
| 125 | |||
| 126 | constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); | ||
| 127 | constexpr size_t ArgEnd = ArgOffset + ArgSize; | ||
| 128 | |||
| 129 | if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) { | ||
| 130 | // TODO: abort parsing if PID is not provided? | ||
| 131 | // TODO: validate against raw data value? | ||
| 132 | std::get<ArgIndex>(args).pid = ctx.GetPID(); | ||
| 133 | } else { | ||
| 134 | std::memcpy(&std::get<ArgIndex>(args), raw_data + ArgOffset, ArgSize); | ||
| 135 | } | ||
| 136 | |||
| 137 | return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 138 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InInterface) { | ||
| 139 | constexpr size_t ArgAlign = alignof(u32); | ||
| 140 | constexpr size_t ArgSize = sizeof(u32); | ||
| 141 | constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); | ||
| 142 | constexpr size_t ArgEnd = ArgOffset + ArgSize; | ||
| 143 | |||
| 144 | static_assert(Domain); | ||
| 145 | ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0); | ||
| 146 | |||
| 147 | u32 value{}; | ||
| 148 | std::memcpy(&value, raw_data + ArgOffset, ArgSize); | ||
| 149 | std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1); | ||
| 150 | |||
| 151 | return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 152 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) { | ||
| 153 | std::get<ArgIndex>(args) = std::move(ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex))); | ||
| 154 | |||
| 155 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 156 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { | ||
| 157 | constexpr size_t BufferSize = sizeof(ArgType); | ||
| 158 | |||
| 159 | // Clear the existing data. | ||
| 160 | std::memset(&std::get<ArgIndex>(args), 0, BufferSize); | ||
| 161 | |||
| 162 | std::span<const u8> buffer{}; | ||
| 163 | |||
| 164 | ASSERT(ctx.CanReadBuffer(InBufferIndex)); | ||
| 165 | if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { | ||
| 166 | buffer = ctx.ReadBuffer(InBufferIndex); | ||
| 167 | } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { | ||
| 168 | buffer = ctx.ReadBufferA(InBufferIndex); | ||
| 169 | } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ { | ||
| 170 | buffer = ctx.ReadBufferX(InBufferIndex); | ||
| 171 | } | ||
| 172 | |||
| 173 | std::memcpy(&std::get<ArgIndex>(args), buffer.data(), std::min(BufferSize, buffer.size())); | ||
| 174 | |||
| 175 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 176 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InBuffer) { | ||
| 177 | using ElementType = typename ArgType::Type; | ||
| 178 | |||
| 179 | std::span<const u8> buffer{}; | ||
| 180 | |||
| 181 | if (ctx.CanReadBuffer(InBufferIndex)) { | ||
| 182 | if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { | ||
| 183 | buffer = ctx.ReadBuffer(InBufferIndex); | ||
| 184 | } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { | ||
| 185 | buffer = ctx.ReadBufferA(InBufferIndex); | ||
| 186 | } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ { | ||
| 187 | buffer = ctx.ReadBufferX(InBufferIndex); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | ElementType* ptr = (ElementType*) buffer.data(); | ||
| 192 | size_t size = buffer.size() / sizeof(ElementType); | ||
| 193 | |||
| 194 | std::get<ArgIndex>(args) = std::span(ptr, size); | ||
| 195 | |||
| 196 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 197 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { | ||
| 198 | constexpr size_t BufferSize = sizeof(ArgType); | ||
| 199 | |||
| 200 | // Clear the existing data. | ||
| 201 | std::memset(&std::get<ArgIndex>(args), 0, BufferSize); | ||
| 202 | |||
| 203 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 204 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { | ||
| 205 | using ElementType = typename ArgType::Type; | ||
| 206 | |||
| 207 | // Set up scratch buffer. | ||
| 208 | auto& buffer = temp[OutBufferIndex]; | ||
| 209 | if (ctx.CanWriteBuffer(OutBufferIndex)) { | ||
| 210 | buffer.resize_destructive(ctx.GetWriteBufferSize(OutBufferIndex)); | ||
| 211 | } else { | ||
| 212 | buffer.resize_destructive(0); | ||
| 213 | } | ||
| 214 | |||
| 215 | ElementType* ptr = (ElementType*) buffer.data(); | ||
| 216 | size_t size = buffer.size() / sizeof(ElementType); | ||
| 217 | |||
| 218 | std::get<ArgIndex>(args) = std::span(ptr, size); | ||
| 219 | |||
| 220 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 221 | } else { | ||
| 222 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | template <bool Domain, typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> | ||
| 228 | void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { | ||
| 229 | if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { | ||
| 230 | return; | ||
| 231 | } else { | ||
| 232 | using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; | ||
| 233 | |||
| 234 | if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) { | ||
| 235 | constexpr size_t ArgAlign = alignof(ArgType); | ||
| 236 | constexpr size_t ArgSize = sizeof(ArgType); | ||
| 237 | |||
| 238 | static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment"); | ||
| 239 | static_assert(!RawDataFinished, "All output interface arguments must appear after raw data"); | ||
| 240 | |||
| 241 | constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); | ||
| 242 | constexpr size_t ArgEnd = ArgOffset + ArgSize; | ||
| 243 | |||
| 244 | std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize); | ||
| 245 | |||
| 246 | return WriteOutArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 247 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) { | ||
| 248 | if constexpr (Domain) { | ||
| 249 | ctx.AddDomainObject(std::get<ArgIndex>(args)); | ||
| 250 | } else { | ||
| 251 | ctx.AddMoveInterface(std::get<ArgIndex>(args)); | ||
| 252 | } | ||
| 253 | |||
| 254 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 255 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) { | ||
| 256 | ctx.AddCopyObject(std::get<ArgIndex>(args).GetPointerUnsafe()); | ||
| 257 | |||
| 258 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 259 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) { | ||
| 260 | ctx.AddMoveObject(std::get<ArgIndex>(args).GetPointerUnsafe()); | ||
| 261 | |||
| 262 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 263 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { | ||
| 264 | constexpr size_t BufferSize = sizeof(ArgType); | ||
| 265 | |||
| 266 | ASSERT(ctx.CanWriteBuffer(OutBufferIndex)); | ||
| 267 | if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { | ||
| 268 | ctx.WriteBuffer(std::get<ArgIndex>(args), OutBufferIndex); | ||
| 269 | } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { | ||
| 270 | ctx.WriteBufferB(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex); | ||
| 271 | } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ { | ||
| 272 | ctx.WriteBufferC(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex); | ||
| 273 | } | ||
| 274 | |||
| 275 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 276 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { | ||
| 277 | auto& buffer = temp[OutBufferIndex]; | ||
| 278 | const size_t size = buffer.size(); | ||
| 279 | |||
| 280 | if (ctx.CanWriteBuffer(OutBufferIndex)) { | ||
| 281 | if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { | ||
| 282 | ctx.WriteBuffer(buffer.data(), size, OutBufferIndex); | ||
| 283 | } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { | ||
| 284 | ctx.WriteBufferB(buffer.data(), size, OutBufferIndex); | ||
| 285 | } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ { | ||
| 286 | ctx.WriteBufferC(buffer.data(), size, OutBufferIndex); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>( args, raw_data, ctx, temp); | ||
| 291 | } else { | ||
| 292 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | template <bool Domain, typename T, typename... A> | ||
| 298 | void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { | ||
| 299 | // Verify domain state. | ||
| 300 | if constexpr (Domain) { | ||
| 301 | ASSERT_MSG(ctx.GetManager()->IsDomain(), "Domain reply used on non-domain session"); | ||
| 302 | } else { | ||
| 303 | ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Non-domain reply used on domain session"); | ||
| 304 | } | ||
| 305 | |||
| 306 | using MethodArguments = std::tuple<std::remove_reference_t<A>...>; | ||
| 307 | |||
| 308 | OutTemporaryBuffers buffers{}; | ||
| 309 | auto call_arguments = std::tuple<typename RemoveOut<A>::Type...>(); | ||
| 310 | |||
| 311 | // Read inputs. | ||
| 312 | const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2; | ||
| 313 | ReadInArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers); | ||
| 314 | |||
| 315 | // Call. | ||
| 316 | const auto Callable = [&]<typename... CallArgs>(CallArgs&... args) { | ||
| 317 | return (t.*f)(args...); | ||
| 318 | }; | ||
| 319 | const Result res = std::apply(Callable, call_arguments); | ||
| 320 | |||
| 321 | // Write result. | ||
| 322 | constexpr RequestLayout layout = GetReplyOutLayout<Domain, MethodArguments>(); | ||
| 323 | IPC::ResponseBuilder rb{ctx, 2 + Common::DivCeil(layout.cmif_raw_data_size, sizeof(u32)), layout.copy_handle_count, layout.move_handle_count + layout.domain_interface_count}; | ||
| 324 | rb.Push(res); | ||
| 325 | |||
| 326 | // Write out arguments. | ||
| 327 | WriteOutArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers); | ||
| 328 | } | ||
| 329 | // clang-format on | ||
| 330 | |||
| 331 | template <typename Self> | ||
| 332 | template <bool Domain, auto F> | ||
| 333 | inline void ServiceFramework<Self>::CmifReplyWrap(HLERequestContext& ctx) { | ||
| 334 | return CmifReplyWrapImpl<Domain>(ctx, *static_cast<Self*>(this), F); | ||
| 335 | } | ||
| 336 | |||
| 337 | } // namespace Service | ||
diff --git a/src/core/hle/service/cmif_types.h b/src/core/hle/service/cmif_types.h new file mode 100644 index 000000000..b80028c19 --- /dev/null +++ b/src/core/hle/service/cmif_types.h | |||
| @@ -0,0 +1,234 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <memory> | ||
| 7 | |||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/service/hle_ipc.h" | ||
| 11 | |||
| 12 | namespace Service { | ||
| 13 | |||
| 14 | // clang-format off | ||
| 15 | template <typename T> | ||
| 16 | class Out { | ||
| 17 | public: | ||
| 18 | /* implicit */ Out(T& t) : raw(&t) {} | ||
| 19 | ~Out() = default; | ||
| 20 | |||
| 21 | T* Get() const { | ||
| 22 | return raw; | ||
| 23 | } | ||
| 24 | |||
| 25 | T& operator*() { | ||
| 26 | return *raw; | ||
| 27 | } | ||
| 28 | |||
| 29 | private: | ||
| 30 | T* raw; | ||
| 31 | }; | ||
| 32 | |||
| 33 | template <typename T> | ||
| 34 | using SharedPointer = std::shared_ptr<T>; | ||
| 35 | |||
| 36 | struct ClientProcessId { | ||
| 37 | explicit operator bool() const { | ||
| 38 | return pid != 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | const u64& operator*() const { | ||
| 42 | return pid; | ||
| 43 | } | ||
| 44 | |||
| 45 | u64 pid; | ||
| 46 | }; | ||
| 47 | |||
| 48 | using ClientAppletResourceUserId = ClientProcessId; | ||
| 49 | |||
| 50 | template <typename T> | ||
| 51 | class InCopyHandle : public Kernel::KScopedAutoObject<T> { | ||
| 52 | public: | ||
| 53 | using Type = T; | ||
| 54 | |||
| 55 | template <typename... Args> | ||
| 56 | /* implicit */ InCopyHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {} | ||
| 57 | ~InCopyHandle() = default; | ||
| 58 | |||
| 59 | InCopyHandle& operator=(InCopyHandle&& rhs) { | ||
| 60 | Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); | ||
| 61 | return *this; | ||
| 62 | } | ||
| 63 | }; | ||
| 64 | |||
| 65 | template <typename T> | ||
| 66 | class OutCopyHandle : public Kernel::KScopedAutoObject<T> { | ||
| 67 | public: | ||
| 68 | using Type = T; | ||
| 69 | |||
| 70 | template <typename... Args> | ||
| 71 | /* implicit */ OutCopyHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {} | ||
| 72 | ~OutCopyHandle() = default; | ||
| 73 | |||
| 74 | OutCopyHandle& operator=(OutCopyHandle&& rhs) { | ||
| 75 | Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); | ||
| 76 | return *this; | ||
| 77 | } | ||
| 78 | }; | ||
| 79 | |||
| 80 | template <typename T> | ||
| 81 | class OutMoveHandle : public Kernel::KScopedAutoObject<T> { | ||
| 82 | public: | ||
| 83 | using Type = T; | ||
| 84 | |||
| 85 | template <typename... Args> | ||
| 86 | /* implicit */ OutMoveHandle(Args&&... args) : Kernel::KScopedAutoObject<T>(std::forward<Args...>(args)...) {} | ||
| 87 | ~OutMoveHandle() = default; | ||
| 88 | |||
| 89 | OutMoveHandle& operator=(OutMoveHandle&& rhs) { | ||
| 90 | Kernel::KScopedAutoObject<T>::operator=(std::move(rhs)); | ||
| 91 | return *this; | ||
| 92 | } | ||
| 93 | }; | ||
| 94 | |||
| 95 | enum BufferAttr : int { | ||
| 96 | BufferAttr_In = (1U << 0), | ||
| 97 | BufferAttr_Out = (1U << 1), | ||
| 98 | BufferAttr_HipcMapAlias = (1U << 2), | ||
| 99 | BufferAttr_HipcPointer = (1U << 3), | ||
| 100 | BufferAttr_FixedSize = (1U << 4), | ||
| 101 | BufferAttr_HipcAutoSelect = (1U << 5), | ||
| 102 | BufferAttr_HipcMapTransferAllowsNonSecure = (1U << 6), | ||
| 103 | BufferAttr_HipcMapTransferAllowsNonDevice = (1U << 7), | ||
| 104 | }; | ||
| 105 | |||
| 106 | template <typename T, int A> | ||
| 107 | struct Buffer : public std::span<T> { | ||
| 108 | static_assert(std::is_trivial_v<T>, "Buffer type must be trivial"); | ||
| 109 | static_assert((A & BufferAttr_FixedSize) == 0, "Buffer attr must not contain FixedSize"); | ||
| 110 | static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "Buffer attr must be In or Out"); | ||
| 111 | static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); | ||
| 112 | using Type = T; | ||
| 113 | |||
| 114 | Buffer& operator=(const std::span<T>& rhs) { | ||
| 115 | std::span<T>::operator=(rhs); | ||
| 116 | return *this; | ||
| 117 | } | ||
| 118 | |||
| 119 | T& operator*() const { | ||
| 120 | return *this->data(); | ||
| 121 | } | ||
| 122 | |||
| 123 | explicit operator bool() const { | ||
| 124 | return this->size() > 0; | ||
| 125 | } | ||
| 126 | }; | ||
| 127 | |||
| 128 | template <BufferAttr A> | ||
| 129 | using InBuffer = Buffer<const u8, BufferAttr_In | A>; | ||
| 130 | |||
| 131 | template <typename T, BufferAttr A> | ||
| 132 | using InArray = Buffer<T, BufferAttr_In | A>; | ||
| 133 | |||
| 134 | template <BufferAttr A> | ||
| 135 | using OutBuffer = Buffer<u8, BufferAttr_Out | A>; | ||
| 136 | |||
| 137 | template <typename T, BufferAttr A> | ||
| 138 | using OutArray = Buffer<T, BufferAttr_Out | A>; | ||
| 139 | |||
| 140 | template <typename T, int A> | ||
| 141 | struct LargeData : public T { | ||
| 142 | static_assert(std::is_trivial_v<T>, "LargeData type must be trivial"); | ||
| 143 | static_assert((A & BufferAttr_FixedSize) != 0, "LargeData attr must contain FixedSize"); | ||
| 144 | static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "LargeData attr must be In or Out"); | ||
| 145 | static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); | ||
| 146 | using Type = T; | ||
| 147 | }; | ||
| 148 | |||
| 149 | template <typename T, BufferAttr A> | ||
| 150 | using InLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_In | A>; | ||
| 151 | |||
| 152 | template <typename T, BufferAttr A> | ||
| 153 | using OutLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_Out | A>; | ||
| 154 | |||
| 155 | template <typename T> | ||
| 156 | struct RemoveOut { | ||
| 157 | using Type = std::remove_reference_t<T>; | ||
| 158 | }; | ||
| 159 | |||
| 160 | template <typename T> | ||
| 161 | struct RemoveOut<Out<T>> { | ||
| 162 | using Type = T; | ||
| 163 | }; | ||
| 164 | |||
| 165 | enum class ArgumentType { | ||
| 166 | InProcessId, | ||
| 167 | InData, | ||
| 168 | InInterface, | ||
| 169 | InCopyHandle, | ||
| 170 | OutData, | ||
| 171 | OutInterface, | ||
| 172 | OutCopyHandle, | ||
| 173 | OutMoveHandle, | ||
| 174 | InBuffer, | ||
| 175 | InLargeData, | ||
| 176 | OutBuffer, | ||
| 177 | OutLargeData, | ||
| 178 | }; | ||
| 179 | |||
| 180 | template <typename T> | ||
| 181 | struct ArgumentTraits; | ||
| 182 | |||
| 183 | template <> | ||
| 184 | struct ArgumentTraits<ClientProcessId> { | ||
| 185 | static constexpr ArgumentType Type = ArgumentType::InProcessId; | ||
| 186 | }; | ||
| 187 | |||
| 188 | template <typename T> | ||
| 189 | struct ArgumentTraits<SharedPointer<T>> { | ||
| 190 | static constexpr ArgumentType Type = ArgumentType::InInterface; | ||
| 191 | }; | ||
| 192 | |||
| 193 | template <typename T> | ||
| 194 | struct ArgumentTraits<InCopyHandle<T>> { | ||
| 195 | static constexpr ArgumentType Type = ArgumentType::InCopyHandle; | ||
| 196 | }; | ||
| 197 | |||
| 198 | template <typename T> | ||
| 199 | struct ArgumentTraits<Out<SharedPointer<T>>> { | ||
| 200 | static constexpr ArgumentType Type = ArgumentType::OutInterface; | ||
| 201 | }; | ||
| 202 | |||
| 203 | template <typename T> | ||
| 204 | struct ArgumentTraits<Out<T>> { | ||
| 205 | static constexpr ArgumentType Type = ArgumentType::OutData; | ||
| 206 | }; | ||
| 207 | |||
| 208 | template <typename T> | ||
| 209 | struct ArgumentTraits<OutCopyHandle<T>> { | ||
| 210 | static constexpr ArgumentType Type = ArgumentType::OutCopyHandle; | ||
| 211 | }; | ||
| 212 | |||
| 213 | template <typename T> | ||
| 214 | struct ArgumentTraits<OutMoveHandle<T>> { | ||
| 215 | static constexpr ArgumentType Type = ArgumentType::OutMoveHandle; | ||
| 216 | }; | ||
| 217 | |||
| 218 | template <typename T, int A> | ||
| 219 | struct ArgumentTraits<Buffer<T, A>> { | ||
| 220 | static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutBuffer : ArgumentType::InBuffer; | ||
| 221 | }; | ||
| 222 | |||
| 223 | template <typename T, int A> | ||
| 224 | struct ArgumentTraits<LargeData<T, A>> { | ||
| 225 | static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutLargeData : ArgumentType::InLargeData; | ||
| 226 | }; | ||
| 227 | |||
| 228 | template <typename T> | ||
| 229 | struct ArgumentTraits { | ||
| 230 | static constexpr ArgumentType Type = ArgumentType::InData; | ||
| 231 | }; | ||
| 232 | // clang-format on | ||
| 233 | |||
| 234 | } // namespace Service | ||
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index e491dd260..50e1ed756 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp | |||
| @@ -501,6 +501,22 @@ bool HLERequestContext::CanWriteBuffer(std::size_t buffer_index) const { | |||
| 501 | } | 501 | } |
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | void HLERequestContext::AddMoveInterface(SessionRequestHandlerPtr s) { | ||
| 505 | ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve( | ||
| 506 | Kernel::LimitableResource::SessionCountMax, 1)); | ||
| 507 | |||
| 508 | auto* session = Kernel::KSession::Create(kernel); | ||
| 509 | session->Initialize(nullptr, 0); | ||
| 510 | Kernel::KSession::Register(kernel, session); | ||
| 511 | |||
| 512 | auto& server = manager.lock()->GetServerManager(); | ||
| 513 | auto next_manager = std::make_shared<Service::SessionRequestManager>(kernel, server); | ||
| 514 | next_manager->SetSessionHandler(std::move(s)); | ||
| 515 | server.RegisterSession(&session->GetServerSession(), next_manager); | ||
| 516 | |||
| 517 | AddMoveObject(&session->GetClientSession()); | ||
| 518 | } | ||
| 519 | |||
| 504 | std::string HLERequestContext::Description() const { | 520 | std::string HLERequestContext::Description() const { |
| 505 | if (!command_header) { | 521 | if (!command_header) { |
| 506 | return "No command header available"; | 522 | return "No command header available"; |
diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index 8329d7265..c2e0e5e8c 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h | |||
| @@ -339,6 +339,8 @@ public: | |||
| 339 | outgoing_move_objects.emplace_back(object); | 339 | outgoing_move_objects.emplace_back(object); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | void AddMoveInterface(SessionRequestHandlerPtr s); | ||
| 343 | |||
| 342 | void AddCopyObject(Kernel::KAutoObject* object) { | 344 | void AddCopyObject(Kernel::KAutoObject* object) { |
| 343 | outgoing_copy_objects.emplace_back(object); | 345 | outgoing_copy_objects.emplace_back(object); |
| 344 | } | 346 | } |
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index 77aa6d7d1..d8fefff89 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp | |||
| @@ -6,12 +6,12 @@ | |||
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/kernel/k_transfer_memory.h" | 7 | #include "core/hle/kernel/k_transfer_memory.h" |
| 8 | #include "core/hle/result.h" | 8 | #include "core/hle/result.h" |
| 9 | #include "core/hle/service/cmif_serialization.h" | ||
| 9 | #include "core/hle/service/ipc_helpers.h" | 10 | #include "core/hle/service/ipc_helpers.h" |
| 10 | #include "core/hle/service/jit/jit.h" | 11 | #include "core/hle/service/jit/jit.h" |
| 11 | #include "core/hle/service/jit/jit_code_memory.h" | 12 | #include "core/hle/service/jit/jit_code_memory.h" |
| 12 | #include "core/hle/service/jit/jit_context.h" | 13 | #include "core/hle/service/jit/jit_context.h" |
| 13 | #include "core/hle/service/server_manager.h" | 14 | #include "core/hle/service/server_manager.h" |
| 14 | #include "core/hle/service/service.h" | ||
| 15 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 16 | 16 | ||
| 17 | namespace Service::JIT { | 17 | namespace Service::JIT { |
| @@ -21,6 +21,9 @@ struct CodeRange { | |||
| 21 | u64 size; | 21 | u64 size; |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | using Struct32 = std::array<u64, 4>; | ||
| 25 | static_assert(sizeof(Struct32) == 32, "Struct32 has wrong size"); | ||
| 26 | |||
| 24 | class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { | 27 | class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { |
| 25 | public: | 28 | public: |
| 26 | explicit IJitEnvironment(Core::System& system_, | 29 | explicit IJitEnvironment(Core::System& system_, |
| @@ -29,12 +32,13 @@ public: | |||
| 29 | : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, | 32 | : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, |
| 30 | user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, | 33 | user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, |
| 31 | context{system_.ApplicationMemory()} { | 34 | context{system_.ApplicationMemory()} { |
| 35 | |||
| 32 | // clang-format off | 36 | // clang-format off |
| 33 | static const FunctionInfo functions[] = { | 37 | static const FunctionInfo functions[] = { |
| 34 | {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, | 38 | {0, C<&IJitEnvironment::GenerateCode>, "GenerateCode"}, |
| 35 | {1, &IJitEnvironment::Control, "Control"}, | 39 | {1, C<&IJitEnvironment::Control>, "Control"}, |
| 36 | {1000, &IJitEnvironment::LoadPlugin, "LoadPlugin"}, | 40 | {1000, C<&IJitEnvironment::LoadPlugin>, "LoadPlugin"}, |
| 37 | {1001, &IJitEnvironment::GetCodeAddress, "GetCodeAddress"}, | 41 | {1001, C<&IJitEnvironment::GetCodeAddress>, "GetCodeAddress"}, |
| 38 | }; | 42 | }; |
| 39 | // clang-format on | 43 | // clang-format on |
| 40 | 44 | ||
| @@ -50,28 +54,10 @@ public: | |||
| 50 | configuration.sys_ro_memory = configuration.user_ro_memory; | 54 | configuration.sys_ro_memory = configuration.user_ro_memory; |
| 51 | } | 55 | } |
| 52 | 56 | ||
| 53 | void GenerateCode(HLERequestContext& ctx) { | 57 | Result GenerateCode(Out<s32> out_return_value, Out<CodeRange> out_range0, |
| 54 | LOG_DEBUG(Service_JIT, "called"); | 58 | Out<CodeRange> out_range1, OutBuffer<BufferAttr_HipcMapAlias> out_buffer, |
| 55 | 59 | u32 data_size, u64 command, CodeRange range0, CodeRange range1, | |
| 56 | struct InputParameters { | 60 | Struct32 data, InBuffer<BufferAttr_HipcMapAlias> buffer) { |
| 57 | u32 data_size; | ||
| 58 | u64 command; | ||
| 59 | std::array<CodeRange, 2> ranges; | ||
| 60 | Struct32 data; | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct OutputParameters { | ||
| 64 | s32 return_value; | ||
| 65 | std::array<CodeRange, 2> ranges; | ||
| 66 | }; | ||
| 67 | |||
| 68 | IPC::RequestParser rp{ctx}; | ||
| 69 | const auto parameters{rp.PopRaw<InputParameters>()}; | ||
| 70 | |||
| 71 | // Optional input/output buffers | ||
| 72 | const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()}; | ||
| 73 | std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); | ||
| 74 | |||
| 75 | // Function call prototype: | 61 | // Function call prototype: |
| 76 | // void GenerateCode(s32* ret, CodeRange* c0_out, CodeRange* c1_out, JITConfiguration* cfg, | 62 | // void GenerateCode(s32* ret, CodeRange* c0_out, CodeRange* c1_out, JITConfiguration* cfg, |
| 77 | // u64 cmd, u8* input_buf, size_t input_size, CodeRange* c0_in, | 63 | // u64 cmd, u8* input_buf, size_t input_size, CodeRange* c0_in, |
| @@ -83,66 +69,36 @@ public: | |||
| 83 | // other arguments are used to transfer state between the game and the plugin. | 69 | // other arguments are used to transfer state between the game and the plugin. |
| 84 | 70 | ||
| 85 | const VAddr ret_ptr{context.AddHeap(0u)}; | 71 | const VAddr ret_ptr{context.AddHeap(0u)}; |
| 86 | const VAddr c0_in_ptr{context.AddHeap(parameters.ranges[0])}; | 72 | const VAddr c0_in_ptr{context.AddHeap(range0)}; |
| 87 | const VAddr c1_in_ptr{context.AddHeap(parameters.ranges[1])}; | 73 | const VAddr c1_in_ptr{context.AddHeap(range1)}; |
| 88 | const VAddr c0_out_ptr{context.AddHeap(ClearSize(parameters.ranges[0]))}; | 74 | const VAddr c0_out_ptr{context.AddHeap(ClearSize(range0))}; |
| 89 | const VAddr c1_out_ptr{context.AddHeap(ClearSize(parameters.ranges[1]))}; | 75 | const VAddr c1_out_ptr{context.AddHeap(ClearSize(range1))}; |
| 90 | 76 | ||
| 91 | const VAddr input_ptr{context.AddHeap(input_buffer.data(), input_buffer.size())}; | 77 | const VAddr input_ptr{context.AddHeap(buffer.data(), buffer.size())}; |
| 92 | const VAddr output_ptr{context.AddHeap(output_buffer.data(), output_buffer.size())}; | 78 | const VAddr output_ptr{context.AddHeap(out_buffer.data(), out_buffer.size())}; |
| 93 | const VAddr data_ptr{context.AddHeap(parameters.data)}; | 79 | const VAddr data_ptr{context.AddHeap(data)}; |
| 94 | const VAddr configuration_ptr{context.AddHeap(configuration)}; | 80 | const VAddr configuration_ptr{context.AddHeap(configuration)}; |
| 95 | 81 | ||
| 96 | // The callback does not directly return a value, it only writes to the output pointer | 82 | // The callback does not directly return a value, it only writes to the output pointer |
| 97 | context.CallFunction(callbacks.GenerateCode, ret_ptr, c0_out_ptr, c1_out_ptr, | 83 | context.CallFunction(callbacks.GenerateCode, ret_ptr, c0_out_ptr, c1_out_ptr, |
| 98 | configuration_ptr, parameters.command, input_ptr, input_buffer.size(), | 84 | configuration_ptr, command, input_ptr, buffer.size(), c0_in_ptr, |
| 99 | c0_in_ptr, c1_in_ptr, data_ptr, parameters.data_size, output_ptr, | 85 | c1_in_ptr, data_ptr, data_size, output_ptr, out_buffer.size()); |
| 100 | output_buffer.size()); | ||
| 101 | |||
| 102 | const s32 return_value{context.GetHeap<s32>(ret_ptr)}; | ||
| 103 | |||
| 104 | if (return_value == 0) { | ||
| 105 | // The callback has written to the output executable code range, | ||
| 106 | // requiring an instruction cache invalidation | ||
| 107 | Core::InvalidateInstructionCacheRange(process.GetPointerUnsafe(), | ||
| 108 | configuration.user_rx_memory.offset, | ||
| 109 | configuration.user_rx_memory.size); | ||
| 110 | |||
| 111 | // Write back to the IPC output buffer, if provided | ||
| 112 | if (ctx.CanWriteBuffer()) { | ||
| 113 | context.GetHeap(output_ptr, output_buffer.data(), output_buffer.size()); | ||
| 114 | ctx.WriteBuffer(output_buffer.data(), output_buffer.size()); | ||
| 115 | } | ||
| 116 | |||
| 117 | const OutputParameters out{ | ||
| 118 | .return_value = return_value, | ||
| 119 | .ranges = | ||
| 120 | { | ||
| 121 | context.GetHeap<CodeRange>(c0_out_ptr), | ||
| 122 | context.GetHeap<CodeRange>(c1_out_ptr), | ||
| 123 | }, | ||
| 124 | }; | ||
| 125 | |||
| 126 | IPC::ResponseBuilder rb{ctx, 8}; | ||
| 127 | rb.Push(ResultSuccess); | ||
| 128 | rb.PushRaw(out); | ||
| 129 | } else { | ||
| 130 | LOG_WARNING(Service_JIT, "plugin GenerateCode callback failed"); | ||
| 131 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 132 | rb.Push(ResultUnknown); | ||
| 133 | } | ||
| 134 | }; | ||
| 135 | 86 | ||
| 136 | void Control(HLERequestContext& ctx) { | 87 | *out_return_value = context.GetHeap<s32>(ret_ptr); |
| 137 | LOG_DEBUG(Service_JIT, "called"); | 88 | *out_range0 = context.GetHeap<CodeRange>(c0_out_ptr); |
| 89 | *out_range1 = context.GetHeap<CodeRange>(c1_out_ptr); | ||
| 90 | context.GetHeap(output_ptr, out_buffer.data(), out_buffer.size()); | ||
| 138 | 91 | ||
| 139 | IPC::RequestParser rp{ctx}; | 92 | if (*out_return_value != 0) { |
| 140 | const auto command{rp.PopRaw<u64>()}; | 93 | LOG_WARNING(Service_JIT, "plugin GenerateCode callback failed"); |
| 94 | R_THROW(ResultUnknown); | ||
| 95 | } | ||
| 141 | 96 | ||
| 142 | // Optional input/output buffers | 97 | R_SUCCEED(); |
| 143 | const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()}; | 98 | } |
| 144 | std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); | ||
| 145 | 99 | ||
| 100 | Result Control(Out<s32> out_return_value, InBuffer<BufferAttr_HipcMapAlias> in_data, | ||
| 101 | OutBuffer<BufferAttr_HipcMapAlias> out_data, u64 command) { | ||
| 146 | // Function call prototype: | 102 | // Function call prototype: |
| 147 | // u64 Control(s32* ret, JITConfiguration* cfg, u64 cmd, u8* input_buf, size_t input_size, | 103 | // u64 Control(s32* ret, JITConfiguration* cfg, u64 cmd, u8* input_buf, size_t input_size, |
| 148 | // u8* output_buf, size_t output_size); | 104 | // u8* output_buf, size_t output_size); |
| @@ -152,53 +108,30 @@ public: | |||
| 152 | 108 | ||
| 153 | const VAddr ret_ptr{context.AddHeap(0u)}; | 109 | const VAddr ret_ptr{context.AddHeap(0u)}; |
| 154 | const VAddr configuration_ptr{context.AddHeap(configuration)}; | 110 | const VAddr configuration_ptr{context.AddHeap(configuration)}; |
| 155 | const VAddr input_ptr{context.AddHeap(input_buffer.data(), input_buffer.size())}; | 111 | const VAddr input_ptr{context.AddHeap(in_data.data(), in_data.size())}; |
| 156 | const VAddr output_ptr{context.AddHeap(output_buffer.data(), output_buffer.size())}; | 112 | const VAddr output_ptr{context.AddHeap(out_data.data(), out_data.size())}; |
| 157 | 113 | ||
| 158 | const u64 wrapper_value{context.CallFunction(callbacks.Control, ret_ptr, configuration_ptr, | 114 | const u64 wrapper_value{context.CallFunction(callbacks.Control, ret_ptr, configuration_ptr, |
| 159 | command, input_ptr, input_buffer.size(), | 115 | command, input_ptr, in_data.size(), output_ptr, |
| 160 | output_ptr, output_buffer.size())}; | 116 | out_data.size())}; |
| 161 | |||
| 162 | const s32 return_value{context.GetHeap<s32>(ret_ptr)}; | ||
| 163 | |||
| 164 | if (wrapper_value == 0 && return_value == 0) { | ||
| 165 | // Write back to the IPC output buffer, if provided | ||
| 166 | if (ctx.CanWriteBuffer()) { | ||
| 167 | context.GetHeap(output_ptr, output_buffer.data(), output_buffer.size()); | ||
| 168 | ctx.WriteBuffer(output_buffer.data(), output_buffer.size()); | ||
| 169 | } | ||
| 170 | |||
| 171 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 172 | rb.Push(ResultSuccess); | ||
| 173 | rb.Push(return_value); | ||
| 174 | } else { | ||
| 175 | LOG_WARNING(Service_JIT, "plugin Control callback failed"); | ||
| 176 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 177 | rb.Push(ResultUnknown); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | void LoadPlugin(HLERequestContext& ctx) { | ||
| 182 | LOG_DEBUG(Service_JIT, "called"); | ||
| 183 | 117 | ||
| 184 | IPC::RequestParser rp{ctx}; | 118 | *out_return_value = context.GetHeap<s32>(ret_ptr); |
| 185 | const auto tmem_size{rp.PopRaw<u64>()}; | 119 | context.GetHeap(output_ptr, out_data.data(), out_data.size()); |
| 186 | const auto tmem_handle{ctx.GetCopyHandle(0)}; | ||
| 187 | const auto nro_plugin{ctx.ReadBuffer(1)}; | ||
| 188 | 120 | ||
| 189 | if (tmem_size == 0) { | 121 | if (wrapper_value == 0 && *out_return_value == 0) { |
| 190 | LOG_ERROR(Service_JIT, "attempted to load plugin with empty transfer memory"); | 122 | R_SUCCEED(); |
| 191 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 192 | rb.Push(ResultUnknown); | ||
| 193 | return; | ||
| 194 | } | 123 | } |
| 195 | 124 | ||
| 196 | auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)}; | 125 | LOG_WARNING(Service_JIT, "plugin Control callback failed"); |
| 126 | R_THROW(ResultUnknown); | ||
| 127 | } | ||
| 128 | |||
| 129 | Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory>& tmem, | ||
| 130 | InBuffer<BufferAttr_HipcMapAlias> nrr, | ||
| 131 | InBuffer<BufferAttr_HipcMapAlias> nro) { | ||
| 197 | if (tmem.IsNull()) { | 132 | if (tmem.IsNull()) { |
| 198 | LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); | 133 | LOG_ERROR(Service_JIT, "Invalid transfer memory handle!"); |
| 199 | IPC::ResponseBuilder rb{ctx, 2}; | 134 | R_THROW(ResultUnknown); |
| 200 | rb.Push(ResultUnknown); | ||
| 201 | return; | ||
| 202 | } | 135 | } |
| 203 | 136 | ||
| 204 | // Set up the configuration with the required TransferMemory address | 137 | // Set up the configuration with the required TransferMemory address |
| @@ -206,7 +139,7 @@ public: | |||
| 206 | configuration.transfer_memory.size = tmem_size; | 139 | configuration.transfer_memory.size = tmem_size; |
| 207 | 140 | ||
| 208 | // Gather up all the callbacks from the loaded plugin | 141 | // Gather up all the callbacks from the loaded plugin |
| 209 | auto symbols{Core::Symbols::GetSymbols(nro_plugin, true)}; | 142 | auto symbols{Core::Symbols::GetSymbols(nro, true)}; |
| 210 | const auto GetSymbol{[&](const std::string& name) { return symbols[name].first; }}; | 143 | const auto GetSymbol{[&](const std::string& name) { return symbols[name].first; }}; |
| 211 | 144 | ||
| 212 | callbacks.rtld_fini = GetSymbol("_fini"); | 145 | callbacks.rtld_fini = GetSymbol("_fini"); |
| @@ -223,16 +156,12 @@ public: | |||
| 223 | if (callbacks.GetVersion == 0 || callbacks.Configure == 0 || callbacks.GenerateCode == 0 || | 156 | if (callbacks.GetVersion == 0 || callbacks.Configure == 0 || callbacks.GenerateCode == 0 || |
| 224 | callbacks.OnPrepared == 0) { | 157 | callbacks.OnPrepared == 0) { |
| 225 | LOG_ERROR(Service_JIT, "plugin does not implement all necessary functionality"); | 158 | LOG_ERROR(Service_JIT, "plugin does not implement all necessary functionality"); |
| 226 | IPC::ResponseBuilder rb{ctx, 2}; | 159 | R_THROW(ResultUnknown); |
| 227 | rb.Push(ResultUnknown); | ||
| 228 | return; | ||
| 229 | } | 160 | } |
| 230 | 161 | ||
| 231 | if (!context.LoadNRO(nro_plugin)) { | 162 | if (!context.LoadNRO(nro)) { |
| 232 | LOG_ERROR(Service_JIT, "failed to load plugin"); | 163 | LOG_ERROR(Service_JIT, "failed to load plugin"); |
| 233 | IPC::ResponseBuilder rb{ctx, 2}; | 164 | R_THROW(ResultUnknown); |
| 234 | rb.Push(ResultUnknown); | ||
| 235 | return; | ||
| 236 | } | 165 | } |
| 237 | 166 | ||
| 238 | context.MapProcessMemory(configuration.sys_ro_memory.offset, | 167 | context.MapProcessMemory(configuration.sys_ro_memory.offset, |
| @@ -252,9 +181,7 @@ public: | |||
| 252 | const auto version{context.CallFunction(callbacks.GetVersion)}; | 181 | const auto version{context.CallFunction(callbacks.GetVersion)}; |
| 253 | if (version != 1) { | 182 | if (version != 1) { |
| 254 | LOG_ERROR(Service_JIT, "unknown plugin version {}", version); | 183 | LOG_ERROR(Service_JIT, "unknown plugin version {}", version); |
| 255 | IPC::ResponseBuilder rb{ctx, 2}; | 184 | R_THROW(ResultUnknown); |
| 256 | rb.Push(ResultUnknown); | ||
| 257 | return; | ||
| 258 | } | 185 | } |
| 259 | 186 | ||
| 260 | // Function prototype: | 187 | // Function prototype: |
| @@ -280,22 +207,19 @@ public: | |||
| 280 | const auto configuration_ptr{context.AddHeap(configuration)}; | 207 | const auto configuration_ptr{context.AddHeap(configuration)}; |
| 281 | context.CallFunction(callbacks.OnPrepared, configuration_ptr); | 208 | context.CallFunction(callbacks.OnPrepared, configuration_ptr); |
| 282 | 209 | ||
| 283 | IPC::ResponseBuilder rb{ctx, 2}; | 210 | R_SUCCEED(); |
| 284 | rb.Push(ResultSuccess); | ||
| 285 | } | 211 | } |
| 286 | 212 | ||
| 287 | void GetCodeAddress(HLERequestContext& ctx) { | 213 | Result GetCodeAddress(Out<u64> rx_offset, Out<u64> ro_offset) { |
| 288 | LOG_DEBUG(Service_JIT, "called"); | 214 | LOG_DEBUG(Service_JIT, "called"); |
| 289 | 215 | ||
| 290 | IPC::ResponseBuilder rb{ctx, 6}; | 216 | *rx_offset = configuration.user_rx_memory.offset; |
| 291 | rb.Push(ResultSuccess); | 217 | *ro_offset = configuration.user_ro_memory.offset; |
| 292 | rb.Push(configuration.user_rx_memory.offset); | 218 | |
| 293 | rb.Push(configuration.user_ro_memory.offset); | 219 | R_SUCCEED(); |
| 294 | } | 220 | } |
| 295 | 221 | ||
| 296 | private: | 222 | private: |
| 297 | using Struct32 = std::array<u8, 32>; | ||
| 298 | |||
| 299 | struct GuestCallbacks { | 223 | struct GuestCallbacks { |
| 300 | VAddr rtld_fini; | 224 | VAddr rtld_fini; |
| 301 | VAddr rtld_init; | 225 | VAddr rtld_init; |
| @@ -335,7 +259,7 @@ public: | |||
| 335 | explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} { | 259 | explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} { |
| 336 | // clang-format off | 260 | // clang-format off |
| 337 | static const FunctionInfo functions[] = { | 261 | static const FunctionInfo functions[] = { |
| 338 | {0, &JITU::CreateJitEnvironment, "CreateJitEnvironment"}, | 262 | {0, C<&JITU::CreateJitEnvironment>, "CreateJitEnvironment"}, |
| 339 | }; | 263 | }; |
| 340 | // clang-format on | 264 | // clang-format on |
| 341 | 265 | ||
| @@ -343,76 +267,33 @@ public: | |||
| 343 | } | 267 | } |
| 344 | 268 | ||
| 345 | private: | 269 | private: |
| 346 | void CreateJitEnvironment(HLERequestContext& ctx) { | 270 | Result CreateJitEnvironment(Out<SharedPointer<IJitEnvironment>> out_jit_environment, |
| 347 | LOG_DEBUG(Service_JIT, "called"); | 271 | u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess>& process, |
| 348 | 272 | InCopyHandle<Kernel::KCodeMemory>& rx_mem, | |
| 349 | struct Parameters { | 273 | InCopyHandle<Kernel::KCodeMemory>& ro_mem) { |
| 350 | u64 rx_size; | ||
| 351 | u64 ro_size; | ||
| 352 | }; | ||
| 353 | |||
| 354 | IPC::RequestParser rp{ctx}; | ||
| 355 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 356 | const auto process_handle{ctx.GetCopyHandle(0)}; | ||
| 357 | const auto rx_mem_handle{ctx.GetCopyHandle(1)}; | ||
| 358 | const auto ro_mem_handle{ctx.GetCopyHandle(2)}; | ||
| 359 | |||
| 360 | if (parameters.rx_size == 0 || parameters.ro_size == 0) { | ||
| 361 | LOG_ERROR(Service_JIT, "attempted to init with empty code regions"); | ||
| 362 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 363 | rb.Push(ResultUnknown); | ||
| 364 | return; | ||
| 365 | } | ||
| 366 | |||
| 367 | auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)}; | ||
| 368 | if (process.IsNull()) { | 274 | if (process.IsNull()) { |
| 369 | LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); | 275 | LOG_ERROR(Service_JIT, "process is null"); |
| 370 | IPC::ResponseBuilder rb{ctx, 2}; | 276 | R_THROW(ResultUnknown); |
| 371 | rb.Push(ResultUnknown); | ||
| 372 | return; | ||
| 373 | } | 277 | } |
| 374 | |||
| 375 | auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)}; | ||
| 376 | if (rx_mem.IsNull()) { | 278 | if (rx_mem.IsNull()) { |
| 377 | LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); | 279 | LOG_ERROR(Service_JIT, "rx_mem is null"); |
| 378 | IPC::ResponseBuilder rb{ctx, 2}; | 280 | R_THROW(ResultUnknown); |
| 379 | rb.Push(ResultUnknown); | ||
| 380 | return; | ||
| 381 | } | 281 | } |
| 382 | 282 | if (rx_mem.IsNull()) { | |
| 383 | auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)}; | 283 | LOG_ERROR(Service_JIT, "ro_mem is null"); |
| 384 | if (ro_mem.IsNull()) { | 284 | R_THROW(ResultUnknown); |
| 385 | LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle); | ||
| 386 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 387 | rb.Push(ResultUnknown); | ||
| 388 | return; | ||
| 389 | } | 285 | } |
| 390 | 286 | ||
| 391 | CodeMemory rx, ro; | 287 | CodeMemory rx, ro; |
| 392 | Result res; | ||
| 393 | |||
| 394 | res = rx.Initialize(*process, *rx_mem, parameters.rx_size, | ||
| 395 | Kernel::Svc::MemoryPermission::ReadExecute, generate_random); | ||
| 396 | if (R_FAILED(res)) { | ||
| 397 | LOG_ERROR(Service_JIT, "rx_mem could not be mapped for handle=0x{:08X}", rx_mem_handle); | ||
| 398 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 399 | rb.Push(res); | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | 288 | ||
| 403 | res = ro.Initialize(*process, *ro_mem, parameters.ro_size, | 289 | R_TRY(rx.Initialize(*process, *rx_mem, rx_size, Kernel::Svc::MemoryPermission::ReadExecute, |
| 404 | Kernel::Svc::MemoryPermission::Read, generate_random); | 290 | generate_random)); |
| 405 | if (R_FAILED(res)) { | 291 | R_TRY(ro.Initialize(*process, *ro_mem, ro_size, Kernel::Svc::MemoryPermission::Read, |
| 406 | LOG_ERROR(Service_JIT, "ro_mem could not be mapped for handle=0x{:08X}", ro_mem_handle); | 292 | generate_random)); |
| 407 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 408 | rb.Push(res); | ||
| 409 | return; | ||
| 410 | } | ||
| 411 | 293 | ||
| 412 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 294 | *out_jit_environment = std::make_shared<IJitEnvironment>(system, std::move(process), |
| 413 | rb.Push(ResultSuccess); | 295 | std::move(rx), std::move(ro)); |
| 414 | rb.PushIpcInterface<IJitEnvironment>(system, std::move(process), std::move(rx), | 296 | R_SUCCEED(); |
| 415 | std::move(ro)); | ||
| 416 | } | 297 | } |
| 417 | 298 | ||
| 418 | private: | 299 | private: |
diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp index f0658bb5d..ae62c430e 100644 --- a/src/core/hle/service/ro/ro.cpp +++ b/src/core/hle/service/ro/ro.cpp | |||
| @@ -6,13 +6,13 @@ | |||
| 6 | #include "common/scope_exit.h" | 6 | #include "common/scope_exit.h" |
| 7 | #include "core/hle/kernel/k_process.h" | 7 | #include "core/hle/kernel/k_process.h" |
| 8 | 8 | ||
| 9 | #include "core/hle/service/cmif_serialization.h" | ||
| 9 | #include "core/hle/service/ipc_helpers.h" | 10 | #include "core/hle/service/ipc_helpers.h" |
| 10 | #include "core/hle/service/ro/ro.h" | 11 | #include "core/hle/service/ro/ro.h" |
| 11 | #include "core/hle/service/ro/ro_nro_utils.h" | 12 | #include "core/hle/service/ro/ro_nro_utils.h" |
| 12 | #include "core/hle/service/ro/ro_results.h" | 13 | #include "core/hle/service/ro/ro_results.h" |
| 13 | #include "core/hle/service/ro/ro_types.h" | 14 | #include "core/hle/service/ro/ro_types.h" |
| 14 | #include "core/hle/service/server_manager.h" | 15 | #include "core/hle/service/server_manager.h" |
| 15 | #include "core/hle/service/service.h" | ||
| 16 | 16 | ||
| 17 | namespace Service::RO { | 17 | namespace Service::RO { |
| 18 | 18 | ||
| @@ -500,46 +500,65 @@ private: | |||
| 500 | } | 500 | } |
| 501 | }; | 501 | }; |
| 502 | 502 | ||
| 503 | class RoInterface { | 503 | class RoInterface : public ServiceFramework<RoInterface> { |
| 504 | public: | 504 | public: |
| 505 | explicit RoInterface(std::shared_ptr<RoContext> ro, NrrKind nrr_kind) | 505 | explicit RoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro, |
| 506 | : m_ro(ro), m_context_id(InvalidContextId), m_nrr_kind(nrr_kind) {} | 506 | NrrKind nrr_kind) |
| 507 | : ServiceFramework{system_, name_}, m_ro(ro), m_context_id(InvalidContextId), | ||
| 508 | m_nrr_kind(nrr_kind) { | ||
| 509 | |||
| 510 | // clang-format off | ||
| 511 | static const FunctionInfo functions[] = { | ||
| 512 | {0, C<&RoInterface::MapManualLoadModuleMemory>, "MapManualLoadModuleMemory"}, | ||
| 513 | {1, C<&RoInterface::UnmapManualLoadModuleMemory>, "UnmapManualLoadModuleMemory"}, | ||
| 514 | {2, C<&RoInterface::RegisterModuleInfo>, "RegisterModuleInfo"}, | ||
| 515 | {3, C<&RoInterface::UnregisterModuleInfo>, "UnregisterModuleInfo"}, | ||
| 516 | {4, C<&RoInterface::RegisterProcessHandle>, "RegisterProcessHandle"}, | ||
| 517 | {10, C<&RoInterface::RegisterProcessModuleInfo>, "RegisterProcessModuleInfo"}, | ||
| 518 | }; | ||
| 519 | // clang-format on | ||
| 520 | |||
| 521 | RegisterHandlers(functions); | ||
| 522 | } | ||
| 523 | |||
| 507 | ~RoInterface() { | 524 | ~RoInterface() { |
| 508 | m_ro->UnregisterProcess(m_context_id); | 525 | m_ro->UnregisterProcess(m_context_id); |
| 509 | } | 526 | } |
| 510 | 527 | ||
| 511 | Result MapManualLoadModuleMemory(u64* out_load_address, u64 client_pid, u64 nro_address, | 528 | Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid, |
| 512 | u64 nro_size, u64 bss_address, u64 bss_size) { | 529 | u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { |
| 513 | R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); | 530 | R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); |
| 514 | R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address, m_context_id, nro_address, | 531 | R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address.Get(), m_context_id, nro_address, |
| 515 | nro_size, bss_address, bss_size)); | 532 | nro_size, bss_address, bss_size)); |
| 516 | } | 533 | } |
| 517 | 534 | ||
| 518 | Result UnmapManualLoadModuleMemory(u64 client_pid, u64 nro_address) { | 535 | Result UnmapManualLoadModuleMemory(ClientProcessId client_pid, u64 nro_address) { |
| 519 | R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); | 536 | R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); |
| 520 | R_RETURN(m_ro->UnmapManualLoadModuleMemory(m_context_id, nro_address)); | 537 | R_RETURN(m_ro->UnmapManualLoadModuleMemory(m_context_id, nro_address)); |
| 521 | } | 538 | } |
| 522 | 539 | ||
| 523 | Result RegisterModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size) { | 540 | Result RegisterModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size) { |
| 524 | R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); | 541 | R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); |
| 525 | R_RETURN( | 542 | R_RETURN( |
| 526 | m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, NrrKind::User, true)); | 543 | m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, NrrKind::User, true)); |
| 527 | } | 544 | } |
| 528 | 545 | ||
| 529 | Result UnregisterModuleInfo(u64 client_pid, u64 nrr_address) { | 546 | Result UnregisterModuleInfo(ClientProcessId client_pid, u64 nrr_address) { |
| 530 | R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); | 547 | R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); |
| 531 | R_RETURN(m_ro->UnregisterModuleInfo(m_context_id, nrr_address)); | 548 | R_RETURN(m_ro->UnregisterModuleInfo(m_context_id, nrr_address)); |
| 532 | } | 549 | } |
| 533 | 550 | ||
| 534 | Result RegisterProcessHandle(u64 client_pid, Kernel::KProcess* process) { | 551 | Result RegisterProcessHandle(ClientProcessId client_pid, |
| 552 | InCopyHandle<Kernel::KProcess>& process) { | ||
| 535 | // Register the process. | 553 | // Register the process. |
| 536 | R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process, client_pid)); | 554 | R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.GetPointerUnsafe(), |
| 555 | *client_pid)); | ||
| 537 | } | 556 | } |
| 538 | 557 | ||
| 539 | Result RegisterProcessModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size, | 558 | Result RegisterProcessModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size, |
| 540 | Kernel::KProcess* process) { | 559 | InCopyHandle<Kernel::KProcess>& process) { |
| 541 | // Validate the process. | 560 | // Validate the process. |
| 542 | R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); | 561 | R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); |
| 543 | 562 | ||
| 544 | // Register the module. | 563 | // Register the module. |
| 545 | R_RETURN(m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, m_nrr_kind, | 564 | R_RETURN(m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, m_nrr_kind, |
| @@ -552,137 +571,6 @@ private: | |||
| 552 | NrrKind m_nrr_kind{}; | 571 | NrrKind m_nrr_kind{}; |
| 553 | }; | 572 | }; |
| 554 | 573 | ||
| 555 | class IRoInterface : public ServiceFramework<IRoInterface> { | ||
| 556 | public: | ||
| 557 | explicit IRoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro, | ||
| 558 | NrrKind nrr_kind) | ||
| 559 | : ServiceFramework{system_, name_}, interface { | ||
| 560 | ro, nrr_kind | ||
| 561 | } { | ||
| 562 | // clang-format off | ||
| 563 | static const FunctionInfo functions[] = { | ||
| 564 | {0, &IRoInterface::MapManualLoadModuleMemory, "MapManualLoadModuleMemory"}, | ||
| 565 | {1, &IRoInterface::UnmapManualLoadModuleMemory, "UnmapManualLoadModuleMemory"}, | ||
| 566 | {2, &IRoInterface::RegisterModuleInfo, "RegisterModuleInfo"}, | ||
| 567 | {3, &IRoInterface::UnregisterModuleInfo, "UnregisterModuleInfo"}, | ||
| 568 | {4, &IRoInterface::RegisterProcessHandle, "RegisterProcessHandle"}, | ||
| 569 | {10, &IRoInterface::RegisterProcessModuleInfo, "RegisterProcessModuleInfo"}, | ||
| 570 | }; | ||
| 571 | // clang-format on | ||
| 572 | |||
| 573 | RegisterHandlers(functions); | ||
| 574 | } | ||
| 575 | |||
| 576 | private: | ||
| 577 | void MapManualLoadModuleMemory(HLERequestContext& ctx) { | ||
| 578 | LOG_DEBUG(Service_LDR, "(called)"); | ||
| 579 | |||
| 580 | struct InputParameters { | ||
| 581 | u64 client_pid; | ||
| 582 | u64 nro_address; | ||
| 583 | u64 nro_size; | ||
| 584 | u64 bss_address; | ||
| 585 | u64 bss_size; | ||
| 586 | }; | ||
| 587 | |||
| 588 | IPC::RequestParser rp{ctx}; | ||
| 589 | auto params = rp.PopRaw<InputParameters>(); | ||
| 590 | |||
| 591 | u64 load_address = 0; | ||
| 592 | auto result = interface.MapManualLoadModuleMemory(&load_address, ctx.GetPID(), | ||
| 593 | params.nro_address, params.nro_size, | ||
| 594 | params.bss_address, params.bss_size); | ||
| 595 | |||
| 596 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 597 | rb.Push(result); | ||
| 598 | rb.Push(load_address); | ||
| 599 | } | ||
| 600 | |||
| 601 | void UnmapManualLoadModuleMemory(HLERequestContext& ctx) { | ||
| 602 | LOG_DEBUG(Service_LDR, "(called)"); | ||
| 603 | |||
| 604 | struct InputParameters { | ||
| 605 | u64 client_pid; | ||
| 606 | u64 nro_address; | ||
| 607 | }; | ||
| 608 | |||
| 609 | IPC::RequestParser rp{ctx}; | ||
| 610 | auto params = rp.PopRaw<InputParameters>(); | ||
| 611 | auto result = interface.UnmapManualLoadModuleMemory(ctx.GetPID(), params.nro_address); | ||
| 612 | |||
| 613 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 614 | rb.Push(result); | ||
| 615 | } | ||
| 616 | |||
| 617 | void RegisterModuleInfo(HLERequestContext& ctx) { | ||
| 618 | LOG_DEBUG(Service_LDR, "(called)"); | ||
| 619 | |||
| 620 | struct InputParameters { | ||
| 621 | u64 client_pid; | ||
| 622 | u64 nrr_address; | ||
| 623 | u64 nrr_size; | ||
| 624 | }; | ||
| 625 | |||
| 626 | IPC::RequestParser rp{ctx}; | ||
| 627 | auto params = rp.PopRaw<InputParameters>(); | ||
| 628 | auto result = | ||
| 629 | interface.RegisterModuleInfo(ctx.GetPID(), params.nrr_address, params.nrr_size); | ||
| 630 | |||
| 631 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 632 | rb.Push(result); | ||
| 633 | } | ||
| 634 | |||
| 635 | void UnregisterModuleInfo(HLERequestContext& ctx) { | ||
| 636 | LOG_DEBUG(Service_LDR, "(called)"); | ||
| 637 | |||
| 638 | struct InputParameters { | ||
| 639 | u64 client_pid; | ||
| 640 | u64 nrr_address; | ||
| 641 | }; | ||
| 642 | |||
| 643 | IPC::RequestParser rp{ctx}; | ||
| 644 | auto params = rp.PopRaw<InputParameters>(); | ||
| 645 | auto result = interface.UnregisterModuleInfo(ctx.GetPID(), params.nrr_address); | ||
| 646 | |||
| 647 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 648 | rb.Push(result); | ||
| 649 | } | ||
| 650 | |||
| 651 | void RegisterProcessHandle(HLERequestContext& ctx) { | ||
| 652 | LOG_DEBUG(Service_LDR, "(called)"); | ||
| 653 | |||
| 654 | auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0)); | ||
| 655 | auto client_pid = ctx.GetPID(); | ||
| 656 | auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe()); | ||
| 657 | |||
| 658 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 659 | rb.Push(result); | ||
| 660 | } | ||
| 661 | |||
| 662 | void RegisterProcessModuleInfo(HLERequestContext& ctx) { | ||
| 663 | LOG_DEBUG(Service_LDR, "(called)"); | ||
| 664 | |||
| 665 | struct InputParameters { | ||
| 666 | u64 client_pid; | ||
| 667 | u64 nrr_address; | ||
| 668 | u64 nrr_size; | ||
| 669 | }; | ||
| 670 | |||
| 671 | IPC::RequestParser rp{ctx}; | ||
| 672 | auto params = rp.PopRaw<InputParameters>(); | ||
| 673 | auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0)); | ||
| 674 | |||
| 675 | auto client_pid = ctx.GetPID(); | ||
| 676 | auto result = interface.RegisterProcessModuleInfo( | ||
| 677 | client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe()); | ||
| 678 | |||
| 679 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 680 | rb.Push(result); | ||
| 681 | } | ||
| 682 | |||
| 683 | RoInterface interface; | ||
| 684 | }; | ||
| 685 | |||
| 686 | } // namespace | 574 | } // namespace |
| 687 | 575 | ||
| 688 | void LoopProcess(Core::System& system) { | 576 | void LoopProcess(Core::System& system) { |
| @@ -691,11 +579,11 @@ void LoopProcess(Core::System& system) { | |||
| 691 | auto ro = std::make_shared<RoContext>(); | 579 | auto ro = std::make_shared<RoContext>(); |
| 692 | 580 | ||
| 693 | const auto RoInterfaceFactoryForUser = [&, ro] { | 581 | const auto RoInterfaceFactoryForUser = [&, ro] { |
| 694 | return std::make_shared<IRoInterface>(system, "ldr:ro", ro, NrrKind::User); | 582 | return std::make_shared<RoInterface>(system, "ldr:ro", ro, NrrKind::User); |
| 695 | }; | 583 | }; |
| 696 | 584 | ||
| 697 | const auto RoInterfaceFactoryForJitPlugin = [&, ro] { | 585 | const auto RoInterfaceFactoryForJitPlugin = [&, ro] { |
| 698 | return std::make_shared<IRoInterface>(system, "ro:1", ro, NrrKind::JitPlugin); | 586 | return std::make_shared<RoInterface>(system, "ro:1", ro, NrrKind::JitPlugin); |
| 699 | }; | 587 | }; |
| 700 | 588 | ||
| 701 | server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser)); | 589 | server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser)); |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index d539ed0f4..22d1343d5 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -206,6 +206,22 @@ protected: | |||
| 206 | RegisterHandlersBaseTipc(functions, n); | 206 | RegisterHandlersBaseTipc(functions, n); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | protected: | ||
| 210 | template <bool Domain, auto F> | ||
| 211 | void CmifReplyWrap(HLERequestContext& ctx); | ||
| 212 | |||
| 213 | /** | ||
| 214 | * Wraps the template pointer-to-member function for use in a domain session. | ||
| 215 | */ | ||
| 216 | template <auto F> | ||
| 217 | static constexpr HandlerFnP<Self> D = &Self::template CmifReplyWrap<true, F>; | ||
| 218 | |||
| 219 | /** | ||
| 220 | * Wraps the template pointer-to-member function for use in a non-domain session. | ||
| 221 | */ | ||
| 222 | template <auto F> | ||
| 223 | static constexpr HandlerFnP<Self> C = &Self::template CmifReplyWrap<false, F>; | ||
| 224 | |||
| 209 | private: | 225 | private: |
| 210 | /** | 226 | /** |
| 211 | * This function is used to allow invocation of pointers to handlers stored in the base class | 227 | * This function is used to allow invocation of pointers to handlers stored in the base class |