mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
Merge pull request #9682 from Gruzzberry/feat/settimeofday
feat(libkernel_sys): implement settimeofday
This commit is contained in:
6 files changed
+57
-8
No files matched your search
@@ -541,6 +541,9 @@ int APS5_VABI clock_gettime_nid_postfix(int clockId, KernelTimespec* tp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::mutex guestTimezoneMutex;
|
||||
static KernelTimezone guestTimezone{0, 0};
|
||||
|
||||
int APS5_VABI gettimeofday_nid_postfix(KernelTimeval* tv, KernelTimezone* tz) {
|
||||
KernelTimeval ignoredTime{};
|
||||
if (tv == nullptr) tv = &ignoredTime;
|
||||
@@ -560,8 +563,8 @@ int APS5_VABI gettimeofday_nid_postfix(KernelTimeval* tv, KernelTimezone* tz) {
|
||||
tv->tv_usec = static_cast<std::int64_t>(native.tv_usec);
|
||||
#endif
|
||||
if (tz != nullptr) {
|
||||
tz->tz_minuteswest = 0;
|
||||
tz->tz_dsttime = 0;
|
||||
std::lock_guard lock(guestTimezoneMutex);
|
||||
*tz = guestTimezone;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -664,6 +667,23 @@ int APS5_VABI clock_settime_nid_postfix(int clockId, const KernelTimespec* tp) {
|
||||
throw std::runtime_error(std::string("clock_settime: setting CLOCK_REALTIME to ") + requested + " is not supported, the host clock is not changed");
|
||||
}
|
||||
|
||||
int SetTimeOfDay_nid_no_patch(const KernelTimeval* tv, const KernelTimezone* tz) {
|
||||
if (tv != nullptr && (tv->tv_usec < 0 || tv->tv_usec >= 1000000 || tv->tv_sec < 0)) {
|
||||
*__error_nid_postfix() = GUEST_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (tv != nullptr) {
|
||||
char requested[48];
|
||||
std::snprintf(requested, sizeof(requested), "%lld.%06lld", static_cast<long long>(tv->tv_sec), static_cast<long long>(tv->tv_usec));
|
||||
throw std::runtime_error(std::string("settimeofday: setting the time to ") + requested + " is not supported, the host clock is not changed");
|
||||
}
|
||||
if (tz != nullptr) {
|
||||
std::lock_guard lock(guestTimezoneMutex);
|
||||
guestTimezone = *tz;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Moved as-is (not yet implemented) from the monolithic libkernel/Export.cpp.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -2299,11 +2299,6 @@ int APS5_VABI setlogin_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI settimeofday_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sigqueue_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -515,6 +515,12 @@ int APS5_VABI fchdir_nid_postfix(int fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetTimeOfDay_nid_no_patch(const KernelTimeval* tv, const KernelTimezone* tz);
|
||||
|
||||
int APS5_VABI settimeofday_nid_postfix(const KernelTimeval* tv, const KernelTimezone* tz) {
|
||||
return SetTimeOfDay_nid_no_patch(tv, tz);
|
||||
}
|
||||
|
||||
int APS5_VABI chroot_nid_postfix(const char* path) {
|
||||
std::string copy;
|
||||
if (const int error = CopyPath(path, copy)) return static_cast<int>(Fail(error));
|
||||
|
||||
@@ -62,6 +62,7 @@ int APS5_VABI chown_nid_postfix(const char* path, std::uint32_t uid, std::uint32
|
||||
int APS5_VABI lchown_nid_postfix(const char* path, std::uint32_t uid, std::uint32_t gid);
|
||||
int APS5_VABI fchownat_nid_postfix(int fd, const char* path, std::uint32_t uid, std::uint32_t gid, int flag);
|
||||
int APS5_VABI fstatat_nid_postfix(int fd, const char* path, FileStat* sb, int flag);
|
||||
int APS5_VABI settimeofday_nid_postfix(const KernelTimeval* tv, const KernelTimezone* tz);
|
||||
int APS5_VABI unlinkat_nid_postfix(int fd, const char* path, int flag);
|
||||
int APS5_VABI scePthreadCondattrGetclock(const PthreadCondattr* attr, KernelClockid* clockId);
|
||||
int APS5_VABI renameat_nid_postfix(int oldfd, const char* from, int newfd, const char* to);
|
||||
@@ -533,7 +534,6 @@ int APS5_VABI sched_setscheduler_nid_postfix(void);
|
||||
int APS5_VABI sem_setname_nid_postfix(void);
|
||||
int APS5_VABI set_phys_fmem_limit_nid_postfix(void);
|
||||
int APS5_VABI setlogin_nid_postfix(void);
|
||||
int APS5_VABI settimeofday_nid_postfix(void);
|
||||
int APS5_VABI sigqueue_nid_postfix(void);
|
||||
int APS5_VABI sigreturn_nid_postfix(void);
|
||||
int APS5_VABI statfs_nid_postfix(void);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "prx/libkernel_sys/include/Api.hpp"
|
||||
#include "prx/libkernel/include/Api.hpp"
|
||||
#include "prx/libkernel/Pthread/include/Cond.hpp"
|
||||
#include "prx/libkernel/Time/include/Time.hpp"
|
||||
#include "prx/libkernel/File/include/File.hpp"
|
||||
#include "prx/libc/include/Api.hpp"
|
||||
#include "SceTypes.hpp"
|
||||
@@ -378,6 +379,31 @@ void CheckPathconf(const std::filesystem::path& root, const std::string& file) {
|
||||
Require(pathconf_nid_postfix(longPath.c_str(), 4) == -1 && Error() == 63);
|
||||
}
|
||||
|
||||
void CheckSettimeofday() {
|
||||
KernelTimezone zone{-1, -1};
|
||||
Require(settimeofday_nid_postfix(nullptr, nullptr) == 0);
|
||||
Require(gettimeofday_nid_postfix(nullptr, &zone) == 0 && zone.tz_minuteswest == 0 && zone.tz_dsttime == 0);
|
||||
const KernelTimezone west{60, 1};
|
||||
for (const KernelTimeval invalid : {KernelTimeval{0, 1000000}, KernelTimeval{0, -1}, KernelTimeval{-1, 0}})
|
||||
Require(settimeofday_nid_postfix(&invalid, &west) == -1 && Error() == 22);
|
||||
Require(gettimeofday_nid_postfix(nullptr, &zone) == 0 && zone.tz_minuteswest == 0 && zone.tz_dsttime == 0);
|
||||
const KernelTimeval valid{1000000000, 0};
|
||||
bool rejected = false;
|
||||
try {
|
||||
settimeofday_nid_postfix(&valid, &west);
|
||||
} catch (const std::runtime_error& error) {
|
||||
rejected = std::strstr(error.what(), "settimeofday: setting the time to 1000000000.000000") != nullptr;
|
||||
}
|
||||
Require(rejected);
|
||||
Require(gettimeofday_nid_postfix(nullptr, &zone) == 0 && zone.tz_minuteswest == 0 && zone.tz_dsttime == 0);
|
||||
Require(settimeofday_nid_postfix(nullptr, &west) == 0);
|
||||
KernelTimeval now{};
|
||||
Require(gettimeofday_nid_postfix(&now, &zone) == 0 && zone.tz_minuteswest == 60 && zone.tz_dsttime == 1 && now.tv_sec > 0);
|
||||
const KernelTimezone zero{0, 0};
|
||||
Require(settimeofday_nid_postfix(nullptr, &zero) == 0);
|
||||
Require(gettimeofday_nid_postfix(nullptr, &zone) == 0 && zone.tz_minuteswest == 0 && zone.tz_dsttime == 0);
|
||||
}
|
||||
|
||||
void DirectoryRenameTests(const std::filesystem::path& parent) {
|
||||
const auto fixture = parent / "directory-identity";
|
||||
const auto original = fixture / "original";
|
||||
@@ -711,6 +737,7 @@ int main() {
|
||||
Require(link_nid_postfix(nullptr, linked.c_str()) == -1 && Error() == 14);
|
||||
Require(link_nid_postfix(original.c_str(), "") == -1 && Error() == 2);
|
||||
Require(std::filesystem::remove(linked) && std::filesystem::hard_link_count(original) == 1);
|
||||
CheckSettimeofday();
|
||||
const int directory = sceKernelOpen(root.string().c_str(), SCE_KERNEL_O_RDONLY | SCE_KERNEL_O_DIRECTORY, 0);
|
||||
Require(directory >= 0);
|
||||
const int fileDescriptor = sceKernelOpen(file.c_str(), SCE_KERNEL_O_RDONLY, 0);
|
||||
|
||||
@@ -286,6 +286,7 @@
|
||||
- [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.
|
||||
- [pthread_atfork](../../../core/libs/prx/libkernel/Pthread/Posix/Atfork.cpp) (libkernel) appends the three handlers to a process-wide list and returns 0, or `ENOMEM` when the entry cannot be allocated, as FreeBSD 11.4's [`_pthread_atfork`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/lib/libthr/thread/thr_fork.c#L78-L100) does; null handlers are accepted. The handlers never run: `fork` throws and `vfork` is absent, so no child process is created. Handlers of a module that is unloaded stay in the list, where FreeBSD's `__pthread_cxa_finalize` removes them. PPSA97358 has a source-level call from the constructor `rcu_init` ([rcu.c](https://github.com/ZiZc3/XPSemu/blob/8eec07b4e31f66dce8e0b05c1ca1281af303e933/util/rcu.c#L488-L495)), but current-main runtime reachability is unverified
|
||||
- [sceKernelGetPageTableStats](../../../core/libs/prx/libkernel/DirectMemory/Export.cpp) (libkernel) reports 8192 entries on each side and counts them as a PS5 (firmware 13.60) counted them for a payload process: one cpu entry for each 2 MiB granule that holds a committed mapping, whatever its protection (none included), and one gpu entry for each 1 GiB region that holds a GPU-accessible mapping, plus one for each 2 MiB granule of such a mapping that is not a whole granule of direct memory at a 2 MiB-aligned physical address. A granule or region shared by several mappings counts once, and reservations do not count. On the console the first GPU mapping of a process also takes three gpu entries and one cpu entry that stay after it is unmapped, which is not modelled, and only the ranges whose protection is recorded here are counted. A null pointer returns `SCE_KERNEL_ERROR_EFAULT`, where the console faults. Resonance: A Plague Tale Legacy (PPSA30601) calls it at start-up (#4067)
|
||||
- [settimeofday](../../../core/libs/prx/libkernel/Time/Time.cpp) (libkernel_sys) checks like FreeBSD 11.4's [`kern_settimeofday`](https://github.com/freebsd/freebsd-src/blob/release/11.4.0/sys/kern/kern_time.c#L688-L707) for a root caller: `EINVAL` for a negative second count or a microsecond count outside 0 to 999999, before anything is stored. A valid time throws, naming it, since the host clock is never set, and its time zone is not stored, as FreeBSD stores the zone only after setting the clock. A time zone without a time is kept for the process and reported by `gettimeofday`; `sceKernelGettimezone` still reports 0 and 0, since whether the console reads the same value is not known. FreeBSD checks `PRIV_SETTIMEOFDAY` first, which a jailed process fails with `EPERM`; whether a title holds it on the console is not known.
|
||||
- [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
|
||||
- [Short sleeps ended by GPU and flip completions](../../../core/libs/prx/libkernel/Time/SleepWake.cpp) (libkernel) - a `sceKernelUsleep`, `usleep`, `nanosleep` or `sceKernelNanosleep` of 1 ms or less returns before the requested time, which FreeBSD and the console do not do: it ends once the AGC driver reports a completed GPU batch or batch completion action, or VideoOut completes a flip, so a title that polls a GPU label or the flip status between sleeps does not sleep the rest. A title that paces frames with such a sleep can wake up to 1 ms early. A thread returns early at most 8 times in a run of sleeps; the run restarts when the thread submits AGC work or did not sleep the requested time since its last sleep, so a loop that counts sleeps to time out still sleeps all but 8 in full. `APS5_NO_SLEEP_WAKE=1` keeps every sleep in full
|
||||
- [chflags](../../../core/libs/prx/libkernel/File/src/Stdio.cpp) (libkernel) follows FreeBSD 11.4's [`kern_chflagsat`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/sys/kern/vfs_syscalls.c#L2366-L2383) and UFS's [`ufs_setattr`](https://github.com/freebsd/freebsd-src/blob/8c639945a44588f6cfdddfb057bb5aad88735da0/sys/ufs/ufs/ufs_vnops.c#L509-L556) for a root caller: the path lookup reports `EFAULT`, `ENOENT` and `ENOTDIR`, a flag outside the 17 UFS stores (`VNOVAL` included) `EOPNOTSUPP`, and `SF_SNAPSHOT` `EPERM`. Neither host keeps BSD file flags, so every file is taken to have none (`stat` reports `st_flags` 0): flags 0 succeed without touching the file, and any other flag throws, naming the flags. `UF_READONLY`, `UF_HIDDEN`, `UF_SYSTEM` and `UF_ARCHIVE` are FreeBSD's names for the Windows attributes but are not mapped to them: UFS stores them without enforcing them, `FILE_ATTRIBUTE_READONLY` already carries the owner write bit of `chmod` on Windows, and Linux has no equivalent a process can set without `CAP_LINUX_IMMUTABLE`. The console's filesystem types, `EROFS` on read-only mounts and the change-time update are not modelled
|
||||
|
||||
Reference in new issue
Block a user