mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-07 13:39:55 +00:00
138 lines
4.9 KiB
C++
138 lines
4.9 KiB
C++
#include "prx/libc/include/Api.hpp"
|
|
#include "prx/libc/include/General.hpp"
|
|
#include "prx/libkernel/include/Api.hpp"
|
|
#include <climits>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#else
|
|
#include <sys/mman.h>
|
|
#endif
|
|
|
|
static void Check(bool condition, int line) {
|
|
if (condition) return;
|
|
std::fprintf(stderr, "timespec_getres check failed at line %d\n", line);
|
|
std::abort();
|
|
}
|
|
#define Require(condition) Check((condition), __LINE__)
|
|
|
|
static int calls, observedClock, response, errorToSet;
|
|
static KernelTimespec* observedPointer;
|
|
static KernelTimespec resolution;
|
|
static bool writeResolution;
|
|
|
|
static int APS5_VABI ClockResolution(int clock, KernelTimespec* output) {
|
|
++calls;
|
|
observedClock = clock;
|
|
observedPointer = output;
|
|
if (output != nullptr && writeResolution) *output = resolution;
|
|
*__error_nid_postfix() = errorToSet;
|
|
return response;
|
|
}
|
|
|
|
static void Mock(int result, bool write, KernelTimespec value = {0, 100}) {
|
|
calls = 0;
|
|
observedClock = -1;
|
|
observedPointer = nullptr;
|
|
response = result;
|
|
writeResolution = write;
|
|
resolution = value;
|
|
errorToSet = 71;
|
|
RegisterClockGetres_nid_no_patch(&ClockResolution);
|
|
}
|
|
|
|
static void Unsupported() {
|
|
Mock(0, true);
|
|
#ifdef _WIN32
|
|
auto* guard = static_cast<KernelTimespec*>(VirtualAlloc(nullptr, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS));
|
|
Require(guard != nullptr);
|
|
#else
|
|
auto* guard = static_cast<KernelTimespec*>(mmap(nullptr, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
|
Require(guard != MAP_FAILED);
|
|
#endif
|
|
KernelTimespec value{123, 456};
|
|
const auto checkBase = [&](int base) {
|
|
if (base == 1) return;
|
|
for (auto* output : {&value, guard, static_cast<KernelTimespec*>(nullptr)}) {
|
|
*__error_nid_postfix() = 97;
|
|
Require(timespec_getres_nid_postfix(output, base) == 0);
|
|
Require(*__error_nid_postfix() == 97 && calls == 0);
|
|
Require(value.tv_sec == 123 && value.tv_nsec == 456);
|
|
}
|
|
};
|
|
for (int base = -4096; base <= 4096; ++base) checkBase(base);
|
|
checkBase(INT_MIN);
|
|
checkBase(INT_MAX);
|
|
#ifdef _WIN32
|
|
VirtualFree(guard, 0, MEM_RELEASE);
|
|
#else
|
|
munmap(guard, 4096);
|
|
#endif
|
|
}
|
|
|
|
struct Frame {
|
|
std::uint64_t before;
|
|
KernelTimespec value;
|
|
std::uint64_t after;
|
|
};
|
|
|
|
static void CheckForward(int result, bool write, bool null, KernelTimespec value) {
|
|
Mock(result, write, value);
|
|
Frame frame{0x123456789ABCDEF0, {123, 456}, 0xFEDCBA9876543210};
|
|
auto* output = null ? nullptr : &frame.value;
|
|
*__error_nid_postfix() = 97;
|
|
Require(timespec_getres_nid_postfix(output, 1) == (result == 0 ? 1 : 0));
|
|
Require(calls == 1 && observedClock == 0 && observedPointer == output);
|
|
Require(*__error_nid_postfix() == 71);
|
|
const auto expected = !null && write ? value : KernelTimespec{123, 456};
|
|
Require(frame.value.tv_sec == expected.tv_sec && frame.value.tv_nsec == expected.tv_nsec);
|
|
Require(frame.before == 0x123456789ABCDEF0 && frame.after == 0xFEDCBA9876543210);
|
|
}
|
|
|
|
static void Forwarding() {
|
|
for (const auto value : {KernelTimespec{0, 1}, KernelTimespec{2, 999999999},
|
|
KernelTimespec{INT64_MIN, INT64_MAX}}) {
|
|
for (const bool null : {false, true}) CheckForward(0, true, null, value);
|
|
}
|
|
CheckForward(0, false, false, {0, 100});
|
|
}
|
|
|
|
static void Errors() {
|
|
for (const int result : {-1, 1, INT_MIN, INT_MAX, static_cast<int>(0x8002000E)}) {
|
|
for (const bool write : {false, true}) {
|
|
for (const bool null : {false, true}) CheckForward(result, write, null, {7, 7654321});
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Integration() {
|
|
KernelTimespec expected{};
|
|
Require(sceKernelClockGetres(0, &expected) == 0);
|
|
Require(expected.tv_sec >= 0 && expected.tv_nsec >= 0 && expected.tv_nsec < 1000000000);
|
|
for (int index = 0; index < 1024; ++index) {
|
|
Frame frame{0x123456789ABCDEF0, {-1, -1}, 0xFEDCBA9876543210};
|
|
*__error_nid_postfix() = 97;
|
|
Require(timespec_getres_nid_postfix(&frame.value, 1) == 1);
|
|
Require(*__error_nid_postfix() == 97);
|
|
Require(frame.value.tv_sec == expected.tv_sec && frame.value.tv_nsec == expected.tv_nsec);
|
|
Require(frame.before == 0x123456789ABCDEF0 && frame.after == 0xFEDCBA9876543210);
|
|
}
|
|
const int nullResult = sceKernelClockGetres(0, nullptr) == 0 ? 1 : 0;
|
|
Require(timespec_getres_nid_postfix(nullptr, 1) == nullResult);
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
Require(argc == 2);
|
|
if (std::strcmp(argv[1], "unsupported") == 0) Unsupported();
|
|
else if (std::strcmp(argv[1], "forwarding") == 0) Forwarding();
|
|
else if (std::strcmp(argv[1], "errors") == 0) Errors();
|
|
else if (std::strcmp(argv[1], "integration") == 0) Integration();
|
|
else Require(false);
|
|
RegisterClockGetres_nid_no_patch(&sceKernelClockGetres);
|
|
std::puts("timespec_getres bases, delegation, errors and kernel integration passed");
|
|
}
|