#include "prx/libkernel/include/Api.hpp" #include "prx/libc/include/Api.hpp" #include "SceTypes.hpp" #include #include #include static void Require(bool value) { if (!value) std::abort(); } #if (defined(__linux__) || defined(_WIN32)) && defined(__x86_64__) static void* APS5_VABI ReadGsBase(void* arg) { auto* read = static_cast(arg); if (sysarch(130, read) != 0) *read = 0; return nullptr; } static void RequireLowHalf(int operation, std::uint64_t base) { unsigned char bytes[8]; std::memset(bytes, 0xaa, sizeof(bytes)); Require(sysarch(operation, bytes) == 0); std::uint32_t low = 0; std::memcpy(&low, bytes, sizeof(low)); Require(low == static_cast(base)); for (int i = 4; i < 8; ++i) Require(bytes[i] == 0xaa); } struct ThreadBases { std::uint64_t expected; std::uint64_t replacement; }; static void* APS5_VABI ChangeGsBase(void* arg) { auto& bases = *static_cast(arg); std::uint64_t read = 0; Require(sysarch(130, &read) == 0 && read == bases.expected); Require(sysarch(131, &bases.replacement) == 0); Require(sysarch(130, &read) == 0 && read == bases.replacement); RequireLowHalf(9, read); Pthread nested = nullptr; std::uint64_t inherited = 0; Require(pthread_create_nid_postfix(&nested, nullptr, ReadGsBase, &inherited) == 0); Require(pthread_join_nid_postfix(nested, nullptr) == 0 && inherited == bases.replacement); return nullptr; } #endif int main() { for (const int operation : {2, 5, 6, 12, 127, 133, 134, 1000, -1}) { *__error_nid_postfix() = 0; Require(sysarch(operation, nullptr) == -1 && *__error_nid_postfix() == 22); } #if (defined(__linux__) || defined(_WIN32)) && defined(__x86_64__) static std::uint64_t slots[2] = {0x1234567890abcdefull, 0}; std::uint64_t base = reinterpret_cast(slots); Require(sysarch(131, &base) == 0); std::uint64_t read = 0; Require(sysarch(130, &read) == 0 && read == base); #ifdef __linux__ std::uint64_t through = 0; asm volatile("movq %%gs:0, %0" : "=r"(through)); Require(through == slots[0]); std::uint64_t fs = 0; Require(sysarch(128, &fs) == 0 && fs != 0); std::uint64_t self = 0; asm volatile("movq %%fs:0, %0" : "=r"(self)); Require(self == fs); RequireLowHalf(7, fs); *__error_nid_postfix() = 0; Require(sysarch(7, nullptr) == -1 && *__error_nid_postfix() == 14); #endif RequireLowHalf(9, base); *__error_nid_postfix() = 0; Require(sysarch(9, nullptr) == -1 && *__error_nid_postfix() == 14); void* const bad = reinterpret_cast(static_cast(0x10)); #ifdef __linux__ *__error_nid_postfix() = 0; Require(sysarch(7, bad) == -1 && *__error_nid_postfix() == 14); #endif *__error_nid_postfix() = 0; Require(sysarch(9, bad) == -1 && *__error_nid_postfix() == 14); *__error_nid_postfix() = 0; Require(sysarch(128, nullptr) == -1 && *__error_nid_postfix() == 14); #ifdef __linux__ *__error_nid_postfix() = 0; Require(sysarch(128, bad) == -1 && *__error_nid_postfix() == 14); #endif *__error_nid_postfix() = 0; Require(sysarch(130, bad) == -1 && *__error_nid_postfix() == 14); std::uint64_t inherited = 0; Pthread child = nullptr; Require(scePthreadCreate(&child, nullptr, ReadGsBase, &inherited, "sysarch_gs") == 0); Require(scePthreadJoin(child, nullptr) == 0 && inherited == base); ThreadBases bases{base, 0x0000123456789abcull}; Require(scePthreadCreate(&child, nullptr, ChangeGsBase, &bases, "sysarch_change") == 0); Require(scePthreadJoin(child, nullptr) == 0); Require(sysarch(130, &read) == 0 && read == base); Require(pthread_create_nid_postfix(&child, nullptr, ChangeGsBase, &bases) == 0); Require(pthread_join_nid_postfix(child, nullptr) == 0); Require(sysarch(130, &read) == 0 && read == base); std::uint64_t outside = 0x0000800000000000ull; *__error_nid_postfix() = 0; Require(sysarch(131, &outside) == -1 && *__error_nid_postfix() == 22); Require(sysarch(130, &read) == 0 && read == base); *__error_nid_postfix() = 0; Require(sysarch(131, nullptr) == -1 && *__error_nid_postfix() == 14); *__error_nid_postfix() = 0; Require(sysarch(131, bad) == -1 && *__error_nid_postfix() == 14); *__error_nid_postfix() = 0; Require(sysarch(130, nullptr) == -1 && *__error_nid_postfix() == 14); Require(sysarch(131, reinterpret_cast(1)) == -1 && *__error_nid_postfix() == 14); Require(sysarch(130, reinterpret_cast(1)) == -1 && *__error_nid_postfix() == 14); Require(sysarch(9, reinterpret_cast(1)) == -1 && *__error_nid_postfix() == 14); Require(sysarch(130, &read) == 0 && read == base); std::uint64_t zero = 0; Require(sysarch(131, &zero) == 0 && sysarch(130, &read) == 0 && read == 0); #endif return 0; }