Commit Graph
201 Commits
Author SHA1 Message Date
Adrià bebc294607 Merge pull request #6443 from EagleBearerYS/fix/libkernel-host-stack-guard-page
fix(libkernel): keep a protected host stack's guard page, and protect the Linux main stack
2026-10-19 02:41:09 +02:00
Adrià 57a9970094 Merge pull request #6311 from Ondra97/codex/fix-posix-flexible-memory-release
fix(libkernel): release flexible memory budget through munmap
2026-10-19 00:06:26 +02:00
Adrià 1288433e8e Merge pull request #6184 from MarcZX10/codex/cache-inaccessible-guest-pages-6183
fix(agc): cache inaccessible guest pages
2026-10-18 22:37:09 +02:00
Dean 1b0c7cfa02 Merge pull request #7112 from Pouare514/fix/flexible-release-scope
fix(libkernel): scope flexible release to tracked ranges with release-then-record
2026-10-18 19:22:54 +13:00
MarcZX100 a352941e77 fix(libkernel): release flexible accounting after fixed mmap 2026-10-17 20:22:14 +00:00
Pouare514 82dff58494 fix(libkernel): scope flexible release to tracked ranges with release-then-record 2026-10-17 14:03:19 +02:00
milescovielloandClaude Opus 5.5 cbf006cb4b fix(libkernel): return 0 from sceKernelMprotect and sceKernelMtypeprotect for a zero length
mprotect already returns 0 for a zero length. The sceKernel entry
points passed it to DoMprotect, which throws for an empty range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 06:26:57 +00:00
Yunus Shaikh 2ac72d48bc Merge main into fix/libkernel-host-stack-guard-page 2026-10-16 22:29:52 -07:00
Adrià 5b70a50680 Merge pull request #5955 from fma-rc/fix/libkernel-linux-guest-module-protect
fix(libkernel): register a relinked guest module's image when Linux protects its pages
2026-10-16 23:29:46 +02:00
Alexej Szpevák d97d6efb1b fix(libkernel): refuse descriptor calls on app0.zar files
flock, fstatfs, ftruncate, fsync, fdatasync, getdirentries, fchmod, futimes and mmap on an archived descriptor acted on its null device and succeeded or failed with an unrelated errno. They now throw NotImplemented, each covered by the kernel archive test; mmap is noexcept, so its refusal is checked through the terminate handler.
2026-10-16 20:03:32 +02:00
Tamalero 13a3902954 fix(agc): cache inaccessible guest pages
Remember inaccessible arena pages and Linux mapping gaps so repeated access checks do not rescan host mappings. Invalidate the cache when guest stack protections change.
2026-10-16 17:44:23 +00:00
Yunus Shaikh 9a48a9605c fix(libkernel): map a protected main stack up to its top on Linux
A protect below the main thread's stack mapping mapped only the
protected pages. Linux keeps a growing stack one guard gap (1 MiB by
default) above a readable mapping, so after a read-only protect, or a
protect later restored to read/write, at the bottom of the reported
stack the stack could no longer grow into the megabyte above it and a
deep enough call faulted where the console has stack pages. The pages
between the protect and the top of the stack are now mapped as well,
so the stack never has to grow past them.
2026-10-16 07:28:23 +00:00
Yunus Shaikh d5c12169fc fix(libkernel): map a host stack's unmapped pages in runs on Linux
MapUnmappedPages probed every 4 KiB page of the protected range with
msync before mapping it. Under an unlimited stack limit the main
thread's reported stack reaches down to the heap, tens of TiB, so a
guest protect over the whole stack ran for hours. Mapped and unmapped
runs are now found by halving the remaining range, and the unmapped
ones are mapped without reserving swap, as the stack itself grows.
2026-10-16 07:24:41 +00:00
Adrià 02a1b772ed Merge pull request #5770 from simonbronk/fix/kernel-mprotect-undefined-bits
fix(libkernel): drop undefined protection bits in sceKernelMprotect
2026-10-15 17:53:02 +02:00
Yunus Shaikh f29ee47366 refactor(libkernel): record a host stack protect's guarded part on its own line
The stack branch now records the reserve and guard below a protected
range with a separate RecordProtection call, and keeps the call that
records the protected range itself as main has it. The ranges recorded
are the same: RecordProtection replaces what it covers, so the two calls
together record the whole requested range, as before. #6184 adds a line
next to that call, and the two no longer touch.
2026-10-15 08:52:21 -07:00
Yunus Shaikh 5796ddfcfd fix(libkernel): commit a protect at the bottom of a host stack's reserve
HotSpot makes its stack guard zones with an RW protect of the lowest
pages of the thread's stack, then PROT_NONE, as it commits them on
native Windows (os::pd_create_stack_guard_pages, then os::guard_memory).
Below a host stack's guard page such a protect was only recorded, so the
pages stayed reserved: they could not be written after the RW protect,
and the zones never held.

