- 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]>
A resident direct memory mapping created a SharedPage, a Physical, a
physical map node and an aliases buffer for every 16 KiB page, about
18 MiB of heap per GiB mapped, although a page mapped once holds no
state there. Resident pages now keep only their View, with pins and the
compare-when-shared mark in it; an index from (section, offset) to the
resident run finds a live resident mapping of a physical page, and the
shared state is created when a run is demoted, or when it is evicted
with data or a compare mark. ForgetSection drops the index entries of
the section's runs.
guest_memory on Windows 11 26200 (Ryzen 5 5600X): private memory per
GiB mapped at map time drops from 30.9 MiB to 13.4 MiB.
Co-Authored-By: Claude <[email protected]>
Add the BSD "quad" `strtoq` export for the libc PRX as a thin wrapper
around `strtoll`, as FreeBSD 11.4 lib/libc/stdlib/strtoq.c does. The
unsigned sibling `strtouq` is already here as the same alias of
`strtoull`. Extend the guest wide strings test to probe the signed
path on an under/overflow run and a short positive run with a trailing
non-digit. Document the export in docs/dev/debt/libc.md with the
registry NID `yUUOxgk8Dmc`; console behavior is unverified beyond the
existing `strtoll` contract.
Co-Authored-By: Claude Opus 4.7 <[email protected]>