Files
AnyPS5/core/libs/tests/GuestSystemConfiguration.cpp
T
Zayd Zaari ed56cff790 fix(libkernel): accept measured system version record values
Preserve the leading field and bytes after the 40-byte legacy version record for the values measured in four PS5 firmware 13.42 hardware runs. Keep the emulator version policy unchanged and leave the separately proposed Prospero correction out of scope.

AI-assisted; regression tests are based on guarded hardware measurements.
2026-10-12 19:02:03 +00:00

252 lines
12 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libkernel/KernelErrors.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
struct SceKernelSystemSwVersion {
std::uint64_t size;
char versionString[0x1C];
std::uint32_t version;
};
static_assert(offsetof(SceKernelSystemSwVersion, size) == 0x00);
static_assert(offsetof(SceKernelSystemSwVersion, versionString) == 0x08);
static_assert(offsetof(SceKernelSystemSwVersion, version) == 0x24);
static_assert(sizeof(SceKernelSystemSwVersion) == 0x28);
extern "C" {
std::int64_t APS5_VABI sysconf_nid_postfix(int);
int APS5_VABI getpagesize_nid_postfix();
int* APS5_VABI __error_nid_postfix();
int APS5_VABI sysctl_nid_postfix(const int*, std::uint32_t, void*, std::size_t*, const void*, std::size_t);
int APS5_VABI sysctlbyname_nid_postfix(const char*, void*, std::size_t*, const void*, std::size_t);
int APS5_VABI sceKernelGetSystemSwVersion_nid_postfix(SceKernelSystemSwVersion*);
int APS5_VABI getpid_nid_postfix();
extern char** environ_nid_postfix;
}
static void Require(bool value) { if (!value) std::abort(); }
static void CheckProcessorCountSysctl() {
const int mib[] = {6, 3};
const int processors = static_cast<int>(sysconf_nid_postfix(58));
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == sizeof(int));
int value = 0;
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, nullptr, 0) == 0 && value == processors && length == sizeof(int));
value = 0;
length = 16;
Require(sysctlbyname_nid_postfix("hw.ncpu", &value, &length, nullptr, 0) == 0 && value == processors && length == sizeof(int));
Require(*__error_nid_postfix() == 13);
unsigned char bytes[4] = {0xaa, 0xaa, 0xaa, 0xaa};
length = 2;
Require(sysctlbyname_nid_postfix("hw.ncpu", bytes, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 2 && bytes[2] == 0xaa && bytes[3] == 0xaa);
Require(sysctl_nid_postfix(mib, 2, bytes, nullptr, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
Require(sysctl_nid_postfix(mib, 1, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
Require(sysctl_nid_postfix(mib, 25, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
Require(sysctl_nid_postfix(nullptr, 2, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 14);
Require(sysctlbyname_nid_postfix(nullptr, &value, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 14);
bool threw = false;
try {
sysctlbyname_nid_postfix("kern.osreldate", &value, &length, nullptr, 0);
} catch (const std::runtime_error&) {
threw = true;
}
Require(threw);
threw = false;
const int unknown[] = {6, 99};
try {
sysctl_nid_postfix(unknown, 2, &value, &length, nullptr, 0);
} catch (const std::runtime_error&) {
threw = true;
}
Require(threw);
}
static void CheckPhysicalMemorySysctl() {
const int mib[] = {6, 5};
const std::uint64_t expected = static_cast<std::uint64_t>(sysconf_nid_postfix(121)) * 0x4000;
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == sizeof(std::uint64_t));
std::uint64_t value = 0;
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, nullptr, 0) == 0 && value == expected && length == sizeof(std::uint64_t));
value = 0;
length = 16;
Require(sysctlbyname_nid_postfix("hw.physmem", &value, &length, nullptr, 0) == 0 && value == expected && length == sizeof(std::uint64_t));
Require(*__error_nid_postfix() == 13);
unsigned char bytes[8] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
length = 4;
Require(sysctlbyname_nid_postfix("hw.physmem", bytes, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 4 && bytes[4] == 0xaa);
length = sizeof(value);
Require(sysctl_nid_postfix(mib, 2, &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
Require(sysctlbyname_nid_postfix("hw.physmem", &value, &length, &value, sizeof(value)) == -1 && *__error_nid_postfix() == 1);
}
static void CheckMachdepCachelineSizeSysctl() {
*__error_nid_postfix() = 13;
int value = 0x5a5a5a5a;
std::size_t length = sizeof(value);
Require(sysctlbyname_nid_postfix("machdep.cacheline_size", &value, &length, nullptr, 0) == -1);
Require(*__error_nid_postfix() == 2);
Require(value == 0x5a5a5a5a);
}
static void CheckPathnameSysctl() {
*__error_nid_postfix() = 13;
char buffer[32] = {};
std::size_t length = sizeof(buffer);
Require(sysctlbyname_nid_postfix("kern.proc.pathname", buffer, &length, nullptr, 0) == -1);
Require(*__error_nid_postfix() == 22);
const int mibTooShort[] = {1, 14, 12};
Require(sysctl_nid_postfix(mibTooShort, 3, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
const int mibTooLong[] = {1, 14, 12, -1, 0};
Require(sysctl_nid_postfix(mibTooLong, 5, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 22);
const int mibSelf[] = {1, 14, 12, -1};
length = 0;
Require(sysctl_nid_postfix(mibSelf, 4, nullptr, &length, nullptr, 0) == 0 && length == sizeof("/app0/eboot.bin"));
std::memset(buffer, 0xaa, sizeof(buffer));
length = sizeof(buffer);
Require(sysctl_nid_postfix(mibSelf, 4, buffer, &length, nullptr, 0) == 0);
Require(length == sizeof("/app0/eboot.bin"));
Require(std::strcmp(buffer, "/app0/eboot.bin") == 0);
const int callerPid = getpid_nid_postfix();
const int mibPid[] = {1, 14, 12, callerPid};
std::memset(buffer, 0xaa, sizeof(buffer));
length = sizeof(buffer);
Require(sysctl_nid_postfix(mibPid, 4, buffer, &length, nullptr, 0) == 0);
Require(length == sizeof("/app0/eboot.bin"));
Require(std::strcmp(buffer, "/app0/eboot.bin") == 0);
const int mibForeign[] = {1, 14, 12, callerPid + 1000};
Require(sysctl_nid_postfix(mibForeign, 4, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 3);
length = 5;
std::memset(buffer, 0xaa, sizeof(buffer));
Require(sysctl_nid_postfix(mibSelf, 4, buffer, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 5 && buffer[4] == '0' && buffer[5] == static_cast<char>(0xaa));
length = sizeof(buffer);
Require(sysctl_nid_postfix(mibSelf, 4, buffer, &length, buffer, sizeof(buffer)) == -1 && *__error_nid_postfix() == 1);
}
static void CheckSystemSwVersion() {
*__error_nid_postfix() = 13;
Require(sceKernelGetSystemSwVersion_nid_postfix(nullptr) == SCE_KERNEL_ERROR_EFAULT && *__error_nid_postfix() == 13);
const std::uint64_t sizes[] = {0, 24, 39, 40, 41, 48, 64};
for (const std::uint64_t size : sizes) {
struct {
std::uint64_t prefix;
SceKernelSystemSwVersion version;
unsigned char suffix[88];
} storage;
std::memset(&storage, 0xaa, sizeof(storage));
storage.version.size = size;
*__error_nid_postfix() = 13;
Require(sceKernelGetSystemSwVersion_nid_postfix(&storage.version) == 0 && *__error_nid_postfix() == 13);
Require(storage.prefix == 0xaaaaaaaaaaaaaaaaull && storage.version.size == size);
Require(std::strcmp(storage.version.versionString, "01.000.000") == 0);
for (std::size_t i = sizeof("01.000.000"); i < sizeof(storage.version.versionString); ++i) {
Require(storage.version.versionString[i] == 0);
}
Require(storage.version.version == 0x01000000);
for (unsigned char byte : storage.suffix) Require(byte == 0xaa);
}
}
static void CheckPseudoRandomSysctl() {
*__error_nid_postfix() = 13;
unsigned char first[64] = {};
unsigned char second[64] = {};
std::size_t length = sizeof(first);
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", first, &length, nullptr, 0) == 0 && length == sizeof(first));
length = sizeof(second);
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", second, &length, nullptr, 0) == 0 && length == sizeof(second));
Require(std::memcmp(first, second, sizeof(first)) != 0);
Require(*__error_nid_postfix() == 13);
Require(sysctlbyname_nid_postfix("kern.rng_pseudo", first, &length, first, sizeof(first)) == -1 && *__error_nid_postfix() == 1);
bool threw = false;
try {
sysctlbyname_nid_postfix("kern.rng_pseudo", nullptr, &length, nullptr, 0);
} catch (const std::runtime_error&) {
threw = true;
}
Require(threw);
}
static void CheckSdkVersionSysctl() {
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctlbyname_nid_postfix("kern.sdk_version", nullptr, &length, nullptr, 0) == 0 && length == sizeof(std::uint32_t));
std::uint32_t version = 0;
length = sizeof(version);
Require(sysctlbyname_nid_postfix("kern.sdk_version", &version, &length, nullptr, 0) == 0 && version == 0x01000000 && length == sizeof(std::uint32_t));
Require(*__error_nid_postfix() == 13);
unsigned char bytes[4] = {0xaa, 0xaa, 0xaa, 0xaa};
length = 2;
Require(sysctlbyname_nid_postfix("kern.sdk_version", bytes, &length, nullptr, 0) == -1 && *__error_nid_postfix() == 12);
Require(length == 2 && bytes[2] == 0xaa && bytes[3] == 0xaa);
length = sizeof(version);
Require(sysctlbyname_nid_postfix("kern.sdk_version", &version, &length, &version, sizeof(version)) == -1 && *__error_nid_postfix() == 1);
}
static void CheckArandomSysctl() {
const int mib[] = {1, 37};
*__error_nid_postfix() = 13;
std::size_t length = 0;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == 0);
length = 64;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == 64);
length = 300;
Require(sysctl_nid_postfix(mib, 2, nullptr, &length, nullptr, 0) == 0 && length == 256);
Require(sysctl_nid_postfix(mib, 2, nullptr, nullptr, nullptr, 0) == 0);
Require(*__error_nid_postfix() == 13);
unsigned char first[64] = {};
unsigned char second[64] = {};
length = sizeof(first);
Require(sysctl_nid_postfix(mib, 2, first, &length, nullptr, 0) == 0 && length == sizeof(first));
length = sizeof(second);
Require(sysctl_nid_postfix(mib, 2, second, &length, nullptr, 0) == 0 && length == sizeof(second));
Require(std::memcmp(first, second, sizeof(first)) != 0);
Require(*__error_nid_postfix() == 13);
unsigned char named[64] = {};
length = sizeof(named);
Require(sysctlbyname_nid_postfix("kern.arandom", named, &length, nullptr, 0) == 0 && length == sizeof(named));
Require(*__error_nid_postfix() == 13);
length = sizeof(first);
Require(sysctl_nid_postfix(mib, 2, first, &length, first, sizeof(first)) == -1 && *__error_nid_postfix() == 1);
*__error_nid_postfix() = 13;
unsigned char big[300] = {};
length = sizeof(big);
Require(sysctl_nid_postfix(mib, 2, big, &length, nullptr, 0) == 0 && length == 256);
unsigned char small[16] = {};
length = sizeof(small);
Require(sysctl_nid_postfix(mib, 2, small, &length, nullptr, 0) == 0 && length == sizeof(small));
Require(sysctl_nid_postfix(mib, 2, first, nullptr, nullptr, 0) == 0);
Require(*__error_nid_postfix() == 13);
}
int main() {
CheckProcessorCountSysctl();
CheckPhysicalMemorySysctl();
CheckMachdepCachelineSizeSysctl();
CheckPathnameSysctl();
CheckSystemSwVersion();
CheckPseudoRandomSysctl();
CheckSdkVersionSysctl();
CheckArandomSysctl();
*__error_nid_postfix() = 13;
Require(sysconf_nid_postfix(47) == 0x4000);
Require(getpagesize_nid_postfix() == sysconf_nid_postfix(47));
Require(sysconf_nid_postfix(57) > 0);
Require(sysconf_nid_postfix(58) > 0);
Require(sysconf_nid_postfix(121) > 0);
Require(*__error_nid_postfix() == 13);
Require(sysconf_nid_postfix(-1) == -1); // verifies full-width signed return
Require(*__error_nid_postfix() == 22);
Require(sysconf_nid_postfix(0x7fffffff) == -1);
Require(environ_nid_postfix && !environ_nid_postfix[0]);
}