Emscripten targets wasm64 without x86 assembly, Linux-only headers or the
x87 long double. These changes add __EMSCRIPTEN__ paths beside the host
ones; native builds compile the same code as before.
- libc: long doubles in guest varargs and scanf go through
GuestLongDouble, a plain copy where long double is the x87 format;
APS5_EXPORT emits no assembler alias; the guest arena is one aligned
allocation that zeroes pages when they are committed again; getifaddrs
keeps its link-level entries on Linux; /proc lookups and the host
stderr duplicate are left out.
- libkernel: file-backed mmap, EVFILT_VNODE watches, getcontext and
setcontext throw; getdents replaces the raw getdents64 syscall;
getdtablesize takes the resource limit alone.
- VideoOut leaves SDL, the display window and the HDR probe out,
Sysmodule asks libkernel for unwind information and Net includes
sys/time.h.
On Windows, sceKernelRaiseException threw for a thread created suspended
and not resumed yet. FreeBSD libthr starts such a thread with signals
blocked and restores its mask on resume, so the signal stays pending and
is delivered on that thread once it runs.
The raise is now recorded in the thread's pendingException with a
compare-exchange, and the thread exchanges it for -1 when it leaves the
creation wait and delivers it to itself before its start routine. Both
sides use one atomic, so a raise racing a resume is either taken by the
thread or, after it started, delivered as for a running thread. Raises
while pending are merged, as for a standard signal.
guest_pthread_create_suspended now runs the deferred-delivery case on
every host, with a second raise while the thread is suspended.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Read APS5_GAME_MODE once at load, the same point where the Windows build
raises the scheduler tick, so an invalid value stops the title at start
with an error that names the variable and an unset one changes nothing.
Run the process session in a test executable linked with libc and leave
through LibcExit and LibcExitWithoutHandlers: the backend is released once
in both. Check that a refused request is never released, that off never
reaches the backend, that a second session is refused, that an unset
APS5_GAME_MODE is accepted and that APS5_GAME_MODE=bogus is rejected with
an error naming the variable.
Add CreateHostBackend (the GameMode client on Linux, the activity backend
on macOS, a backend that reports itself unavailable elsewhere),
StartProcessSession, which owns the one session of the process and
releases it from the libc shutdown callbacks that every exit path runs,
and StartFromEnvironment, which reads APS5_GAME_MODE and does nothing at
all when it is unset, empty or off. Build the files into libkernel; the
session is not started yet.
macOS throttles timers and background work of a process unless it holds an
NSProcessInfo activity (Apple, Foundation, NSProcessInfo
beginActivityWithOptions:reason:, with NSActivityUserInitiated and
NSActivityLatencyCritical, which asks for the highest timer and I/O
precision available). The tree has no Objective-C sources, so call the
runtime from C++: load libobjc and Foundation with dlopen, look up
objc_getClass, sel_registerName, objc_msgSend and the autorelease pool
functions, begin one activity, retain its token, and end and release it on
End. Both library paths are injectable, and any missing piece is reported
as unavailable. Nothing uses the backend yet.
Linux hosts running Feral's gamemoded switch the CPU governor and scheduler
for a registered game. The client the project ships is a header that loads
libgamemode.so.0 (then libgamemode.so) with dlopen and binds the library's
real_gamemode_request_start, real_gamemode_request_end and
real_gamemode_error_string symbols (FeralInteractive/gamemode at
a74b8106a2236d1f2696aa44c93bc4c8ef13b42e, lib/gamemode_client.h).
Do the same here with the library name list injectable: a missing library
or symbol is reported as unavailable, a failing request as refused, nothing
is linked, and the request is ended only when it was made. Nothing uses the
backend yet.
Accept off, on and auto, treat an unset or empty value as off so the
default stays as it is today, and reject anything else with an error that
names the variable and the accepted values.
A title that runs for hours would like the host to treat it as a game
(Feral GameMode on Linux, a latency-critical activity on macOS), but no
code owns that request. Add IBackend, the interface a host mechanism
implements, and Session, the state machine that requests once, releases
once, contains every backend failure and logs it once. Nothing uses it
yet.
The patched libkernel does not hand its plain C++ functions to the other patched libraries: every cross-library call in the tree goes through an extern C helper with a _nid suffix. The host CPU probe had none, so a library that wants the CPU model or the missing feature list cannot reach it. These helpers return plain structs, as the application metadata helpers do.
GuestLoadAverage's braced initializer left its four bytes of padding after ldavg indeterminate, and the sysctl copies all 24 bytes to the guest. The scaled value of a load over UINT32_MAX / 2048 was converted out of range. The test now checks the padding and the exact fscale 2048 scaling against the host averages read just before and after the call.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
setrlimit read the guest rlimit struct directly, so a non-null pointer
into unmapped memory crashed the host. It now copies the struct in with
GuestCopyIn_nid_no_patch together with the existing null check, before
the resource check, as FreeBSD's sys_setrlimit copies in before
kern_setrlimit validates the resource, and fails with EFAULT.
SuspendThread fails with STATUS_THREAD_IS_TERMINATING for a thread that
has begun to exit while its handle is not signaled yet. TryDeliver took
only the signaled handle as an exit, so the raise deliverer, which keeps
sweeping a target in host code until delivery or exit, threw "cannot
suspend the target thread" and aborted the process when that target
exited in between. The suspension now reads the NTSTATUS from
NtSuspendThread and treats a terminating target as exited; other
failures still throw.
guest_raise_exiting_thread raises at 32 threads per round that block in
a host wait and exit after it, for 100 rounds.
Probe p87_libkernel lines 7-27: a payload process on a PS5 returns 0 and keeps the limits for a raised RLIMIT_DATA or RLIMIT_STACK hard limit, and reads back RLIMIT_CORE soft limits.
waitpid translated the stop and termination signal of a child from the
Linux numbering to the FreeBSD one on every non-Windows host. Darwin
already numbers its signals like FreeBSD, so on macOS the translation
broke them: a child stopped by SIGSTOP (17) was reported as stopped by
20, SIGBUS (10) as 30, SIGSYS (12) as 31, and a child killed by SIGUSR1 (30)
made waitpid report a missing guest equivalent.
macOS now passes the host signal through. The spawn test finds its own
executable with _NSGetExecutablePath on macOS instead of /proc/self/exe,
and also checks a child killed by SIGUSR1, whose number differs between
Linux and FreeBSD and which macOS used to reject.
FreeBSD 11.4's sys___sysctl and userland_sysctl copy the name and the
old length in, and copy the value and the length out, so a bad pointer
gives EFAULT in that order. sysctl dereferenced them directly, and
sysctlbyname read its name with strcmp.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
sigreturn applies FreeBSD 11's amd64 sys_sigreturn checks:
- EFAULT for a null context;
- EINVAL for unknown mc_flags, and for rflags bits outside
PSL_USERCHANGE that differ from the current flags;
- set_fpcontext's FPU format and ownership cases.
It then restores the context through the path setcontext uses, which
now lives in RestoreContext. A non-user %cs and an extended FPU state
still throw.
The only conflict is sceKernelGettimezone in Time.cpp: main now reports the host zone, so the zone is built from that into a local and copied out with the checked write.