A protect of reserved pages that starts at the bottom of the reserve and
stops short of the guard page now commits and protects them. The guard
page and the reserve above the range stay as they are, so the stack still
grows through the guard down to it, and the stack limit in the TEB still
follows the committed stack.

Windows moves the guard down by committing the pages below it as
read/write guard pages, committed or not. The zones therefore hold until
the stack is within one guard region of them (three pages on GitHub's
runners), and the pages the guard reaches then come in read/write. The
test checks both, and the debt entry says so.
2026-10-15 08:10:42 -07:00
Yunus Shaikh 3724c577d8 fix(libkernel): keep a host stack's guard page and reserve when protecting it on Windows
Committing the reserved pages of a host thread's stack before protecting
it, as the stack branch did for a range the arena doesn't own, also
cleared the guard page's PAGE_GUARD. The thread was left with no guard
and no reserve: an overflow ran into whatever lay below the stack instead
of raising a stack overflow, and the stack limit in the thread's TEB,
which Windows moves only when the guard page is hit, stopped following
the stack. A range that began inside the reserve also left the reserved
pages below it with no guard above them, so the stack could no longer
grow into them.

The stack branch now leaves the guard page and the reserved pages below
it as they are, and commits and protects only what lies above them;
reserved pages above the guard are still committed first. The protection
is recorded for the whole range, and a range of only reserved and guard
pages changes nothing on the host. The test protects the main thread's
whole stack and a reserved thread's whole stack and upper part, then
checks that the guard page is still there and that the stack grows
through it, also after a PROT_NONE protect of its lowest page. The debt
file records that those pages come in read/write as the stack grows.
2026-10-15 08:10:42 -07:00
Yunus Shaikh b5909a5ee0 fix(libkernel): map the unmapped pages of a host stack before protecting it on Linux
On Linux the guest's main runs on the host main thread's stack, which
the kernel maps only as it grows. sceKernelIsStack reports the whole
range that pthread_getattr_np gives, which is sized by RLIMIT_STACK and
is mostly not mapped yet. A protection of that range failed with ENOMEM,
so mprotect returned EINVAL and sceKernelMprotect stopped the title.

