A PS5 (firmware 13.60) reports CPU write 0x2 with CPU read 0x1, 0x80 with 0x40 and 0x200 with 0x100 after a map, sceKernelMprotect, sceKernelMtypeprotect or POSIX mprotect; GPU write 0x20 keeps GPU read 0x10 clear. sceKernelVirtualQuery and sceKernelQueryMemoryProtection now report the protection that way.
The C runtime allows 512 stdio streams by default, so after about 509
guest fopen/fdopen streams every further stream failed with EMFILE,
including the std::ifstream APR opens for each read, while getrlimit
reports 8192 open files. Raise the limit to 8192 when libkernel loads,
as the Linux build raises RLIMIT_NOFILE.
PPSA34015 (EA SPORTS FC 27) stopped with "Joining guest thread: Access is
denied": scePthreadJoin waited on a thread that another call released
under it, and then waited on its closed handle. As FreeBSD 11.4's
thr_join.c and thr_detach.c do with the joiner field, scePthreadDetach
now returns EINVAL while a thread waits to join the target, a second
concurrent scePthreadJoin returns EOPNOTSUPP, a cancelled join backs out,
and a completed join leaves the thread detached.
A shared mapping is a view of a file section created on the descriptor's
handle, read-write when the descriptor is, otherwise read-only. A private
mapping is a copy of the file read at mmap, as POSIX allows. Anonymous
shm_open objects and JIT shared memory descriptors are temporary files on
Windows, so mmap now maps them too (it failed with EOPNOTSUPP before).
mprotect of a mapped view above the view's protection fails with EACCES
before any bookkeeping changes. The cases Windows cannot represent are
listed in the libkernel debt.
Dusklight (PPSA99305) uses SQLite in WAL mode, which maps its -shm file.
On Windows main f0634088b every start logged "Failed to start
transaction: disk I/O error" for its Dawn and pipeline caches (3 of 3
runs); with this change the caches initialise and their WAL files fill
(4 of 4 runs). The title reaches its menu either way.
A shared mapping may end inside the 16 KiB page that holds the end of
the file, as POSIX mmap allows: the view ends with the file's last 4 KiB
host page, which Windows zero-fills past the end, the rest of the guest
page is private zero pages, and the file never grows. A mapping that
reaches a whole page past the end still fails with EOPNOTSUPP.
PS5LM Plus (PPSA99581) loads its model with llama.cpp, which maps the
whole GGUF file shared and read-only. With a 491,400,032-byte model,
Windows main 5de7a46e0 and this change without the last page logged
"llama_model_load: error loading model: mmap failed: Operation not
supported" (3 of 3 runs); now the model loads and the completion of
"The capital of France is" starts with " Paris" (3 of 3 runs).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a payload process on a PS5 (firmware 12.70), I386_GET_FSBASE (7) and
I386_GET_GSBASE (9) wrote 4 bytes, the low 32 bits of the FS and GS
bases, and failed with EFAULT for a null argument; both threw here. On
Linux x86-64 hosts they now do the same.
The nine operation numbers tried that FreeBSD 11's amd64 sysarch has no
case for (2, 5, 6, 12, 127, 133, 134, 1000 and -1), each with a null
argument, failed with EINVAL there, as its default case does, and threw
here. Every such number now returns EINVAL on every host.
Threads made with pthread_create and scePthreadCreate started with their
creator's GS base there; the test now checks that a guest thread does so
on Linux. The sysarch debt entry records these measurements and what
AMD64_GET_XFPUSTATE and I386_GET_XFPUSTATE returned there; both still
throw here.
An adopted thread (the main thread, or a host thread that calls
scePthreadSelf) reported its whole Windows stack reservation, and so
did sceKernelIsStack on a host thread before adoption. A relinked
executable reserves 0x210000 bytes for its main thread and commits the
top 0x200000, so the lowest 64 KiB of the reported stack hold only
reserved pages and Windows' guard pages. mprotect fails there, so
HotSpot in Java 25 LAN / DNS (PPSA99869) could not create the main
thread's stack guard pages ("Attempt to allocate stack guard pages
failed").
When everything above the bottom allocation granule is committed
read-write, the host stack is now reported from there, as created
guest threads report only their committed stack. Other host stacks
keep the whole range. The committed-pages walk is shared with
StartNativeThread and throws when VirtualQuery fails.
A read event on a listening socket took its data from FIONREAD, which a listening socket refuses on Linux, so kevent and sceKernelAddReadEvent reported 0 connections while saying one was ready. FreeBSD 11.4 gives a listening socket filt_solisten, which reports so_qlen, the completed connections waiting for accept. Ready now checks SO_ACCEPTCONN and on Linux reads a TCP listener's accept backlog from TCP_INFO, where tcp_get_info puts it in tcpi_unacked; with no host call for the count (Windows, macOS, a listener that is not TCP) it reports 1, the lower bound the readiness already implies.
A mounted folder uses the junction reparse tag and would otherwise be returned as a relative Volume GUID path. Only a drive path is reported, through the absolute-link text helpers.
A kqueue descriptor is readable while one of its events is triggered and
is never writable or exceptional, as FreeBSD's kqueue_poll answers, on
both hosts. On Windows select threw for it, and on Linux its /dev/null
placeholder was reported readable and writable.
A descriptor that stops being a socket, a kqueue or a pipe during the
wait now fails the call with EBADF when it was closed and is selected
again with the rest of the timeout when its number was reused, as
FreeBSD's kern_select looks every descriptor up again in each pass,
instead of throwing. On Windows a host descriptor that is not a pipe
throws when select starts, before waiting.
Depends on #7139.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
select takes descriptors 0 to 2 as a console title's terminal with no input: 0 is never readable and 1 and 2 are always writable. poll threw for them unless the host happened to attach a pipe, so the same title could select on its standard streams but not poll them. poll now gives the same answer, with POLLOUT, the one bit ttydev_poll reports for a writable terminal, for 1 and 2 and nothing for 0.
selscan asks a descriptor once, with the flags of every set it is in (POLLRDNORM for the read set, POLLWRNORM for the write set, POLLRDBAND for the exception set, plus POLLHUP and POLLERR), and marks each set whose flags the answer shares. A seeded random device's randomdev_poll narrows a request with POLLRDNORM to that bit and returns any other request whole, so in the read set it is readable and in no other set, and otherwise it is in each write and exception set it was asked in; select reported it readable and writable together and never exceptional. A regular file or directory went to the host poll, which on Windows threw; vop_stdpoll makes it readable and writable and never exceptional, which select now answers in process on every host, as poll does.
poll threw for /dev/random and /dev/urandom, which select already treats as ready. FreeBSD 11.4's randomdev_poll, once the device is seeded, narrows a request that has POLLIN or POLLRDNORM to those bits and returns any other request whole, POLLOUT and the band bits included. poll now answers that, and the test that relied on the random device throwing uses a kqueue descriptor, which poll still does not support.
poll threw for any descriptor that is neither a socket nor a pipe, so a title polling a file it also reads stopped there. FreeBSD 11.4 hands a vnode to VOP_POLL, and both vop_stdpoll and vop_nopoll return POLLIN, POLLRDNORM and POLLOUT of the requested events for every event poll accepts and never POLLPRI, POLLRDBAND or POLLWRBAND. A file, a directory or a file read from app0.zar now answers that without a host call. File::IsVnode tells such a descriptor apart from the host file type without throwing, so a host socket lent by libSceNet still reaches its own path.
On a PS5 (firmware 12.70), of the values 0, 1, 2 and -1,
pthread_condattr_setpshared accepts only 0 and leaves the attribute
unchanged otherwise. pthread_condattr_getpshared reports 0 and returns
EINVAL for a null, uninitialized or destroyed attribute, also with a
null output. With an initialized attribute a null output crashes the
console; here it throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on a PS5 (firmware 12.70): the getter reports 0, and of the
values 0, 1, 2 and -1 the setter accepts only 0 and checks the value
before the attribute. A null or uninitialized attribute, or a null
output, crashes the console; here it throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a PS5 (firmware 12.70), of the values 0, 1, 2 and -1,
pthread_spin_init, pthread_barrierattr_setpshared and
pthread_mutexattr_setpshared accept only PTHREAD_PROCESS_PRIVATE (0);
1, 2 and -1 return EINVAL and leave the attribute unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PPSA34015 (EA SPORTS FC 27) registers EVFILT_READ for descriptor 0 in a
new kqueue at start-up, ignores the result, and stopped with "kevent:
EVFILT_READ on a non-socket descriptor not implemented". A read event on
the host stream on descriptor 0 is now accepted and never triggers, as
select never reports descriptor 0 readable.
An ITIMER_REAL or alarm expiry while SIGALRM is blocked is marked on the
pending set of sigtimedwait instead of throwing, as kern_psignal leaves a
blocked signal pending. sigwait, sigwaitinfo and sigtimedwait take it,
repeated expiries merge into one pending signal, and unblocking it runs a
guest handler on the unblocking thread or, with the default disposition,
exits the process with status 142 as FreeBSD's default action does.
The expiry rechecks the mask after marking the signal, so an unblock that
races it does not leave SIGALRM pending while unblocked, and TakePending
clears the bit with the value it read so one signal is taken once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>