A guest mmap with PROT_EXEC and MAP_SHARED of a shared-memory object or a regular file threw on Windows. The section is now created from a handle reopened with GENERIC_EXECUTE, as PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE, the owner ACE of named objects grants execute with read, and a writable shared mapping of a read-only descriptor fails with EACCES, as FreeBSD 11.4 shm_mmap and vn_mmap do.
Fixes#12337
Both log their arguments and the caller and return. Note what the
titles' bundled libc.prx passes them and that three of its
sceKernelDebugRaiseException calls are followed by ud2 in every build
checked, so the guest reaches that ud2 here.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This reverts commit 780b33aea3, restoring the 13824 MiB direct memory pool.
With the pool at 12288 MiB, Astro Bot (PPSA21564) can no longer load its
level: DirectMemoryAllocator asserts "Can't allocate direct memory" for a
64 MB VideoPlayerTexture with 12228 of 12288 MB in use, then the process
faults about 26 s in (2 of 2 runs, RTX 4090, Linux, main cccdaa2734).
The same tree with only this merge reverted runs the full 150 s with no
direct memory assert (2 of 2 runs).
scePthreadMutexattrSetkind called NotImplemented_nid_no_patch for a kind
outside 1 to 4. Firmware 13.42's libkernel, run in an emulator, makes it
call pthread_mutexattr_setkind_np, which stores any kind as a signed
16-bit value and returns 0, and turns a null attribute's -1 with errno 22
into 0x8001FFFF. It now forwards to pthread_mutexattr_setkind_np and
converts the result with sceKernelError, so a null attribute or object
still returns 0x8001FFFF and now also sets errno 22.
An out-of-range kind is refused by scePthreadMutexInit with 0x80020016,
leaving the mutex untouched, as measured for the same module.
scePthreadMutexattrGetkind is unchanged; kind 0 now reaches it and
returns 0.
XNU's poll reports POLLHUP as soon as either direction of a stream socket has ended, adds POLLPRI and POLLRDBAND to it and then drops POLLOUT. FreeBSD's sopoll_generic reports POLLHUP only once the receive and the send side are both shut, and Linux does the same, so on macOS a guest saw POLLIN|POLLHUP for a stream whose peer had only shut its sending side, and POLLHUP for one that had only shut its own.
When the host reports POLLHUP on a guest stream socket, ask it about each direction alone and keep POLLHUP only when both have ended, report the requested POLLOUT while the sending side is shut or writable, and leave urgent data to SIOCATMARK.
FreeBSD code reaches its thread pointer through %fs and macOS cannot set
the fs base. The macOS relinker turns each %fs access of a guest image
into a stub that reads the thread pointer from a pthread key and calls
Aps5GuestTlsAllocate on a thread's first access, registers the TLS
descriptor of an image with Aps5GuestTlsRegister, and routes
__tls_get_addr to Aps5GuestTlsGetAddr. No library provided them, so a
relinked executable could not start.
- Aps5GuestTlsRegister validates the descriptor the relinker wrote and
creates the key; its destructor frees the block of a thread.
- Aps5GuestTlsAllocateThreadPointer allocates the block (the TLS template
followed by zeros, then a 0x100-byte thread control block whose first
word points at itself, as on FreeBSD) and stores the thread pointer
under the key.
- Aps5GuestTlsAllocate is the entry the stubs call: rax holds the
descriptor and returns the thread pointer, every other register is
preserved, the upper halves of the ymm registers only where AVX exists.
- Aps5GuestTlsGetAddr returns the block of the thread plus the offset.
Co-authored-by: mugurc <[email protected]>
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]>
- mlock on macOS wires only the pages libkernel has not wired yet. XNU
counts each wire of a page, and the locked ranges merge overlapping
locks, so a page locked twice stayed wired after munlock and
munlockall. The mlock test checks the wire count on macOS.
- mprotect changes a watched page through GuestWriteWatchProtect, which
applies the host protection and records it under the write watch's
lock, so a collection on another thread cannot run between the two.
The write watch test covers it.
- sceKernelVirtualQuery takes a watched page's write permission from the
write watch for memory outside the guest allocation registry.
- GuestAllocationsGuestPages counts an image segment up to the end of
its last host page, as the image page collection does.
- The macOS includes stay in main's include block, so the host code
other pull requests add there still sees them; the unused Mach-O
headers and the end trim, which never changed the protected spans,
are gone, and the guest page size is passed in.
- The libc and libkernel debt entries describe what is wired now.
- mprotect: the guest rounds a range to its 16 KiB pages. A Mach-O image
is loaded at a multiple of the host page size only (4 KiB under
Rosetta), so the pages are counted from where the ELF address 0 of the
image holding the range was loaded, and a rounded edge smaller than a
guest page that lies in the gap between two segments, where no host page
exists, is left out. The write watch is told the new protection.
- sceKernelVirtualQuery reads the region with mach_vm_region.
- sceKernelMunlockall unlocks the ranges libkernel locked, one by one:
macOS has no munlockall, which fails there with ENOSYS and would
overwrite errno.
- The stack protect test reads page protections with mach_vm_region.
This is mugurc's f66a4df741 from his macOS series, without the mlock
check that #10889 adds.
Co-authored-by: mugurc <[email protected]>