sceSystemServiceLoadExec found its own executable through /proc/self/exe
and replaced the process with fexecve after close_range, none of which
macOS has, so on macOS every call except "exit" threw. On macOS:
- the running executable's path comes from _NSGetExecutablePath, resolved
with std::filesystem::canonical, as libSceNpEntitlementAccess and
libSceFont already do;
- the target must be an x86-64 Mach-O executable (MH_MAGIC_64,
CPU_TYPE_X86_64, MH_EXECUTE) that the user may run;
- macOS has no fexecve, so the process is replaced by path with
posix_spawn and POSIX_SPAWN_SETEXEC; POSIX_SPAWN_CLOEXEC_DEFAULT closes
every descriptor but the standard streams, as close_range does on Linux;
- before the replacement the exit starts and the shutdown callbacks run
(LibcStartExit, then LibcRunShutdown), as on Linux, so guest threads
that call a stopped library wait instead of unwinding;
- descriptor 2 gets the host standard error back before the replacement,
as on Linux, and guest_system_load_exec_standard_error runs on macOS.
A launch without arguments keeps the Linux execv path, which macOS has.
guest_system_exit finds its own executable the same way on macOS.
SystemServiceConsoleLanguage in SystemService.hpp reads ANYPS5_LANGUAGE
with the same default, range and error as sceSystemServiceParamGetInt,
which now calls it. Other libraries can pick the console language
without linking libSceSystemService.
Under -DANYPS5_ENABLE_ASAN=ON with ASAN_OPTIONS=detect_leaks=0, 14 of
the 849 tests outside the AGC driver, shader and VideoOut suites failed
on main for reasons that come from the ASan build itself, not from the
code they test:
- libc copies the main executable's file-backed writable pages before
remapping them anonymously. In an instrumented test executable those
pages hold ASan's redzones around globals, so the memcpy reported a
global-buffer-overflow at load (patched_libraries,
guest_memory_lifetime). The ASan build copies the pages word by word
without instrumentation.
- Five tests check that a local variable is on the thread's stack.
With detect_stack_use_after_return, which is on by default on Linux,
instrumented locals live on ASan's fake stack. These tests now run
with it off. guest_kernel_is_stack also bounded the worker stack by
the application area without the ASan build's arena offset.
- The relinker module tests and loadexec_arguments load instrumented
libraries into a Python process or a relinked guest, so the ASan
runtime is not first in the initial library list. They now run with
verify_asan_link_order=0. Preloading libasan instead put its
__cxa_throw interceptor ahead of libc.prx's and broke the unwind of
an exception that LoadExec throws and catches.
- guest_allocator_failures limits RLIMIT_DATA to 128 MiB and then
commits 300 GiB. ASan maps 37.5 GiB of shadow for that commit, which
the limit refuses, and aborts. The ASan build skips that section.
- fiber checks the address of a local against the fiber's context too,
so it runs without fake stacks as well. Its CheckActiveContext then
reads the fiber stack word by word above that local, through the
redzones of the frames on that stack, and is no longer instrumented.
- agc_multisample_guest_access passed aligned_alloc a size that is not
a multiple of the alignment, which C11 does not allow and ASan
rejects. It now rounds the size up.
add_asan_test_options appends to ASAN_OPTIONS for one test in an ASan
build and does nothing otherwise.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #5978, StartExit only parks the other guest threads and exit runs
LibcRunShutdown itself, so LoadExec's three exits (the converted
executable on Windows and Linux, and the host executable) now call
LibcStartExit and then LibcRunShutdown, as exit does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Metal Gear Solid 4 (PPSA18194) aborts on main when its launcher starts
the game: sceSystemServiceLoadExec runs the guest shutdown, a render
thread that then calls into the stopped AGC driver gets ProcessShutdown
back from LibcAwaitExit, and the exception unwinds into title code,
which terminates the process before the new executable starts.
LibcAwaitExit parks a thread only once an exit has been requested, and
LoadExec ran the shutdown without requesting one. It now starts the
shutdown the way exit does, so such threads wait until the process is
replaced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceSystemServiceParamGetInt answered 0 for the time zone (parameter 4)
and summer time (parameter 5), so the console looked set to UTC while
libSceRtc and libc convert local time with the host's zone. Titles add
the time zone in minutes and 60 more minutes when summer time is 1 to
UTC to get the local time (Apollo, GoldHEN's frame logger). Both now
follow the host's local time zone: summer time is whether it is in
effect, and the time zone is the current offset east of UTC less the
summer time shift while it is.
On Windows that shift is the C runtime's own summer time bias
(_get_dstbias), the one localtime_s applied, not a fixed 60 minutes.
The UCRT reads the system zone when libc.prx loads and keeps that
zone's bias after TZ is set later, so on a host whose system zone has
no summer time (the CI runner's UTC) a TZ of CET-1CEST shifted by 0 and
the time zone came out as 0. The cause and the change are screamm's,
from the review.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A LoadExec with an argument list replaces the process through Replace (fexecve), which runs before StartHostExecutable, so the next image still wrote to the title's redirect. Descriptor 2 now gets the kept host descriptor there too, after the shutdown and the flush and before close_range closes it.
A forked child with stderr on a pipe moves the guest's descriptor 2 to a
second pipe with dup2, then starts itself again through
sceSystemServiceLoadExec("/app0/eboot.bin"). What the new image writes
to stderr must reach the first pipe and nothing the second. It fails
with the previous execv, where the text goes to the guest's pipe.
A guest dup2 onto descriptor 2 keeps a close-on-exec duplicate of the
host's standard error (#4792), so the runtime's own output stays on the
console while the title's stderr goes where the title pointed it. The
duplicate did not survive LoadExec's execv, and the next executable
started with descriptor 2 still on the title's redirect: its runtime
output, terminate report included, went there.
RetroArch (PPSA99169) points stderr at app0/trace.txt and then starts
its picker. The picker's [gpu] and sceKernelDebugOutText lines landed
in trace.txt, and its abort on an unconverted es-de.bin showed up
nowhere; the message was found only in the core dump.
Before execv, the kept descriptor now goes back onto descriptor 2.
Detect HDR output on the host: on Windows the monitor showing the window
must run in HDR10 (DXGI IDXGIOutput6), and on every host the window's
Vulkan surface must offer a 10-bit VK_COLOR_SPACE_HDR10_ST2084_EXT
swapchain with VK_EXT_swapchain_colorspace and VK_EXT_hdr_metadata. The
monitor's luminance comes from DXGI; hosts that report none get 1000
nits peak and full frame, 0 nits black.
While HDR output is available, sceVideoOutGetOutputStatus reports
dynamic range 2 and flag bit 0, sceSystemServiceGetHdrToneMapLuminance
reports the monitor's luminance, and every open port's output mode
event fires when that changes. PQ display buffers are presented
unchanged through an HDR10 swapchain with HDR metadata; any other
display buffer switches back to the SDR swapchain. Without HDR output
the PQ to SDR conversion uses the peak the title was last told as its
white level.
AI-assisted: yes
Accept the 10-bit BT.2100 PQ display formats 0x8100070422000000 (red
in the low bits) and 0x8100070400000000 (blue in the low bits) and
convert them to 8-bit sRGB when presented: PQ EOTF, BT.2020 to BT.709
primaries, a luminance tone map whose white level is the tone-map
luminance sceSystemServiceGetHdrToneMapLuminance reports (reference
white min(203 nits, white level)), and the sRGB encoding.
The conversion runs on the CPU for linear buffers and DCC clear values,
in the color transfer shader for tiled guest buffers, and in the
presentation pass for resident images. The three share the PQ EOTF
table computed once in double precision.
AI-assisted: yes
A guest handler that called exit threw out of the libc exit path because the exiting thread waited on itself. Like FreeBSD, the nested call now runs the handlers that are still registered and ends the process with the status it passed.
The relinker's repeatable --executable converts another executable of the
title beside the output, sharing its libs, app0 and guest modules.
sceSystemServiceLoadExec maps /app0 paths to those executables, passes the
argument list on the new command line and finds the main executable through
APS5_EBOOT. RetroArch (PPSA99169) starts its frontend picker this way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceSystemServiceParamGetInt always reported English (United States) as
the console language, so a title that follows the console's language,
such as Jelly5 (PPSA99505) with its Arabic text, can only show English.
ANYPS5_LANGUAGE now selects a console language number from 0 to 30
(21 is Arabic). Unset or empty keeps English (United States); any other
value throws at the language query instead of being ignored.
(cherry picked from commit 9bcf196daa01b07a22be876a7f1143149503e054)
The param is void*, as RommPS declares it. The test also passes a null and an empty URI and a param that must stay untouched, and compares against 0x8002002D itself. The debt entries now say the error is returned for any arguments and that the param layout and the console's argument checks are unknown.
sceSystemServiceLaunchWebBrowser fails with the kernel's EOPNOTSUPP: there is no web browser to open. RommPS PPSA76677 stops on main at this import and shows a QR code instead when the browser does not open.
sceSystemServiceKillApp now ends the title as guest exit() does, so driver calls that wait for the exit park instead of throwing ProcessShutdown, and a second exit waits for the first. The test now fails when the kill returns, exits with a status other than 0 or bypasses the coordinator, and checks why a rejected call throws.
Report an app ID for the running title from sceSystemServiceGetAppIdOfRunningBigApp, and shut the guest down and exit when sceSystemServiceKillApp receives that ID with the arguments -1, 0 and 0. SwanStationPS5 (PPSA98510) 1.0.6 closes itself this way and stops on both imports on main.
Every library CMakeLists.txt ended with the same block removing -static,
-static-libgcc and -static-libstdc++ from CMAKE_EXE_LINKER_FLAGS on MinGW,
because core/libs/CMakeLists.txt only removed them after adding the library
directories. Remove them before the libc and library directories are added
so each directory inherits the stripped flags, and drop the 52 copies.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017pTZqAyVSZy2FZmaqakPHZ
Implement scePthreadGetschedparam and scePthreadSetschedparam on top of
the thread priority, POSIX utimes and fsync on top of sceKernelUtimes
and sceKernelFsync, and sceUserServiceGetAccessibilityZoomFollowFocus
like the other accessibility queries. Add the remaining imports of
PPSA12544 as unimplemented exports and record unknown NIDs and
signatures in the technical debt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The export threw, and titles query the system name during startup.
Parameter 6 (the system name) now writes the fixed name "PS5" into a
buffer of at least SYSTEM_SERVICE_MAX_SYSTEM_NAME_LENGTH (65) bytes.
A null buffer or a zero size returns SYSTEM_SERVICE_ERROR_PARAMETER,
as in KytyPS5. Other parameter ids and buffers of 1 to 64 bytes still
throw, because no PS5 source gives their result. guest_system_service
covers the error rows, both throws and the returned name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign-in, web browser and player dialogs finish cancelled; the message dialog finishes at once;
NpAuth, entitlement consumption, reachability, account age and the NpUtility bandwidth test
report signed out; sceKernelMtypeprotect changes the protection (the memory type has no host
equivalent); the APR ForEach resolvers resolve every path and report each failure in its own
result entry. vswprintf's stub is dropped in favor of the existing wide-formatter
implementation, which already covers it on every platform.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>