Files
AnyPS5/core/libs/tests/GuestSysarch.cpp
T
milescovielloandClaude Opus 5.5 d7c83db2a5 feat(libkernel): read and set the GS base through sysarch
sysarch's AMD64_GET_FSBASE, AMD64_GET_GSBASE and AMD64_SET_GSBASE now
follow FreeBSD 11's amd64 sysarch on Linux x86-64 through arch_prctl: the
GS base is the calling thread's, a base at or above VM_MAXUSER_ADDRESS
returns EINVAL and a null argument EFAULT. AMD64_SET_FSBASE, whose base
guest and host code share for their TLS, other operations and other hosts
still throw. Wine sets its TEB this way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:43:32 +00:00

56 lines
1.9 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
#include <stdexcept>
#include <string>
extern "C" {
int APS5_VABI sysarch(int number, void* args);
int* APS5_VABI __error_nid_postfix();
}
static void Require(bool value) { if (!value) std::abort(); }
template <typename TCall> static std::string Thrown(TCall call) {
try {
call();
} catch (const std::runtime_error& error) {
return error.what();
}
return {};
}
int main() {
Require(Thrown([] { sysarch(129, nullptr); }) == "sysarch: operation 129 not implemented");
Require(Thrown([] { sysarch(7, nullptr); }) == "sysarch: operation 7 not implemented");
#if defined(__linux__) && defined(__x86_64__)
static std::uint64_t slots[2] = {0x1234567890abcdefull, 0};
std::uint64_t base = reinterpret_cast<std::uintptr_t>(slots);
Require(sysarch(131, &base) == 0);
std::uint64_t read = 0;
Require(sysarch(130, &read) == 0 && read == base);
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);
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);
Require(sysarch(130, nullptr) == -1 && *__error_nid_postfix() == 14);
std::uint64_t zero = 0;
Require(sysarch(131, &zero) == 0 && sysarch(130, &read) == 0 && read == 0);
#else
std::uint64_t base = 0;
Require(Thrown([&base] { sysarch(130, &base); }) == "sysarch: segment bases on this host not implemented");
#endif
return 0;
}