ReXGlue SDK
Loading...
Searching...
No Matches
call.h
Go to the documentation of this file.
1
10
11/*
12 * Parts of the translation wrappers are based on XenonRecomp and UnleashedRecomp.
13 */
14
15#pragma once
16
17#include <algorithm>
18#include <array>
19#include <atomic>
20#include <bit>
21#include <concepts>
22#include <cstdint>
23#include <cstring>
24#include <tuple>
25#include <type_traits>
26#include <utility>
27#include <vector>
28
29#include <rex/assert.h>
32#include <rex/ppc/seh.h>
33#include <rex/ppc/context.h>
34#include <rex/types.h>
36
37namespace rex::ppc {
38
40template <typename R, typename... T>
41constexpr std::tuple<T...> FunctionArgs(R (*)(T...)) noexcept {
42 return std::tuple<T...>();
43}
44
45template <auto V>
46static constexpr decltype(V) constant_v = V;
47
48template <typename T>
49static constexpr bool is_float_v = std::is_same_v<T, f32> || std::is_same_v<T, f64>;
50
51template <typename T>
52concept BigEndianType = is_be_type_v<T>;
53
54template <typename T>
55concept MappedPtrType = memory::is_mapped_ptr_v<T>;
56
57template <typename T>
58concept FloatType = is_float_v<T>;
59
61template <typename T>
62concept VectorType = std::is_same_v<std::remove_cvref_t<T>, PPCVRegister>;
63
69template <typename T>
70struct ByValue {
71 T value;
72};
73
74template <typename T>
75struct IsByValue : std::false_type {};
76
77template <typename T>
78struct IsByValue<ByValue<T>> : std::true_type {};
79
80template <typename T>
82
86template <ByValueType T>
87inline constexpr size_t kByValueSize = sizeof(std::declval<std::remove_cvref_t<T>>().value);
88
90template <typename T>
92
94constexpr u32 ByValueSlots(size_t size) {
95 return static_cast<u32>((size + sizeof(u64) - 1) / sizeof(u64));
96}
97
103constexpr bool IsRightJustified(size_t size) {
104 return size < sizeof(u64) && std::has_single_bit(size);
105}
106
108template <typename T>
109concept PlainType = !std::is_pointer_v<T> && !BigEndianType<T> && !MappedPtrType<T> &&
111
112template <auto Func>
113struct ArgCountT {
114 static constexpr size_t value = std::tuple_size_v<decltype(FunctionArgs(Func))>;
115};
116
118struct ArgPlace {
119 u32 slot{};
120 u32 slots{};
121 i32 gpr{-1};
122 i32 fpr{-1};
123 i32 vr{-1};
124 bool stack{};
125};
126
130 static constexpr size_t kIntegerRegisters = 8;
132 static constexpr size_t kFloatRegisters = 13;
134 static constexpr size_t kVectorRegisters = 13;
135
142 static constexpr PPCRegister& GetIntegerRegister(PPCContext& ctx, size_t slot) noexcept {
143 switch (slot) {
144 case 0:
145 return ctx.r3;
146 case 1:
147 return ctx.r4;
148 case 2:
149 return ctx.r5;
150 case 3:
151 return ctx.r6;
152 case 4:
153 return ctx.r7;
154 case 5:
155 return ctx.r8;
156 case 6:
157 return ctx.r9;
158 default:
159 return ctx.r10;
160 }
161 }
162
167 static constexpr PPCRegister& GetFloatRegister(PPCContext& ctx, size_t ordinal) noexcept {
168 switch (ordinal) {
169 case 0:
170 return ctx.f1;
171 case 1:
172 return ctx.f2;
173 case 2:
174 return ctx.f3;
175 case 3:
176 return ctx.f4;
177 case 4:
178 return ctx.f5;
179 case 5:
180 return ctx.f6;
181 case 6:
182 return ctx.f7;
183 case 7:
184 return ctx.f8;
185 case 8:
186 return ctx.f9;
187 case 9:
188 return ctx.f10;
189 case 10:
190 return ctx.f11;
191 case 11:
192 return ctx.f12;
193 default:
194 return ctx.f13;
195 }
196 }
197
202 static constexpr PPCVRegister& GetVectorRegister(PPCContext& ctx, size_t ordinal) noexcept {
203 PPCVRegister* registers[] = {&ctx.v1, &ctx.v2, &ctx.v3, &ctx.v4, &ctx.v5, &ctx.v6, &ctx.v7,
204 &ctx.v8, &ctx.v9, &ctx.v10, &ctx.v11, &ctx.v12, &ctx.v13};
205 return *registers[ordinal];
206 }
207
214 static constexpr u32 GetStackSlotAddress(const PPCContext& ctx, size_t slot) noexcept {
215 return ctx.r1.u32 + 0x50 + static_cast<u32>((slot - kIntegerRegisters) * 8);
216 }
217
224 template <size_t Bytes = sizeof(u32)>
225 static constexpr u64 GetIntegerArgumentValue(const PPCContext& ctx, u8* base,
226 size_t slot) noexcept {
227 if constexpr (Bytes == sizeof(u64)) {
228 if (slot < kIntegerRegisters) {
229 return GetIntegerRegister(const_cast<PPCContext&>(ctx), slot).u64;
230 }
231 return *rex::memory::GuestPtr<be_u64*>(base, GetStackSlotAddress(ctx, slot));
232 } else {
233 if (slot < kIntegerRegisters) {
234 return GetIntegerRegister(const_cast<PPCContext&>(ctx), slot).u32;
235 }
236 return *rex::memory::GuestPtr<be_u32*>(base, GetStackSlotAddress(ctx, slot) + 4);
237 }
238 }
239
246 static f64 GetFloatArgumentValue(const PPCContext& ctx, u8* base, const ArgPlace& arg,
247 bool single) noexcept {
248 if (arg.fpr >= 0) {
249 return GetFloatRegister(const_cast<PPCContext&>(ctx), static_cast<size_t>(arg.fpr)).f64;
250 }
251 const u32 address = GetStackSlotAddress(ctx, arg.slot);
252 if (single) {
253 return std::bit_cast<f32>(
254 static_cast<u32>(*rex::memory::GuestPtr<be_u32*>(base, address + 4)));
255 }
256 return std::bit_cast<f64>(static_cast<u64>(*rex::memory::GuestPtr<be_u64*>(base, address)));
257 }
258
265 template <size_t Bytes = sizeof(u32)>
266 static constexpr void SetIntegerArgumentValue(PPCContext& ctx, u8* base, size_t slot,
267 u64 value) noexcept {
268 if (slot < kIntegerRegisters) {
269 GetIntegerRegister(ctx, slot).u64 = value;
270 return;
271 }
272 if constexpr (Bytes == sizeof(u64)) {
273 *rex::memory::GuestPtr<be_u64*>(base, GetStackSlotAddress(ctx, slot)) = value;
274 } else {
276 static_cast<u32>(value);
277 }
278 }
279
285 static void SetFloatArgumentValue(PPCContext& ctx, u8* base, const ArgPlace& arg, f64 value,
286 bool single) noexcept {
287 if (arg.fpr >= 0) {
288 GetFloatRegister(ctx, static_cast<size_t>(arg.fpr)).f64 = value;
289 if (!arg.stack) {
290 return;
291 }
292 }
293 const u32 address = GetStackSlotAddress(ctx, arg.slot);
294 if (single) {
295 *rex::memory::GuestPtr<be_u32*>(base, address + 4) =
296 std::bit_cast<u32>(static_cast<f32>(value));
297 } else {
298 *rex::memory::GuestPtr<be_u64*>(base, address) = std::bit_cast<u64>(value);
299 }
300 }
301
307 static PPCVRegister GetVectorArgumentValue(const PPCContext& ctx, u8* base,
308 const ArgPlace& arg) noexcept {
309 if (arg.vr >= 0) {
310 return GetVectorRegister(const_cast<PPCContext&>(ctx), static_cast<size_t>(arg.vr));
311 }
312 PPCVRegister result{};
313 const u8* image = rex::memory::GuestPtr<const u8*>(base, GetStackSlotAddress(ctx, arg.slot));
314 for (size_t i = 0; i < sizeof(PPCVRegister); ++i) {
315 result.u8[i] = image[sizeof(PPCVRegister) - 1 - i];
316 }
317 return result;
318 }
319
325 static void SetVectorArgumentValue(PPCContext& ctx, u8* base, const ArgPlace& arg,
326 const PPCVRegister& value) noexcept {
327 if (arg.vr >= 0) {
328 GetVectorRegister(ctx, static_cast<size_t>(arg.vr)) = value;
329 return;
330 }
331 u8* image = rex::memory::GuestPtr<u8*>(base, GetStackSlotAddress(ctx, arg.slot));
332 for (size_t i = 0; i < sizeof(PPCVRegister); ++i) {
333 image[sizeof(PPCVRegister) - 1 - i] = value.u8[i];
334 }
335 }
336
338 template <ByValueType T>
339 static T GetValue(PPCContext& ctx, u8* base, const ArgPlace& arg) noexcept {
340 constexpr size_t kSize = kByValueSize<T>;
341 u8 image[ByValueSlots(kSize) * sizeof(u64)]{};
342 for (u32 k = 0; k < arg.slots; ++k) {
343 const size_t slot = arg.slot + k;
344 const u64 word = slot < kIntegerRegisters ? GetIntegerRegister(ctx, slot).u64
345 : static_cast<u64>(*rex::memory::GuestPtr<be_u64*>(
346 base, GetStackSlotAddress(ctx, slot)));
347 for (size_t b = 0; b < sizeof(u64); ++b) {
348 image[k * sizeof(u64) + b] = static_cast<u8>(word >> (56 - 8 * b));
349 }
350 }
351 T result{};
352 std::memcpy(&result.value, image + (IsRightJustified(kSize) ? sizeof(u64) - kSize : 0), kSize);
353 return result;
354 }
355
357 template <ByValueType T>
358 static void SetByValueArgumentValue(PPCContext& ctx, u8* base, const ArgPlace& arg,
359 const T& value) noexcept {
360 constexpr size_t kSize = kByValueSize<T>;
361 u8 image[ByValueSlots(kSize) * sizeof(u64)]{};
362 std::memcpy(image + (IsRightJustified(kSize) ? sizeof(u64) - kSize : 0), &value.value, kSize);
363 for (u32 k = 0; k < arg.slots; ++k) {
364 u64 word = 0;
365 for (size_t b = 0; b < sizeof(u64); ++b) {
366 word = (word << 8) | image[k * sizeof(u64) + b];
367 }
368 const size_t slot = arg.slot + k;
369 if (slot < kIntegerRegisters) {
370 GetIntegerRegister(ctx, slot).u64 = word;
371 } else {
372 *rex::memory::GuestPtr<be_u64*>(base, GetStackSlotAddress(ctx, slot)) = word;
373 }
374 }
375 }
376
378 template <BigEndianType T>
379 static constexpr T GetValue(PPCContext& ctx, u8* base, const ArgPlace& arg) noexcept {
380 T result;
381 result.value = static_cast<decltype(result.value)>(
382 GetIntegerArgumentValue<sizeof(result.value)>(ctx, base, arg.slot));
383 return result;
384 }
385
391 template <MappedPtrType T>
392 static T GetValue(PPCContext& ctx, u8* base, const ArgPlace& arg) noexcept {
393 return GetMappedPointerValue<T>(GetIntegerArgumentValue(ctx, base, arg.slot), base);
394 }
395
402 template <MappedPtrType T>
403 static T GetMappedPointerValue(u64 value, u8* base) noexcept {
405 const u32 guest_addr = static_cast<u32>(value);
406 if (guest_addr == 0) {
407 return T(nullptr);
408 }
409 return T(rex::memory::GuestPtr<InnerT*>(base, guest_addr), guest_addr);
410 }
411
412 template <VectorType T>
413 static T GetValue(PPCContext& ctx, u8* base, const ArgPlace& arg) noexcept {
414 return GetVectorArgumentValue(ctx, base, arg);
415 }
416
418 template <PlainType T>
419 static constexpr T GetValue(PPCContext& ctx, u8* base, const ArgPlace& arg) noexcept {
420 if constexpr (is_float_v<T>) {
421 return static_cast<T>(GetFloatArgumentValue(ctx, base, arg, std::is_same_v<T, f32>));
422 } else {
423 return static_cast<T>(GetIntegerArgumentValue<sizeof(T)>(ctx, base, arg.slot));
424 }
425 }
426
432 template <typename T>
433 requires std::is_pointer_v<T>
434 static constexpr T GetValue(PPCContext& ctx, u8* base, const ArgPlace& arg) noexcept {
435 return GetPointerValue<T>(GetIntegerArgumentValue(ctx, base, arg.slot), base);
436 }
437
444 template <typename T>
445 requires std::is_pointer_v<T>
446 static constexpr T GetPointerValue(u64 value, u8* base) noexcept {
447 const u32 guest_addr = static_cast<u32>(value);
448 if (guest_addr == 0) {
449 return nullptr;
450 }
451 return rex::memory::GuestPtr<T>(base, guest_addr);
452 }
453
455 template <typename T>
456 static constexpr void SetValue(PPCContext& ctx, u8* base, const ArgPlace& arg, T value) noexcept {
457 if constexpr (is_float_v<T>) {
458 SetFloatArgumentValue(ctx, base, arg, value, std::is_same_v<T, f32>);
459 } else if constexpr (VectorType<T>) {
460 SetVectorArgumentValue(ctx, base, arg, value);
461 } else if constexpr (ByValueType<T>) {
462 SetByValueArgumentValue(ctx, base, arg, value);
463 } else if constexpr (MappedPtrType<T>) {
464 SetIntegerArgumentValue(ctx, base, arg.slot, value.GetGuestAddress());
465 } else if constexpr (std::is_null_pointer_v<T>) {
466 SetIntegerArgumentValue(ctx, base, arg.slot, 0);
467 } else if constexpr (std::is_pointer_v<T>) {
469 ctx, base, arg.slot,
470 rex::memory::HostPtrToGuest(base, reinterpret_cast<const void*>(value)));
471 } else {
472 SetIntegerArgumentValue<(sizeof(T) > sizeof(u32)) ? sizeof(u64) : sizeof(u32)>(
473 ctx, base, arg.slot, value);
474 }
475 }
476};
477
479template <typename T>
480constexpr bool IsFloatType() {
481 return is_float_v<T>;
482}
483
491template <typename... Args>
492constexpr std::array<ArgPlace, sizeof...(Args)> PlaceArgs() {
493 std::array<ArgPlace, sizeof...(Args)> places{};
494 if constexpr (sizeof...(Args) > 0) {
495 constexpr u32 kIntegerRegisters = 8;
496 constexpr u32 kFloatRegisters = 13;
497 constexpr u32 kVectorRegisters = 13;
498 u32 slot = 0;
499 u32 float_register = 0;
500 u32 vector_register = 0;
501 size_t index = 0;
502 (
503 [&]<typename T>() {
504 ArgPlace place;
505 place.slot = slot;
506 place.slots = 1;
507 if constexpr (VectorType<T>) {
508 if (vector_register < kVectorRegisters) {
509 place.vr = static_cast<i32>(vector_register);
510 place.slots = 0;
511 } else {
512 const u32 first = (std::max(slot, kIntegerRegisters) + 1) & ~1u;
513 place.slot = first;
514 place.slots = 2;
515 place.stack = true;
516 slot = first + place.slots;
517 }
518 ++vector_register;
519 places[index++] = place;
520 return;
521 } else if constexpr (ByValueType<T>) {
522 place.slots = ByValueSlots(kByValueSize<T>);
523 if (slot < kIntegerRegisters) {
524 place.gpr = static_cast<i32>(slot);
525 }
526 place.stack = slot + place.slots > kIntegerRegisters;
527 slot += place.slots;
528 places[index++] = place;
529 return;
530 } else if constexpr (IsFloatType<std::remove_cvref_t<T>>()) {
531 if (float_register < kFloatRegisters) {
532 place.fpr = static_cast<i32>(float_register);
533 }
534 place.stack = slot >= kIntegerRegisters || place.fpr < 0;
535 ++float_register;
536 } else {
537 if (slot < kIntegerRegisters) {
538 place.gpr = static_cast<i32>(slot);
539 }
540 place.stack = slot >= kIntegerRegisters;
541 }
542 ++slot;
543 places[index++] = place;
544 }.template operator()<Args>(),
545 ...);
546 }
547 return places;
548}
549
551template <typename R, typename... Args>
552constexpr auto PlaceSignatureArgs(R (*)(Args...)) {
553 if constexpr (HiddenReturnType<R>) {
554 const auto all = PlaceArgs<u32, Args...>();
555 std::array<ArgPlace, sizeof...(Args)> places{};
556 for (size_t i = 0; i < sizeof...(Args); ++i) {
557 places[i] = all[i + 1];
558 }
559 return places;
560 } else {
561 return PlaceArgs<Args...>();
562 }
563}
564
566template <auto Func>
567constexpr auto PlaceFunctionArgs() {
568 return PlaceSignatureArgs(Func);
569}
570
572template <auto Func, size_t I>
573struct ArgPlaceT {
574 static constexpr ArgPlace value = PlaceFunctionArgs<Func>()[I];
575};
576
578template <auto Func, int I = 0, typename... TArgs>
579 requires(I >= sizeof...(TArgs))
580void TranslateArgsToHost([[maybe_unused]] PPCContext& ctx, [[maybe_unused]] u8* base,
581 [[maybe_unused]] std::tuple<TArgs...>&) noexcept {}
582
584template <auto Func, int I = 0, typename... TArgs>
585 requires(I < sizeof...(TArgs))
586void TranslateArgsToHost(PPCContext& ctx, u8* base, std::tuple<TArgs...>& tpl) noexcept {
587 using T = std::tuple_element_t<I, std::remove_reference_t<decltype(tpl)>>;
588 std::get<I>(tpl) = ArgTranslator::GetValue<T>(ctx, base, ArgPlaceT<Func, I>::value);
589 TranslateArgsToHost<Func, I + 1>(ctx, base, tpl);
590}
591
593template <int I = 0, typename... TArgs>
594 requires(I >= sizeof...(TArgs))
595void TranslateArgsToGuest([[maybe_unused]] PPCContext& ctx, [[maybe_unused]] u8* base,
596 [[maybe_unused]] std::tuple<TArgs...>&) noexcept {}
597
599template <int I = 0, typename... TArgs>
600 requires(I < sizeof...(TArgs))
601void TranslateArgsToGuest(PPCContext& ctx, u8* base, std::tuple<TArgs...>& tpl) noexcept {
602 using T = std::tuple_element_t<I, std::remove_reference_t<decltype(tpl)>>;
603 ArgTranslator::SetValue<T>(ctx, base, PlaceArgs<TArgs...>()[I], std::get<I>(tpl));
604 TranslateArgsToGuest<I + 1>(ctx, base, tpl);
605}
606
608template <ByValueType T>
609void StoreByValue(u8* base, u32 address, const T& value) {
610 u8* destination = rex::memory::GuestPtr<u8*>(base, address);
611 if constexpr (std::is_same_v<std::remove_cvref_t<decltype(value.value)>, PPCVRegister>) {
612 for (size_t i = 0; i < sizeof(PPCVRegister); ++i) {
613 destination[sizeof(PPCVRegister) - 1 - i] = value.value.u8[i];
614 }
615 } else {
616 std::memcpy(destination, &value.value, sizeof(value.value));
617 }
618}
619
626template <ByValueType T>
627u64 ByValueToWord(const T& value) {
628 constexpr size_t kSize = kByValueSize<T>;
629 u8 image[sizeof(u64)]{};
630 std::memcpy(image + (IsRightJustified(kSize) ? sizeof(u64) - kSize : 0), &value.value, kSize);
631 u64 word = 0;
632 for (const u8 byte : image) {
633 word = (word << 8) | byte;
634 }
635 return word;
636}
637
639template <ByValueType T>
640T ByValueFromWord(u64 word) {
641 constexpr size_t kSize = kByValueSize<T>;
642 u8 image[sizeof(u64)]{};
643 for (size_t b = 0; b < sizeof(u64); ++b) {
644 image[b] = static_cast<u8>(word >> (56 - 8 * b));
645 }
646 T result{};
647 std::memcpy(&result.value, image + (IsRightJustified(kSize) ? sizeof(u64) - kSize : 0), kSize);
648 return result;
649}
650
652template <ByValueType T>
653T LoadByValue(u8* base, u32 address) {
654 const u8* source = rex::memory::GuestPtr<const u8*>(base, address);
655 T result{};
656 if constexpr (std::is_same_v<std::remove_cvref_t<decltype(result.value)>, PPCVRegister>) {
657 for (size_t i = 0; i < sizeof(PPCVRegister); ++i) {
658 result.value.u8[i] = source[sizeof(PPCVRegister) - 1 - i];
659 }
660 } else {
661 std::memcpy(&result.value, source, sizeof(result.value));
662 }
663 return result;
664}
665
671template <typename RetT>
672void StoreHostResult(PPCContext& ctx, u8* base, u32 hidden_pointer, const RetT& value) {
673 if constexpr (std::is_pointer<RetT>()) {
674 ctx.r3.u64 = rex::memory::HostPtrToGuest(base, reinterpret_cast<const void*>(value));
675 } else if constexpr (is_float_v<RetT>) {
676 ctx.f1.f64 = value;
677 } else if constexpr (VectorType<RetT>) {
678 ctx.v1 = value;
679 } else if constexpr (HiddenReturnType<RetT>) {
680 StoreByValue(base, hidden_pointer, value);
681 ctx.r3.u64 = hidden_pointer;
682 } else if constexpr (ByValueType<RetT>) {
683 ctx.r3.u64 = ByValueToWord(value);
684 } else {
685 ctx.r3.u64 = static_cast<u64>(value);
686 }
687}
688
695template <auto Func, bool StopAtEntry = true>
696__attribute__((noinline)) void GuestToHostThunk(PPCContext& ctx, u8* base) {
697 using RetT = decltype(std::apply(Func, FunctionArgs(Func)));
698
699 detail::CheckHookContext(ctx, __PRETTY_FUNCTION__);
700 if (StopAtEntry && ctx.stop_requested && ctx.stop_requested->load(std::memory_order_acquire)) {
701 throw rex::ThreadStop{};
702 }
703#if !REX_PLATFORM_WIN32
704 const rex::platform::HostCallDepth host_call_depth;
705#endif
706 const u32 hidden_pointer = ctx.r3.u32;
707 auto args = FunctionArgs(Func);
708 TranslateArgsToHost<Func>(ctx, base, args);
709
710 if constexpr (std::is_same_v<RetT, void>) {
711 std::apply(Func, args);
712 } else {
713 auto v = std::apply(Func, args);
714
715 asm volatile("" ::: "memory");
716
717 StoreHostResult(ctx, base, hidden_pointer, v);
718 }
719 if (ctx.stop_requested && ctx.stop_requested->load(std::memory_order_acquire)) {
720 throw rex::ThreadStop{};
721 }
722}
723
725inline constexpr u32 kRedZone = 1344;
726
728inline constexpr u32 kLinkageSize = 0x50;
729
731inline constexpr u32 kHostReturnAddress = 0xBCBCBCBC;
732
734inline u32 GetStackLimit(PPCContext& ctx, u8* base) {
735 if (ctx.r13.u32 == 0)
736 return 0;
737 u32 raw;
738 std::memcpy(&raw, rex::memory::GuestPtr(base, ctx.r13.u32 + 0x74), sizeof(raw));
739 return std::byteswap(raw);
740}
741
748inline void stack_bounds_check(PPCContext& ctx, u8* base, u32 new_r1) {
749 const u32 limit = GetStackLimit(ctx, base);
750 if (limit == 0) {
751 return;
752 }
753 const u32 stack_base = *rex::memory::GuestPtr<be_u32*>(base, ctx.r13.u32 + 0x70);
754 if (ctx.r1.u32 > limit && ctx.r1.u32 <= stack_base) {
755 REXCPU_CHECK(new_r1 > limit, "PPC stack overflow, r1 ({:#x}) below stack_end_ptr ({:#x})",
756 new_r1, limit);
757 }
758}
759
766inline u32 FrameBelow(PPCContext& ctx, u8* base, u32 size) {
767 const u32 r1 = ctx.r1.u32;
768 REXCPU_CHECK(size <= r1, "PPC stack underflow, r1 ({:#x}) below a {:#x} byte frame", r1, size);
769 const u32 new_r1 = (r1 - size) & ~0xFu;
770 if (base) {
771 stack_bounds_check(ctx, base, new_r1);
772 }
773 return new_r1;
774}
775
782inline u32 OpenCallFrame(PPCContext& ctx, u8* base, u32 stack_bytes) {
783 const u32 caller_r1 = ctx.r1.u32;
784 ctx.r1.u64 = FrameBelow(ctx, base, kLinkageSize + stack_bytes);
785 *rex::memory::GuestPtr<be_u32*>(base, ctx.r1.u32) = caller_r1;
787 return caller_r1;
788}
789
794template <typename... Args>
795constexpr u32 GetStackArgumentBytes() {
796 u32 end = 0;
797 for (const ArgPlace& place : PlaceArgs<Args...>()) {
798 end = std::max(end, place.slot + place.slots);
799 }
800 return end > 8 ? (end - 8) * 8 : 0;
801}
802
807template <typename R>
808constexpr u32 HiddenReturnBytes() {
809 if constexpr (HiddenReturnType<R>) {
810 return (static_cast<u32>(kByValueSize<R>) + 15) & ~15u;
811 } else {
812 return 0;
813 }
814}
815
821template <typename R>
822R LoadGuestResult([[maybe_unused]] u8* base, [[maybe_unused]] const PPCRegister& r3,
823 [[maybe_unused]] const PPCRegister& f1, [[maybe_unused]] const PPCVRegister& v1,
824 [[maybe_unused]] u32 result_storage) {
825 if constexpr (std::is_void_v<R>) {
826 return;
827 } else if constexpr (std::is_pointer_v<R>) {
828 return r3.u32 ? rex::memory::GuestPtr<R>(base, r3.u32) : nullptr;
829 } else if constexpr (is_float_v<R>) {
830 return static_cast<R>(f1.f64);
831 } else if constexpr (VectorType<R>) {
832 return v1;
833 } else if constexpr (HiddenReturnType<R>) {
834 return LoadByValue<R>(base, result_storage);
835 } else if constexpr (ByValueType<R>) {
836 return ByValueFromWord<R>(r3.u64);
837 } else {
838 return static_cast<R>(r3.u64);
839 }
840}
841
848template <typename R, typename... Args>
849R Call(PPCContext& ctx, u8* base, PPCFunc& fn, Args... args) {
850 const PPCContext saved = ctx;
851 constexpr bool kHidden = HiddenReturnType<R>;
852 u32 result_storage = 0;
853 auto tpl = [&] {
854 if constexpr (kHidden) {
855 return std::make_tuple(u32{0}, args...);
856 } else {
857 return std::make_tuple(args...);
858 }
859 }();
860 constexpr u32 kStackBytes =
861 ((kHidden ? GetStackArgumentBytes<u32, Args...>() : GetStackArgumentBytes<Args...>()) + 15) &
862 ~15u;
863 constexpr u32 kStorageBytes = HiddenReturnBytes<R>();
864 OpenCallFrame(ctx, base, kStackBytes + kStorageBytes);
865 if constexpr (kHidden) {
866 result_storage = ctx.r1.u32 + kLinkageSize + kStackBytes;
867 std::get<0>(tpl) = result_storage;
868 }
869 TranslateArgsToGuest(ctx, base, tpl);
870 fn(ctx, base);
871 const PPCRegister r3 = ctx.r3;
872 const PPCRegister f1 = ctx.f1;
873 const PPCVRegister v1 = ctx.v1;
874 const PPCFPSCRRegister fpscr = ctx.fpscr;
875 ctx = saved;
876 ctx.fpscr = fpscr;
877 return LoadGuestResult<R>(base, r3, f1, v1, result_storage);
878}
879
885template <typename T, typename... TArgs>
886T HostToGuestCall(PPCFunc* func, TArgs&&... argv) {
887 const BoundThread bound = GetBoundThread();
888 REX_ASSERT(bound.ctx && func, "HostToGuestCall needs a bound thread state and a function");
889 return Call<T>(*bound.ctx, bound.base, *func, std::forward<TArgs>(argv)...);
890}
891
892} // namespace rex::ppc
893
895constexpr size_t kExLoadedImageNameSize = 255 + 1;
896
897namespace rex::ppc {
898
900template <typename S>
902
904template <typename R, typename... Args>
905struct ImportFunction<R(Args...)> {
906 PPCFunc& fn;
907
909 R operator()(PPCContext& ctx, u8* base, Args... args) const {
910 return Call<R>(ctx, base, fn, args...);
911 }
912
914 R operator()(Args... args) const {
915 const BoundThread bound = GetBoundThread();
916 return Call<R>(*bound.ctx, bound.base, fn, args...);
917 }
918};
919
920} // namespace rex::ppc
#define REX_ASSERT(cond,...)
Definition assert.h:84
constexpr size_t kExLoadedImageNameSize
Definition call.h:895
Definition seh.h:100
Definition call.h:52
Definition call.h:81
Definition call.h:58
Definition call.h:91
Definition call.h:55
Definition call.h:109
Definition call.h:62
T GuestPtr(u8 *base, u32 guest_address) noexcept
Definition mapped_ptr.h:393
u32 HostPtrToGuest(const u8 *base, const void *host_address) noexcept
Definition mapped_ptr.h:403
Definition title_runtime.h:33
T ByValueFromWord(u64 word)
Definition call.h:640
u32 OpenCallFrame(PPCContext &ctx, u8 *base, u32 stack_bytes)
Definition call.h:782
void StoreHostResult(PPCContext &ctx, u8 *base, u32 hidden_pointer, const RetT &value)
Definition call.h:672
constexpr u32 HiddenReturnBytes()
Definition call.h:808
R Call(PPCContext &ctx, u8 *base, PPCFunc &fn, Args... args)
Definition call.h:849
constexpr u32 ByValueSlots(size_t size)
Definition call.h:94
R LoadGuestResult(u8 *base, const PPCRegister &r3, const PPCRegister &f1, const PPCVRegister &v1, u32 result_storage)
Definition call.h:822
constexpr bool IsRightJustified(size_t size)
Definition call.h:103
constexpr u32 GetStackArgumentBytes()
Definition call.h:795
T HostToGuestCall(PPCFunc *func, TArgs &&... argv)
Definition call.h:886
constexpr bool IsFloatType()
Definition call.h:480
T LoadByValue(u8 *base, u32 address)
Definition call.h:653
u32 FrameBelow(PPCContext &ctx, u8 *base, u32 size)
Definition call.h:766
constexpr std::tuple< T... > FunctionArgs(R(*)(T...)) noexcept
Definition call.h:41
REX_PPC_API BoundThread GetBoundThread()
constexpr size_t kByValueSize
Definition call.h:87
constexpr u32 kLinkageSize
Definition call.h:728
void GuestToHostThunk(PPCContext &ctx, u8 *base)
Definition call.h:696
u64 ByValueToWord(const T &value)
Definition call.h:627
constexpr std::array< ArgPlace, sizeof...(Args)> PlaceArgs()
Definition call.h:492
constexpr auto PlaceFunctionArgs()
Definition call.h:567
constexpr u32 kHostReturnAddress
Definition call.h:731
constexpr u32 kRedZone
Definition call.h:725
void TranslateArgsToGuest(PPCContext &ctx, u8 *base, std::tuple< TArgs... > &) noexcept
Definition call.h:595
void stack_bounds_check(PPCContext &ctx, u8 *base, u32 new_r1)
Definition call.h:748
void TranslateArgsToHost(PPCContext &ctx, u8 *base, std::tuple< TArgs... > &) noexcept
Definition call.h:580
u32 GetStackLimit(PPCContext &ctx, u8 *base)
Definition call.h:734
constexpr auto PlaceSignatureArgs(R(*)(Args...))
Definition call.h:552
void StoreByValue(u8 *base, u32 address, const T &value)
Definition call.h:609
Definition context.h:387
const std::atomic< bool > * stop_requested
Definition context.h:634
PPCRegister f1
Definition context.h:461
u64 lr
Definition context.h:428
PPCRegister r3
Definition context.h:389
PPCVRegister v1
Definition context.h:499
PPCRegister r13
Definition context.h:407
PPCRegister r1
Definition context.h:396
Definition thread.h:356
Definition mapped_ptr.h:330
Definition call.h:113
Definition call.h:573
Definition call.h:118
u32 slot
Definition call.h:119
bool stack
Definition call.h:124
i32 vr
Definition call.h:123
i32 gpr
Definition call.h:121
i32 fpr
Definition call.h:122
Definition call.h:128
static constexpr u64 GetIntegerArgumentValue(const PPCContext &ctx, u8 *base, size_t slot) noexcept
Definition call.h:225
static constexpr PPCRegister & GetFloatRegister(PPCContext &ctx, size_t ordinal) noexcept
Definition call.h:167
static f64 GetFloatArgumentValue(const PPCContext &ctx, u8 *base, const ArgPlace &arg, bool single) noexcept
Definition call.h:246
static constexpr T GetValue(PPCContext &ctx, u8 *base, const ArgPlace &arg) noexcept
Definition call.h:379
static constexpr size_t kVectorRegisters
Definition call.h:134
static PPCVRegister GetVectorArgumentValue(const PPCContext &ctx, u8 *base, const ArgPlace &arg) noexcept
Definition call.h:307
static T GetMappedPointerValue(u64 value, u8 *base) noexcept
Definition call.h:403
static void SetByValueArgumentValue(PPCContext &ctx, u8 *base, const ArgPlace &arg, const T &value) noexcept
Definition call.h:358
static constexpr T GetPointerValue(u64 value, u8 *base) noexcept
Definition call.h:446
static constexpr T GetValue(PPCContext &ctx, u8 *base, const ArgPlace &arg) noexcept
Definition call.h:434
static constexpr void SetValue(PPCContext &ctx, u8 *base, const ArgPlace &arg, T value) noexcept
Definition call.h:456
static T GetValue(PPCContext &ctx, u8 *base, const ArgPlace &arg) noexcept
Definition call.h:339
static constexpr size_t kFloatRegisters
Definition call.h:132
static void SetVectorArgumentValue(PPCContext &ctx, u8 *base, const ArgPlace &arg, const PPCVRegister &value) noexcept
Definition call.h:325
static constexpr PPCRegister & GetIntegerRegister(PPCContext &ctx, size_t slot) noexcept
Definition call.h:142
static constexpr PPCVRegister & GetVectorRegister(PPCContext &ctx, size_t ordinal) noexcept
Definition call.h:202
static constexpr u32 GetStackSlotAddress(const PPCContext &ctx, size_t slot) noexcept
Definition call.h:214
static void SetFloatArgumentValue(PPCContext &ctx, u8 *base, const ArgPlace &arg, f64 value, bool single) noexcept
Definition call.h:285
static constexpr void SetIntegerArgumentValue(PPCContext &ctx, u8 *base, size_t slot, u64 value) noexcept
Definition call.h:266
static constexpr size_t kIntegerRegisters
Definition call.h:130
Definition context.h:719
PPCContext * ctx
Definition context.h:720
u8 * base
Definition context.h:721
Definition call.h:70
R operator()(Args... args) const
Definition call.h:914
R operator()(PPCContext &ctx, u8 *base, Args... args) const
Definition call.h:909
Definition call.h:901
Definition call.h:75
Integer types, byte order wrappers and size literals.