summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/cmif_serialization.h337
-rw-r--r--src/core/hle/service/cmif_types.h234
-rw-r--r--src/core/hle/service/hle_ipc.cpp16
-rw-r--r--src/core/hle/service/hle_ipc.h2
-rw-r--r--src/core/hle/service/jit/jit.cpp283
-rw-r--r--src/core/hle/service/ro/ro.cpp192
-rw-r--r--src/core/hle/service/service.h16
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
12namespace Service {
13
14// clang-format off
15struct RequestLayout {
16 u32 copy_handle_count;
17 u32 move_handle_count;
18 u32 cmif_raw_data_size;
19 u32 domain_interface_count;
20};
21
22template <ArgumentType Type1, ArgumentType Type2, typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0>
23constexpr 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
45template <ArgumentType DataType, typename MethodArguments, size_t ArgCount = 0, size_t ArgIndex = 0>
46constexpr 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
60template <typename MethodArguments>
61constexpr 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
70template <typename MethodArguments>
71constexpr 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
80template <typename MethodArguments>
81constexpr 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
90template <typename MethodArguments>
91constexpr 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
100template <bool Domain, typename MethodArguments>
101constexpr RequestLayout GetReplyInLayout() {
102 return Domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>();
103}
104
105template <bool Domain, typename MethodArguments>
106constexpr RequestLayout GetReplyOutLayout() {
107 return Domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>();
108}
109
110using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>;
111
112template <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>
113void 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
227template <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>
228void 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
297template <bool Domain, typename T, typename... A>
298void 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
331template <typename Self>
332template <bool Domain, auto F>
333inline 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
12namespace Service {
13
14// clang-format off
15template <typename T>
16class Out {
17public:
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
29private:
30 T* raw;
31};
32
33template <typename T>
34using SharedPointer = std::shared_ptr<T>;
35
36struct 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
48using ClientAppletResourceUserId = ClientProcessId;
49
50template <typename T>
51class InCopyHandle : public Kernel::KScopedAutoObject<T> {
52public:
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
65template <typename T>
66class OutCopyHandle : public Kernel::KScopedAutoObject<T> {
67public:
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
80template <typename T>
81class OutMoveHandle : public Kernel::KScopedAutoObject<T> {
82public:
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
95enum 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
106template <typename T, int A>
107struct 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
128template <BufferAttr A>
129using InBuffer = Buffer<const u8, BufferAttr_In | A>;
130
131template <typename T, BufferAttr A>
132using InArray = Buffer<T, BufferAttr_In | A>;
133
134template <BufferAttr A>
135using OutBuffer = Buffer<u8, BufferAttr_Out | A>;
136
137template <typename T, BufferAttr A>
138using OutArray = Buffer<T, BufferAttr_Out | A>;
139
140template <typename T, int A>
141struct 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
149template <typename T, BufferAttr A>
150using InLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_In | A>;
151
152template <typename T, BufferAttr A>
153using OutLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_Out | A>;
154
155template <typename T>
156struct RemoveOut {
157 using Type = std::remove_reference_t<T>;
158};
159
160template <typename T>
161struct RemoveOut<Out<T>> {
162 using Type = T;
163};
164
165enum 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
180template <typename T>
181struct ArgumentTraits;
182
183template <>
184struct ArgumentTraits<ClientProcessId> {
185 static constexpr ArgumentType Type = ArgumentType::InProcessId;
186};
187
188template <typename T>
189struct ArgumentTraits<SharedPointer<T>> {
190 static constexpr ArgumentType Type = ArgumentType::InInterface;
191};
192
193template <typename T>
194struct ArgumentTraits<InCopyHandle<T>> {
195 static constexpr ArgumentType Type = ArgumentType::InCopyHandle;
196};
197
198template <typename T>
199struct ArgumentTraits<Out<SharedPointer<T>>> {
200 static constexpr ArgumentType Type = ArgumentType::OutInterface;
201};
202
203template <typename T>
204struct ArgumentTraits<Out<T>> {
205 static constexpr ArgumentType Type = ArgumentType::OutData;
206};
207
208template <typename T>
209struct ArgumentTraits<OutCopyHandle<T>> {
210 static constexpr ArgumentType Type = ArgumentType::OutCopyHandle;
211};
212
213template <typename T>
214struct ArgumentTraits<OutMoveHandle<T>> {
215 static constexpr ArgumentType Type = ArgumentType::OutMoveHandle;
216};
217
218template <typename T, int A>
219struct ArgumentTraits<Buffer<T, A>> {
220 static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutBuffer : ArgumentType::InBuffer;
221};
222
223template <typename T, int A>
224struct ArgumentTraits<LargeData<T, A>> {
225 static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutLargeData : ArgumentType::InLargeData;
226};
227
228template <typename T>
229struct 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
504void 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
504std::string HLERequestContext::Description() const { 520std::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
17namespace Service::JIT { 17namespace Service::JIT {
@@ -21,6 +21,9 @@ struct CodeRange {
21 u64 size; 21 u64 size;
22}; 22};
23 23
24using Struct32 = std::array<u64, 4>;
25static_assert(sizeof(Struct32) == 32, "Struct32 has wrong size");
26
24class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { 27class IJitEnvironment final : public ServiceFramework<IJitEnvironment> {
25public: 28public:
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
296private: 222private:
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
345private: 269private:
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
418private: 299private:
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
17namespace Service::RO { 17namespace Service::RO {
18 18
@@ -500,46 +500,65 @@ private:
500 } 500 }
501}; 501};
502 502
503class RoInterface { 503class RoInterface : public ServiceFramework<RoInterface> {
504public: 504public:
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
555class IRoInterface : public ServiceFramework<IRoInterface> {
556public:
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
576private:
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
688void LoopProcess(Core::System& system) { 576void 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
209protected:
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
209private: 225private:
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