Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions core/libs/prx/libkernel/Time/Time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@

extern "C" int* APS5_VABI __error_nid_postfix();

static constexpr int GUEST_EFAULT = 14;
static constexpr int GUEST_EINVAL = 22;
static constexpr int GUEST_CLOCK_REALTIME = 0;
static constexpr int GUEST_CLOCK_THREAD_CPUTIME_ID = 14;

static bool IsCpuClock(int clockId) {
Expand Down Expand Up @@ -550,6 +552,20 @@ int APS5_VABI clock_getres_nid_postfix(int clockId, KernelTimespec* res) {
#endif
}

int APS5_VABI clock_settime_nid_postfix(int clockId, const KernelTimespec* tp) {
if (tp == nullptr) {
*__error_nid_postfix() = GUEST_EFAULT;
return -1;
}
if (clockId != GUEST_CLOCK_REALTIME || tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000 || tp->tv_sec < 0) {
*__error_nid_postfix() = GUEST_EINVAL;
return -1;
}
char requested[48];
std::snprintf(requested, sizeof(requested), "%lld.%09lld", static_cast<long long>(tp->tv_sec), static_cast<long long>(tp->tv_nsec));
throw std::runtime_error(std::string("clock_settime: setting CLOCK_REALTIME to ") + requested + " is not supported, the host clock is not changed");
}

// ---------------------------------------------------------------------------
// Moved as-is (not yet implemented) from the monolithic libkernel/Export.cpp.
// ---------------------------------------------------------------------------
Expand Down
38 changes: 38 additions & 0 deletions core/libs/tests/GuestFreebsdClocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdexcept>

extern "C" {
int APS5_VABI clock_gettime_nid_postfix(int clockId, KernelTimespec* tp);
int APS5_VABI clock_getres_nid_postfix(int clockId, KernelTimespec* res);
int APS5_VABI clock_settime_nid_postfix(int clockId, const KernelTimespec* tp);
int APS5_VABI sceKernelClockGettime(KernelClockid clockId, KernelTimespec* tp);
int APS5_VABI sceKernelClockGetres(KernelClockid clockId, KernelTimespec* tp);
int* APS5_VABI __error_nid_postfix();
Expand All @@ -25,7 +27,9 @@ static constexpr int GUEST_CLOCK_REALTIME = 0;
static constexpr int GUEST_CLOCK_VIRTUAL = 1;
static constexpr int GUEST_CLOCK_PROF = 2;
static constexpr int GUEST_CLOCK_MONOTONIC = 4;
static constexpr int GUEST_CLOCK_REALTIME_PRECISE = 9;
static constexpr int GUEST_CLOCK_SECOND = 13;
static constexpr int GUEST_CLOCK_THREAD_CPUTIME_ID = 14;
static constexpr int GUEST_CLOCK_PROCESS_CPUTIME_ID = 15;

static constexpr std::int64_t NANOS_PER_SECOND = 1000000000LL;
Expand Down Expand Up @@ -205,9 +209,43 @@ static void CalendarConversionsInitializeTheirState() {
Require(sceKernelConvertUtcToLocaltime(0, nullptr, nullptr, nullptr) == SCE_OK);
}

static void RequireSettimeError(int clockId, const KernelTimespec* time, int error) {
*__error_nid_postfix() = 0;
Require(clock_settime_nid_postfix(clockId, time) == -1 && *__error_nid_postfix() == error);
}

static bool SettimeThrows(const KernelTimespec& time, const char* requested) {
try {
clock_settime_nid_postfix(GUEST_CLOCK_REALTIME, &time);
} catch (const std::runtime_error& error) {
return std::strstr(error.what(), requested) != nullptr;
}
return false;
}

static void SettimeValidatesLikeFreebsd() {
const KernelTimespec valid{1767225600, 5};
RequireSettimeError(GUEST_CLOCK_REALTIME, nullptr, 14);
RequireSettimeError(GUEST_CLOCK_MONOTONIC, nullptr, 14);
for (const int clockId : {GUEST_CLOCK_VIRTUAL, GUEST_CLOCK_PROF, GUEST_CLOCK_MONOTONIC, GUEST_CLOCK_REALTIME_PRECISE,
GUEST_CLOCK_SECOND, GUEST_CLOCK_THREAD_CPUTIME_ID, GUEST_CLOCK_PROCESS_CPUTIME_ID, -1, 16})
RequireSettimeError(clockId, &valid, 22);
const KernelTimespec negativeNanoseconds{0, -1};
const KernelTimespec wholeSecondOfNanoseconds{0, NANOS_PER_SECOND};
const KernelTimespec negativeSeconds{-1, 0};
RequireSettimeError(GUEST_CLOCK_REALTIME, &negativeNanoseconds, 22);
RequireSettimeError(GUEST_CLOCK_REALTIME, &wholeSecondOfNanoseconds, 22);
RequireSettimeError(GUEST_CLOCK_REALTIME, &negativeSeconds, 22);
RequireSettimeError(GUEST_CLOCK_MONOTONIC, &negativeSeconds, 22);
Require(SettimeThrows(valid, "1767225600.000000005"));
Require(SettimeThrows(KernelTimespec{0, 0}, "0.000000000"));
Require(SettimeThrows(KernelTimespec{1, NANOS_PER_SECOND - 1}, "1.999999999"));
}

int main() {
if (!OmittedResolutionSucceeds()) return 1;
UnsupportedResolutionStillThrows();
SettimeValidatesLikeFreebsd();
CalendarConversionsInitializeTheirState();
SecondClockReportsWholeSeconds();
KernelTimezone zone{-1, -1};
Expand Down
1 change: 1 addition & 0 deletions docs/dev/debt/libkernel.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,4 @@
- [pthread_cond_reltimedwait_np](../../../core/libs/prx/libkernel/Pthread/Posix/Cond.cpp) (libkernel) takes `(cond, mutex, usec)`, a relative timeout in microseconds, and is `scePthreadCondTimedwait` with POSIX error numbers. FreeBSD 11.4 has no such function; the signature comes only from shadPS4, which registers one function for this NID and for `scePthreadCondTimedwait` ([`condvar.cpp`](https://github.com/shadps4-emu/shadPS4/blob/3a9f57265d28975658f1ca941daa5c879c7a74bd/src/core/libraries/kernel/threads/condvar.cpp#L229-L234)). shadPS4 reads a 64-bit count; here it is the 32-bit `SceKernelUseconds` of the SCE twin, as for `sem_reltimedwait_np`. Unverified on the console
- [sysctl kern.arandom](../../../core/libs/prx/libkernel/System/src/SystemConfiguration.cpp) (libkernel) serves FreeBSD 11's MIB {1, 37} (CTL_KERN, KERN_ARANDOM) and the "kern.arandom" sysctlbyname lookup through std::random_device, returning min(*oldLength, 256) random bytes. Following FreeBSD's sysctl_kern_arnd, a null buffer reports min(*oldLength, 256) without writing, a null length returns 0 without writing, and requests with a new value return EPERM (1) as the node is read-only. Cryptographic quality depends on the host's random device implementation.
- [sceKernelGetPageTableStats](../../../core/libs/prx/libkernel/DirectMemory/Export.cpp) (libkernel) - reports 2048 page-table entries on each side (a 4 GiB pool of 2 MiB entries, the constants of [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/main/src/kernel/memory.cpp)) and all of them available: no entries are counted as used, so a title never sees page-table pressure. KytyPS5 counts the 2 MiB entries of the committed CPU- or GPU-accessible ranges as used, which this port does not do. The four `int*` arguments follow OpenOrbis' `libkernel.h`, the Orbital type database and SharpProspero; a null pointer returns `SCE_KERNEL_ERROR_EFAULT` as in KytyPS5. None of the values is measured on a console. PPSA30601 (Resonance) calls it during start-up
- [clock_settime](../../../core/libs/prx/libkernel/Time/Time.cpp) (libkernel) validates like FreeBSD 11.4's [`kern_clock_settime`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/sys/kern/kern_time.c#L396-L412) for a root caller: `EFAULT` for a null time, `EINVAL` for any clock but `CLOCK_REALTIME`, a negative second count or a nanosecond count outside 0 to 999999999. A valid `CLOCK_REALTIME` request throws, naming the requested time, since the host clock is never set and no guest clock offset is kept. FreeBSD checks `PRIV_CLOCK_SETTIME` first, which a jailed process fails with `EPERM`; whether a title holds it on the console is unverified. PS5MC (PPSA99420) imports it; no call site is known
Loading