When the stack branch's mprotect fails with ENOMEM, the range's unmapped
pages are now mapped read-write at their own addresses
(MAP_FIXED_NOREPLACE) and the protection is applied again. This matches
how the reserved pages of a host stack are committed on Windows.
2026-10-15 08:10:42 -07:00
Adrià d8862a63ba Merge pull request #5703 from EagleBearerYS/fix/libkernel-protect-reserved-host-stack
fix(libkernel): commit a reserved host stack before protecting it
2026-10-15 17:04:17 +02:00
Ondra97 0cbec9f8f4 fix(libkernel): release flexible memory budget through munmap 2026-10-15 12:50:29 +02:00
al3w0f205 e03e6f7a4e feat(libkernel): add munlockall export
Follows mlockall (#4386) for XPSemu (PPSA97358, QEMU os-posix.c), which
imports munlockall (NpLBpgVV7PU) from libkernel.prx. Predicted stop:

  FAIL: unresolved ELF import NpLBpgVV7PU from libkernel.prx

The NID is computed with tools/nid_names.py and matches aerolib.

Follows FreeBSD 11.4 sys/vm/vm_mmap.c sys_munlockall
(8c639945a44588f6cfdddfb057bb5aad88735da0): checks PRIV_VM_MUNLOCK,
clears wire state and returns 0. To match, munlockall unlocks ranges
locked by mlock (through VirtualUnlock on Windows, tolerating
ERROR_NOT_LOCKED, and munlockall on Linux).
2026-10-14 18:07:34 -05:00
simonbronkandClaude Opus 5.5 3da081aaad fix(libkernel): drop undefined protection bits in sceKernelMprotect
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 21:51:52 +02:00
Adrià 9811e9d4b7 Merge pull request #5218 from YossiYad/fix/guest-arena-mapping-hint
fix(libkernel): fall back below a mapping hint with no room above it
2026-10-14 21:05:23 +02:00
Adrià 066442c961 Merge pull request #5143 from xXPBSXx/fix/mprotect-unmapped-einval-v2
fix(libkernel): fail sceKernelMprotect over an unmapped range with EINVAL instead of aborting
2026-10-14 21:05:05 +02:00
Adrià 587b63d2a3 Merge pull request #5073 from krishalivaibhav/codex/memory-service-lifetime
fix(memory): preserve process-owned services during exit
2026-10-14 20:33:53 +02:00
fma-rc c1783f9d64 fix(libkernel): register a relinked guest module's image when Linux protects its pages 2026-10-14 18:24:45 +02:00
Yossi Yadgar a016b4f2bc fix(libkernel): fall back below a mapping hint with no room above it
A mapping without MAP_FIXED treated its address as the lowest place it
could go, and a hint at or above the end of the guest arena threw on the
host. FreeBSD 11.4's vm_mmap_object places such mappings with
vm_map_find_min, which takes the address as a hint only: it tries at or
above it, then again from its minimum address.

GuestArenaAllocateFromHint does the same in the arena: at or above the
hint when it lies below the arena's end and a range fits there, otherwise
from the arena's start. MapPlaced and the Windows mmap_aligned use it for
hinted mappings; GuestArenaAllocateAtOrAbove keeps its meaning for the
callers that need a range above an address.

PS5CEMU-HAR (PPSA99360) reserves its JIT range with
sceKernelReserveVirtualRange and a hint near its own code, a host address
above the arena here, and aborted with "mapping address hint is above the
guest address space arena" when launching a 3DS title.
2026-10-14 17:41:31 +03:00
Adrià 5adefa6f89 Merge pull request #5643 from Amirtheshwaran/feat/libkernel-mincore
feat(libkernel): implement mincore
2026-10-14 16:25:54 +02:00
Adrià 1b55ee4ab3 Merge pull request #5610 from Dripl1x/codex/feat-libkernel-fixed-anonymous-mmap
feat(libkernel): support fixed anonymous mmap
2026-10-14 14:52:53 +02:00
Adrià a628765e58 Merge pull request #5053 from YossiYad/feat/libkernel-mmap-regular-files
feat(libkernel): map regular files with mmap on Linux
2026-10-14 14:41:32 +02:00
Adrià FranchandClaude 2854d51352 fix(libkernel): follow kern_mincore order and report reserved pages as not resident
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-14 14:40:12 +02:00
Amirtheshwaran Navaneethakrishnan 3699eff904 fix(libkernel): round mincore address down as FreeBSD does
Follow FreeBSD 11's sys_mincore by rounding unaligned address down to page boundary rather than returning EINVAL. Update guest memory test and document unmodeled residency/referenced/modified bits in libkernel technical debt.
2026-10-14 14:40:08 +02:00
Amirtheshwaran Navaneethakrishnan 7781eda113 feat(libkernel): implement mincore
Implement mincore (+hFjyohmOU0) in libkernel following FreeBSD 11's sys_mincore (sys/vm/vm_mmap.c). Validate page alignment, return EFAULT for null vector, check range bounds and residency via sceKernelVirtualQuery, and report MINCORE_INCORE (1) for resident pages. Required by Java 25 LAN / DNS (PPSA99869).
2026-10-14 14:40:08 +02:00
Adrià aa6b757662 Merge pull request #4725 from akkadbakkad89/feat/kernel-page-table-stats
feat(libkernel): count committed ranges in sceKernelGetPageTableStats
2026-10-14 12:56:24 +02:00
Dean Galvin 8cc20401a2 fix(libc): forget a released section's pages even while views remain on Windows
WindowsMappings keys each physical page's state (moved into the section,
saved bytes of an unmapped resident page) by the section handle value.
sceKernelReleaseDirectMemory frees the backing before it unmaps the views,
so ForgetSection ran while those views still existed and kept their slots.
After the views went, the slots stayed under a handle value that Windows
hands out again, and the next direct allocation whose section got that
value started with the old page state: its first mapping went to the
section instead of private memory, or received the old allocation's bytes.

Views now share ownership of their slot, ForgetSection drops every slot
of the section at once, and JIT shared memory forgets its section before
closing it too.
2026-10-14 21:11:38 +13:00
Yunus Shaikh 187e5fc0ac fix(libkernel): commit a reserved host stack before protecting it
Guest threads run on host stacks that Windows reserves (0x210000 bytes
by default) and commits on demand. Resident Evil Village protects one
thread's whole host stack with 0xc2 at startup while its lowest 0xd000
bytes are still only reserved, so the Windows mprotect emulation threw.
When such a stack sat inside the arena bounds as a host region, the call
took the arena commit path and failed to split a placeholder that was
never one.

