Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
common/va_ctx.h
ShadPKG / common / va_ctx.h
1// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3#pragma once
4 
5#include <xmmintrin.h>
6#include "common/shadpkg_types.h"
7 
8#define VA_ARGS \
9 uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
10 uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
11 __m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...
12 
13#define VA_CTX(ctx) \
14 alignas(16)::Common::VaCtx ctx{}; \
15 (ctx).reg_save_area.gp[0] = rdi; \
16 (ctx).reg_save_area.gp[1] = rsi; \
17 (ctx).reg_save_area.gp[2] = rdx; \
18 (ctx).reg_save_area.gp[3] = rcx; \
19 (ctx).reg_save_area.gp[4] = r8; \
20 (ctx).reg_save_area.gp[5] = r9; \
21 (ctx).reg_save_area.fp[0] = xmm0; \
22 (ctx).reg_save_area.fp[1] = xmm1; \
23 (ctx).reg_save_area.fp[2] = xmm2; \
24 (ctx).reg_save_area.fp[3] = xmm3; \
25 (ctx).reg_save_area.fp[4] = xmm4; \
26 (ctx).reg_save_area.fp[5] = xmm5; \
27 (ctx).reg_save_area.fp[6] = xmm6; \
28 (ctx).reg_save_area.fp[7] = xmm7; \
29 (ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
30 (ctx).va_list.gp_offset = offsetof(::Common::VaRegSave, gp); \
31 (ctx).va_list.fp_offset = offsetof(::Common::VaRegSave, fp); \
32 (ctx).va_list.overflow_arg_area = &overflow_arg_area;
33 
34namespace Common {
35 
36// https://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure
37 
38struct VaList {
39 u32 gp_offset;
40 u32 fp_offset;
41 void* overflow_arg_area;
42 void* reg_save_area;
43};
44 
45struct VaRegSave {
46 u64 gp[6];
47 __m128 fp[8];
48};
49 
50struct VaCtx {
51 VaRegSave reg_save_area;
52 VaList va_list;
53};
54 
55template <class T, uint32_t Size>
56T vaArgRegSaveAreaGp(VaList* l) {
57 auto* addr = reinterpret_cast<T*>(static_cast<u8*>(l->reg_save_area) + l->gp_offset);
58 l->gp_offset += Size;
59 return *addr;
60}
61template <class T, u64 Align, u64 Size>
62T vaArgOverflowArgArea(VaList* l) {
63 auto ptr = ((reinterpret_cast<u64>(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1));
64 auto* addr = reinterpret_cast<T*>(ptr);
65 l->overflow_arg_area = reinterpret_cast<void*>(ptr + Size);
66 return *addr;
67}
68 
69template <class T, uint32_t Size>
70T vaArgRegSaveAreaFp(VaList* l) {
71 auto* addr = reinterpret_cast<T*>(static_cast<u8*>(l->reg_save_area) + l->fp_offset);
72 l->fp_offset += Size;
73 return *addr;
74}
75 
76inline int vaArgInteger(VaList* l) {
77 if (l->gp_offset <= 40) {
78 return vaArgRegSaveAreaGp<int, 8>(l);
79 }
80 return vaArgOverflowArgArea<int, 1, 8>(l);
81}
82 
83inline long long vaArgLongLong(VaList* l) {
84 if (l->gp_offset <= 40) {
85 return vaArgRegSaveAreaGp<long long, 8>(l);
86 }
87 return vaArgOverflowArgArea<long long, 1, 8>(l);
88}
89inline long vaArgLong(VaList* l) {
90 if (l->gp_offset <= 40) {
91 return vaArgRegSaveAreaGp<long, 8>(l);
92 }
93 return vaArgOverflowArgArea<long, 1, 8>(l);
94}
95 
96inline double vaArgDouble(VaList* l) {
97 if (l->fp_offset <= 160) {
98 return vaArgRegSaveAreaFp<double, 16>(l);
99 }
100 return vaArgOverflowArgArea<double, 1, 8>(l);
101}
102 
103template <class T>
104T* vaArgPtr(VaList* l) {
105 if (l->gp_offset <= 40) {
106 return vaArgRegSaveAreaGp<T*, 8>(l);
107 }
108 return vaArgOverflowArgArea<T*, 1, 8>(l);
109}
110 
111} // namespace Common
112