40template <
typename R,
typename... T>
42 return std::tuple<T...>();
46static constexpr decltype(V) constant_v = V;
49static constexpr bool is_float_v = std::is_same_v<T, f32> || std::is_same_v<T, f64>;
62concept VectorType = std::is_same_v<std::remove_cvref_t<T>, PPCVRegister>;
86template <ByValueType T>
87inline constexpr size_t kByValueSize =
sizeof(std::declval<std::remove_cvref_t<T>>().value);
95 return static_cast<u32
>((size +
sizeof(u64) - 1) /
sizeof(u64));
104 return size <
sizeof(u64) && std::has_single_bit(size);
114 static constexpr size_t value = std::tuple_size_v<
decltype(
FunctionArgs(Func))>;
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];
224 template <
size_t Bytes = sizeof(u32)>
226 size_t slot)
noexcept {
227 if constexpr (Bytes ==
sizeof(u64)) {
247 bool single)
noexcept {
253 return std::bit_cast<f32>(
265 template <
size_t Bytes = sizeof(u32)>
267 u64 value)
noexcept {
272 if constexpr (Bytes ==
sizeof(u64)) {
276 static_cast<u32
>(value);
286 bool single)
noexcept {
296 std::bit_cast<u32>(
static_cast<f32
>(value));
312 PPCVRegister result{};
314 for (
size_t i = 0; i <
sizeof(PPCVRegister); ++i) {
315 result.u8[i] = image[
sizeof(PPCVRegister) - 1 - i];
326 const PPCVRegister& value)
noexcept {
332 for (
size_t i = 0; i <
sizeof(PPCVRegister); ++i) {
333 image[
sizeof(PPCVRegister) - 1 - i] = value.u8[i];
338 template <ByValueType T>
342 for (u32 k = 0; k < arg.slots; ++k) {
343 const size_t slot = arg.slot + k;
347 for (
size_t b = 0; b <
sizeof(u64); ++b) {
348 image[k *
sizeof(u64) + b] =
static_cast<u8
>(word >> (56 - 8 * b));
352 std::memcpy(&result.value, image + (
IsRightJustified(kSize) ?
sizeof(u64) - kSize : 0), kSize);
357 template <ByValueType T>
359 const T& value)
noexcept {
362 std::memcpy(image + (
IsRightJustified(kSize) ?
sizeof(u64) - kSize : 0), &value.value, kSize);
363 for (u32 k = 0; k < arg.slots; ++k) {
365 for (
size_t b = 0; b <
sizeof(u64); ++b) {
366 word = (word << 8) | image[k *
sizeof(u64) + b];
368 const size_t slot = arg.slot + k;
378 template <BigEndianType T>
381 result.value =
static_cast<decltype(result.value)
>(
391 template <MappedPtrType T>
402 template <MappedPtrType T>
405 const u32 guest_addr =
static_cast<u32
>(value);
406 if (guest_addr == 0) {
412 template <VectorType T>
418 template <PlainType T>
420 if constexpr (is_float_v<T>) {
432 template <
typename T>
433 requires std::is_pointer_v<T>
444 template <
typename T>
445 requires std::is_pointer_v<T>
447 const u32 guest_addr =
static_cast<u32
>(value);
448 if (guest_addr == 0) {
455 template <
typename T>
457 if constexpr (is_float_v<T>) {
465 }
else if constexpr (std::is_null_pointer_v<T>) {
467 }
else if constexpr (std::is_pointer_v<T>) {
473 ctx, base, arg.slot, value);
481 return is_float_v<T>;
491template <
typename... Args>
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;
499 u32 float_register = 0;
500 u32 vector_register = 0;
508 if (vector_register < kVectorRegisters) {
509 place.
vr =
static_cast<i32
>(vector_register);
512 const u32 first = (std::max(slot, kIntegerRegisters) + 1) & ~1u;
516 slot = first + place.slots;
519 places[index++] = place;
523 if (slot < kIntegerRegisters) {
524 place.
gpr =
static_cast<i32
>(slot);
526 place.
stack = slot + place.slots > kIntegerRegisters;
528 places[index++] = place;
531 if (float_register < kFloatRegisters) {
532 place.
fpr =
static_cast<i32
>(float_register);
534 place.
stack = slot >= kIntegerRegisters || place.
fpr < 0;
537 if (slot < kIntegerRegisters) {
538 place.
gpr =
static_cast<i32
>(slot);
540 place.
stack = slot >= kIntegerRegisters;
543 places[index++] = place;
544 }.template operator()<Args>(),
551template <
typename R,
typename... Args>
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];
572template <auto Func,
size_t I>
578template <
auto Func,
int I = 0,
typename... TArgs>
579 requires(I >=
sizeof...(TArgs))
581 [[maybe_unused]] std::tuple<TArgs...>&)
noexcept {}
584template <
auto Func,
int I = 0,
typename... TArgs>
585 requires(I <
sizeof...(TArgs))
587 using T = std::tuple_element_t<I, std::remove_reference_t<
decltype(tpl)>>;
593template <
int I = 0,
typename... TArgs>
594 requires(I >=
sizeof...(TArgs))
596 [[maybe_unused]] std::tuple<TArgs...>&)
noexcept {}
599template <
int I = 0,
typename... TArgs>
600 requires(I <
sizeof...(TArgs))
602 using T = std::tuple_element_t<I, std::remove_reference_t<
decltype(tpl)>>;
608template <ByValueType T>
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];
616 std::memcpy(destination, &value.value,
sizeof(value.value));
626template <ByValueType T>
629 u8 image[
sizeof(u64)]{};
630 std::memcpy(image + (
IsRightJustified(kSize) ?
sizeof(u64) - kSize : 0), &value.value, kSize);
632 for (
const u8
byte : image) {
633 word = (word << 8) |
byte;
639template <ByValueType 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));
647 std::memcpy(&result.value, image + (
IsRightJustified(kSize) ?
sizeof(u64) - kSize : 0), kSize);
652template <ByValueType T>
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];
661 std::memcpy(&result.value, source,
sizeof(result.value));
671template <
typename RetT>
673 if constexpr (std::is_pointer<RetT>()) {
675 }
else if constexpr (is_float_v<RetT>) {
681 ctx.
r3.u64 = hidden_pointer;
685 ctx.
r3.u64 =
static_cast<u64
>(value);
695template <auto Func,
bool StopAtEntry = true>
697 using RetT =
decltype(std::apply(Func,
FunctionArgs(Func)));
699 detail::CheckHookContext(ctx, __PRETTY_FUNCTION__);
703#if !REX_PLATFORM_WIN32
706 const u32 hidden_pointer = ctx.
r3.u32;
710 if constexpr (std::is_same_v<RetT, void>) {
711 std::apply(Func, args);
713 auto v = std::apply(Func, args);
715 asm volatile(
"" :::
"memory");
735 if (ctx.
r13.u32 == 0)
739 return std::byteswap(raw);
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})",
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;
783 const u32 caller_r1 = ctx.
r1.u32;
794template <
typename... Args>
798 end = std::max(end, place.slot + place.slots);
800 return end > 8 ? (end - 8) * 8 : 0;
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>) {
827 }
else if constexpr (std::is_pointer_v<R>) {
829 }
else if constexpr (is_float_v<R>) {
830 return static_cast<R
>(f1.f64);
838 return static_cast<R
>(r3.u64);
848template <
typename R,
typename... Args>
852 u32 result_storage = 0;
854 if constexpr (kHidden) {
855 return std::make_tuple(u32{0}, args...);
857 return std::make_tuple(args...);
860 constexpr u32 kStackBytes =
865 if constexpr (kHidden) {
867 std::get<0>(tpl) = result_storage;
871 const PPCRegister r3 = ctx.
r3;
872 const PPCRegister f1 = ctx.
f1;
873 const PPCVRegister v1 = ctx.
v1;
874 const PPCFPSCRRegister fpscr = ctx.fpscr;
885template <
typename T,
typename... TArgs>
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)...);
904template <
typename R,
typename... Args>
910 return Call<R>(ctx, base, fn, args...);
#define REX_ASSERT(cond,...)
Definition assert.h:84
constexpr size_t kExLoadedImageNameSize
Definition call.h:895
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
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 mapped_ptr.h:330
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
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
PPCContext * ctx
Definition context.h:720
u8 * base
Definition context.h:721
R operator()(Args... args) const
Definition call.h:914
R operator()(PPCContext &ctx, u8 *base, Args... args) const
Definition call.h:909
Integer types, byte order wrappers and size literals.