Commit the reserved pages of a host range before protecting it, and only
use the arena commit for ranges the arena owns.
2026-10-14 00:28:23 -07:00
Yossi Yadgar bc71ffb433 feat(libkernel): map regular files with mmap on Linux 2026-10-14 09:04:47 +03:00
krishalivaibhav d50eed2df3 fix(memory): preserve process-owned services during exit 2026-10-14 07:18:19 +02:00
akkadbakkad89 975ed1213d feat(libkernel): count committed ranges in sceKernelGetPageTableStats
Charge each recorded protection ranges 2 MiB granules to the gpu
pool when the range has GPU-access protection bits and to the cpu
pool otherwise, so the available counts reflect committed usage
instead of staying at the 2048-entry budget. Follows KytyPS5s
counting model.
2026-10-14 05:14:20 +00:00
Dean ee50655414 Merge pull request #5109 from pushkarreddyy/feat/libkernel-foreign-module-protect
feat(libkernel): support sceKernelMprotect on foreign guest module images on Windows
2026-10-14 17:26:42 +13:00
pushkarreddyy 516b06f945 feat(libkernel): support sceKernelMprotect on foreign guest module images on Windows 2026-10-14 08:19:25 +05:30
xXPBSXxandClaude Sonnet 5.5 238fe1eec7 fix(libkernel): check every part of an mprotect range for pins before protecting the first
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 04:21:32 +02:00
Evgeniy Kazarin 6215101d28 feat(libkernel): support fixed anonymous mmap
Map fixed private anonymous ranges through the existing guest arena. Preserve occupied ranges for MAP_EXCL and use FreeBSD 11.4 errors.

Cover replacement, exclusivity, range validation, rounding, and memory access.
2026-10-14 03:48:36 +03:00
thibautandClaude Opus 5.5 71da166a18 fix(libc): keep resident mappings to direct memory backings on Windows
Map made every singly mapped section page private resident memory. A JIT
or shm_open section is file backed and committed: its bytes live in the
file, and its alias descriptors map duplicated handles, which the physical
page slots do not match, so a resident copy diverged from the file, and
committing its view on a demote failed with access denied
(guest_jit_shared_memory). Only direct memory backings, mapped through the
new GuestArenaMapDirect, now become resident; other sections keep main's
shared views. Shared pages are committed only while their section page is
reserved, as on main.

The socket host write tests map their direct memory a second time, so the
write-protected shared path they check is still the one they exercise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-14 02:39:10 +02:00
DotDebianandClaude Opus 5.5 d9852df2a2 fix(libc): track writes to singly mapped direct memory without faults on Windows
A direct memory page mapped at one guest address now lives in private
MEM_WRITE_WATCH memory at that address, and its writes are collected with
GetWriteWatch like flexible memory: no fault is raised. A page mapped at a
second address moves its whole resident run into the section, behind a
read-only fence while it is copied, and every address becomes a view of it,
tracked by write protection. Unmapped resident pages that are not blank are
kept in a private reservation until they are mapped again, not in the
section.

Ported onto main's 4 KiB subpage tracking of shared views: resident runs
keep a per-page collected bit and enter the fresh ranges, so Fresh and
Armed collections select them like shared views; a demoted run carries its
collected bits into the views and reports every page once. MapAlias throws
through refuse() when a resident run extends outside the aliased range, and
the caller keeps main's fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1W4jdNSKTV7xwuS6xQPJV
2026-10-14 02:39:10 +02:00
xXPBSXx e528ac9c58 Merge remote-tracking branch 'upstream/main' into d-5143-merge
# Conflicts:
#	core/libs/prx/libkernel/CMakeLists.txt
2026-10-14 02:21:10 +02:00
Adelmo Junior 72211b70fe fix(kernel): honor the declared flexible memory budget
Read the optional aligned budget from param.json and apply it consistently to configured, available and mapped flexible memory. Add parser and allocation regression coverage.
2026-10-13 20:13:14 -03:00
Dean 9baec8793f Merge pull request #3870 from yash27git/clean/Direct-Memory-Exception
fix(libkernel): harden DirectMemory validation and tests
2026-10-14 05:55:11 +13:00
xXPBSXxandClaude Sonnet 5.5 05ffb45164 fix(libkernel): fail sceKernelMprotect over an unmapped range with EINVAL instead of aborting
The allocation tracker threw a runtime_error (a hole in the protected range) from inside
sceKernelMprotect, which terminated the title. mprotect already turned the exception into
EINVAL. sceKernelMprotect and sceKernelMtypeprotect now check that the range is registered
first and return EINVAL; the retype of direct mappings is skipped on failure.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 17:41:52 +02:00
MarcZX100 9b6e7f66c4 fix(libkernel): protect host-only guest stack pages 2026-10-13 16:03:36 +02:00