Repository navigation
feat(libSceNpManager): retain the game presence callback and validate content restrictions offline - #9
Closed
KernelPanicNT wants to merge 137 commits into
Closed
feat(libSceNpManager): retain the game presence callback and validate content restrictions offline#9KernelPanicNT wants to merge 137 commits into
KernelPanicNT wants to merge 137 commits into
Conversation
send, sendto, sendmsg, recv, recvfrom and recvmsg failed with EOPNOTSUPP
for MSG_DONTWAIT (0x80), so code that polls a blocking socket with it
got an error on every call instead of its data or EWOULDBLOCK.
FreeBSD 11.4 defines the flag in sys/sys/socket.h:
#define MSG_DONTWAIT 0x80 /* this message should be nonblocking */
and soreceive_generic() (sys/kern/uipc_socket.c) treats it as a
non-blocking socket for that one call:
if ((so->so_state & SS_NBIO) ||
(flags & (MSG_DONTWAIT|MSG_NBIO))) {
SOCKBUF_UNLOCK(&so->so_rcv);
error = EWOULDBLOCK;
goto release;
On Linux and macOS the flag now maps to the host's MSG_DONTWAIT, next to
MSG_PEEK on a receive and MSG_NOSIGNAL on a send. Winsock has no
per-call non-blocking flag, so Windows keeps failing with EOPNOTSUPP
for it; TechnicalDebt records that. Other flags still fail with
EOPNOTSUPP.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ters progress_history passed filter="data" to TarFile.extractall, which only exists from Python 3.12 and the 3.11.4/3.10.12 security releases. On Python 3.10.11 every measured commit raised TypeError, so progress_history failed. Pass the filter when tarfile has data_filter and extract without it otherwise; the archive is git archive output of the repository's own commits.
…2PortGetState sceAudioOut2PortGetState returned the two channels of the host output for every port. It now reports the channel count of the port's data format and clears the rest of the state, so the reserved fields no longer keep the caller's stack contents. The speaker info and system state calls are unchanged; a new test covers all three, since none had one. The channel count follows SharpEmu, another emulator; no console measurement exists, recorded in TechnicalDebt.md. ASTRO BOT and ASTRO's PLAYROOM reportedly stop on an assertion that depends on the reported state (boykopovar#4317); which field matters is not isolated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Four catalog titles (ProsperoTV PPSA99003, ProsperoRadio PPSA99001,
ProsperoLight PPSA99002, ProsperoLichess PPSA99009) locate their own
directory with stat("/app0/eboot.bin"), which always exists on the
console, and fall back to /data/homebrew/<title id> without it; that
directory is empty here, so they fail to load their fonts and die with
"renderer init failed". Staging the original eboot.bin next to the app
resources makes all four load their fonts; ProsperoLichess then renders
(1267 frames in 60 s on Windows).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…put groups The test recompiled and rebuilt the same program for every group of 32 input pairs. Only the input buffer changes between groups, so compile once per compare, EXEC/VCC capture and float mode (96 programs instead of 768) and dispatch it for each group. On lavapipe the test drops from about 11.5 s to 1.3 s; it is the slowest test of the Linux CI run (14.5 s). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceNetCtlGetState reports IPOBTAINED from the host's addresses, but sceNetCtlGetInfo returned NOT_CONNECTED for every code. It now answers from the host interface that holds an IPv4 address, preferring the one with the default route: its address, netmask, gateway, MTU and DNS servers. The link is presented as wired, connected, configured by DHCP and without a proxy, with the Ethernet address sceNetGetMacAddress reports. A null info returns INVALID_ADDR and a code outside 1..21 INVALID_CODE; the Wi-Fi, DHCP host name, PPPoE and proxy server codes throw. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The JpegDec structures were libScePngDec's under new names. OpenOrbis jpeg.h and SharpProspero JpegDec.cs agree on a 12-byte create param, a 0x30-byte decode param with a coefficient buffer, decode mode and down scale, and a 0x24-byte image info that reports the coefficient memory size, the suitable CSC attribute and the output size. Accept the CSC attributes 1 and 2 that SharpProspero passes, fill the output size, component count, coefficient memory size and suitable attribute, apply the requested alpha, and throw for decode modes other than 0 and down scales other than 1. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
GCN and RDNA code reads a compute wave's index in its workgroup from TG_SIZE[11:6] (ACO: s_bfe_u32 tg_size, 6 | 6 << 16). The prologue wrote it only at bit 20, so every wave read 0 there and cross-wave reductions such as RADV's radix sort lost the carries of all but wave 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aps5FiberMain kept the fiber's entry address in rbp when it called the entry, so the guest entry saved that code address as the caller's frame. A guest walking frame pointers from inside a fiber read machine code as a frame record and faulted. libSceFiber is now built with frame pointers: Aps5FiberMain sets up a frame whose saved rbp is the zero of the initial fiber frame, and the chain ends there.
…location A storage image whose surface runs past the end of its registered allocation had every write-back dropped as "memory no longer registered". Titles can size a single-level surface's allocation as pitch x height. A tiled mip's 64 KiB blocks are stored row-major, so that size ends inside the last block row, and the bytes after it are the tail of that row: they hold texels with y < height, which the GPU's own store writes into the next allocation. When the allocation ends inside the last block row and registered readable memory continues to the surface's end, the write-back now stores the whole surface, as the GPU does. Padding slots keep their bytes, since the store writes only bytes that changed. Epic Mickey: Rebrushed streams its lightmaps into an 8160x8160 BC3 pool (SW_64KB_S, 2048 block rows) through a 2040x2040 RGBA32UI alias written by compute. The game allocates 2040 rows, so all its write-backs were dropped and the walls sampled leftover memory as speckled noise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A relink killed between writing <output>.tmp and renaming it left that file behind, and every later relink of the output then fell back to the in-place write, bringing back the failure on a running build. The temporary file is now created under a new name beside the output with O_CREAT | O_EXCL and the previous permission bits, and written through that descriptor, so a file left by an earlier run never blocks a replacement and is never touched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… locks sceAgcCreateInterpolantMapping resolved the pixel shader's ABI, which takes the process-wide shader preparation lock until the scope ends, and then waited under that lock for the vertex shader's background registration preparation. sceAgcCreatePrimState and sceAgcLinkShaders could wait the same way. Every other shader registration and ABI resolution queued behind that one compile: on PPSA07411 the lock was held 8 to 10 s of every 10 s, almost all of it waiting for registration preparations, while its loader threads waited 13 to 45 s per 10 s to take it. A preparation scope now names the shaders it resolves and waits for their registration preparations before it can take the lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e library Every library under core/libs/prx links the libc and libkernel import libraries, and every NID patch step depended on the unpatched libc.prx. GNU ld 2.46 rewrites the import library on every link with new archive timestamps (the member headers and the symbol map header), so the restat on the link edge never pruned anything: one libc or libkernel .cpp edit relinked all 124 libraries and re-patched all of them. On MinGW the shared library link now writes the import library to <implib>.new with SOURCE_DATE_EPOCH=0 (ld then writes zero member timestamps), makes the symbol map deterministic with ranlib -D and copies the result over the import library only when its bytes differ (cmake -E copy_if_different). The link edge keeps restat, so a link that keeps the exports leaves the import library untouched and prunes every dependent link. The SOURCE_DATE_EPOCH also zeroes the export directory TimeDateStamp of the DLL; the COFF header TimeDateStamp that the unwinder keys on is unchanged. The NID patch steps only use the names libc exports. nid_patcher --write-export-list writes those names, normalized and sorted, to libc.exports and leaves the file untouched when they did not change; the patch steps read it with --preserve-export-list and depend on it instead of libc.prx, on every platform. A patched library is byte-identical to one patched against libc.prx. Measured on Windows (GCC 15.2, -j 4, loaded machine) after touching libc/src/Strings.cpp: with CMAKE_LINK_DEPENDS_NO_SHARED off, 124 links and 124 patches in 74.9 s before, 1 compile, 1 link, the export list and the libc patch in 4.3 s after; with it on, 124 patches in 7.8 s before and the same four steps in 5.3 s after. Touching libkernel/Time/Time.cpp runs 123 links and 123 patches (89.1 s) before and one compile, link and patch (3.4 s) after. Removing a libc export still relinks and re-patches all 124 libraries. nid_patcher_macho covers --write-export-list (sorted normalized names, no rewrite when unchanged, rewrite when changed) and --preserve-export-list (the same exports kept as with --preserve-exports; malformed lists and two references refused). It fails on main, where the option is unknown. Sources: SOURCE_DATE_EPOCH, https://reproducible-builds.org/specs/source-date-epoch/; ranlib -D and ld --out-implib, GNU binutils documentation; ninja restat, https://ninja-build.org/manual.html#ref_rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…locks On a host-imported surface a storage write-back keeps the 64 KiB blocks the CPU wrote since their tracked layer's generation, stores the rest and stamps the stored ranges with MarkWritten. Settling advanced the stored layers' generations past those stamps only when no layer kept a block (or when an adjacent pending surface needed the collect). When one tracked layer kept a block, every other stored layer kept its old generation, so the write-back's own stamps read as CPU writes: the next write-back kept those layers as well and did not store the GPU's newer results over them. A tracked layer is one 64 KiB unit when the surface has block units: tiled (not linear), 64 KiB-aligned base, not thick, with layer and block tracking on. Otherwise it is an array layer (64 KiB-aligned layer slices, layer tracking on) or the whole surface. Settling now collects and advances each stored layer that kept no block; a layer that kept a block keeps its old generation and re-uploads at its next use, as before. When no stored layer advances (nothing stored, or every selected layer kept a block, such as a single tracked layer that kept one), no adjacent pending surface needs the collect and no unit was retiled into the unit shadow, settling still skips the collect, as main did. Units retiled into the unit shadow are now marked at the settle collect's generation also when a block was kept; main marked them at TrackerGeneration() there without collecting. The two differ only for a CPU write to a stored unit made after the keep decision: main left it to a later walk, which made the retiled unit stale so the CPU's bytes won; now the walk stamps it at the marked generation and the stored results win, as they already did when no block was kept. agc_storage_kept_unit_settle uses a 1024x512 RGBA8 surface in 64 KiB tiling (32 block units): it writes one byte of unit 0 from the CPU, stores a red clear, stores a blue clear, and requires units 1-31 to hold blue and unit 0 to keep the CPU's byte after both stores. On main the GPU-mapped direct memory case fails with unit 1 still red. The watched-memory case (host imports off: the write-back that stores through the CPU) passes on main; it guards the kept layer's old generation and fails when settling also advances a layer that kept a block. The test returns 77, naming the reason, when the direct-memory case cannot run: no write watching, no host imports, direct memory not write-watched, or its host import refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ompared agc_storage_kept_unit_settle checked that the GPU-mapped direct memory was write-watched before it made the host import. On Linux, when host imports resolve write protection and dma-buf imports keep it, the host-pointer import is tried first in a window that does not stay watched, and dma-buf only when it fails (importAllocation in GuestBufferMemory.cpp). Where the host-pointer import of shared memory succeeds, as on Intel's ANV, the import takes the direct memory out of the write watch, so the case ran on the compared path: the upload saves the guest bytes, the first write-back keeps unit 0 by comparison and drops the saved bytes of every unit it selected, and the second write-back has nothing to compare. Before e544993 it stored every unit whole, over the CPU's byte in unit 0, which is the failure reported on Linux; on main it throws (technical debt: results over memory outside the write watch without saved bytes). Neither depends on the settle change. On Windows, importing watched private memory (compared there) reproduces both: on 7e181fc, with or without this branch's Texture.cpp change, the second check fails with that message; on main the second write-back throws. The case now checks the write watch again after the import and returns 77, naming the reason, when the import took the memory out of it. Where the import keeps the memory watched (the Windows alias import, a Linux dma-buf import) it runs as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pointer-shaped NID kW3GLb7QfPg calls from public homebrew succeed on console; returning an error left those titles failing init after boykopovar#4835.
…p-wait fix(agc): settle registration preparations before a preparation scope locks
…k-overhang fix(agc): store a storage image whose last block row runs past its allocation
docs(build): link the supported WinLibs release
docs(user): stage the original eboot.bin in app0
A sampled depth texture whose layers are all backed by host depth surfaces is gathered host-to-host, plane by plane. The gather located the surface for layer n at base.address + n * DepthSliceBytes(extent), the host depth slice stride, and required the guest descriptor's sliceLinearBytes to equal that stride. Bendy and the Ink Machine (PPSA27616) samples a 64x64 F32 cube over six D32 depth surfaces. The descriptor's per-layer footprint is the tiled depth slice, but its linear footprint is smaller, so the check refused a valid resource and the game aborted as soon as it sampled the cube. Locate each layer at base.address + geometry.GuestLayerOffset(layer) instead. That is the address the descriptor itself uses, and the one the guest-memory fallback already used, so both ways of finding a layer agree by construction. Keep the geometry check for the mixed case, where a layer has no host surface and is filled from guest memory, because that path lays its layers out at sliceLinearBytes. The storage-image path still refuses a layer pitch that is not the depth slice size; that is unchanged and out of scope.
…nternal-helper-nids fix(videoout): keep mouse helpers out of NID exports
…rivatives-linear-groups fix(shader): group compute derivatives by four consecutive lanes
…ess-lock-1488 fix(libkernel): defer raises while a thread holds the address-wait lock on Windows
…lice-htile fix(agc): give each slice of a depth array its own HTILE
…ack-any-storage fix(agc): store a written storage image over a depth plane into the surface
…compile test(agc): compile each v_cmp denormals program once for its eight input groups
…out2-advance-grains fix(audio): preserve completed AudioOut2 grains across threads
…ve-id fix(shader): put the compute wave index in TG_SIZE[11:6]
…-walk perf(libc): remember clean pages once per run in Windows write collects
…mpress-msaa fix(agc): handle FMASK decompress on MSAA targets
…ration-preparation-at-submit fix(agc): wait for queued registration preparations before accepting a submission
…be-gather fix(agc): gather a sampled depth cube at the descriptor's layer offsets
…info fix(libSceNetCtl): answer sceNetCtlGetInfo from the host IPv4 interface
…erence-abi fix(libSceJpegDec): use the JpegDec parameter and image info layouts
…service-lifetime fix(memory): preserve process-owned services during exit
…k-out-of-range fix(agc): return 0 for out-of-range sceAgcInit without table lookup
…e-capture-status refactor(libSceShare.native): drop duplicated exports
…undancy perf(shader): avoid redundancy traversal map copies
…host-streams fix(libkernel): keep host standard streams open on guest close
…tat-symbolic-links feat(libkernel): report relative symbolic links in lstat on Windows
… content restrictions offline sceNpSetContentRestriction takes the 0x18-byte restriction and the checks of shadPS4: a null restriction returns INVALID_ARGUMENT, a size other than 0x18 INVALID_SIZE, and a negative default age, more than 256 age restrictions or a count with no array INVALID_ARGUMENT. Any other restriction returns success, a negative count included as in shadPS4; nothing is enforced while signed out. sceNpRegisterGamePresenceCallback retains the callback and its user data as shadPS4 does. No game presence event is delivered while the NP model stays signed out, as for the reachability callback, and the test checks that a registered callback is never called. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KernelPanicNT
force-pushed
the
feat/libscenpmanager-presence-content-restriction
branch
from
October 14, 2026 18:47
fa22c75 to
4654163
Compare
Owner
Author
|
Superseded: published upstream; closing the CI draft. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Implements
sceNpSetContentRestriction(NIDA2CQ3kgSopQ) andsceNpRegisterGamePresenceCallback(NIDuFJpaKNBAj4) on the existing signed-out libSceNpManager model, and replaces the opaque 128-byteNpContentRestrictionwith its 0x18-byte layout.Source of the behaviour. No console measurement is involved.
OrbisNpAgeRestriction/OrbisNpContentRestrictionatf47bbd5np_manager.h L56-L68:u64 size; s8 default_age_restriction; u8 padding[3]; s32 age_restriction_count; const OrbisNpAgeRestriction* age_restriction;with an 8-byte age entry (4-byte country code,s8age, 3 padding bytes). KytyPS5, a PS5 emulator, has the same two structures (network.cpp L3799-L3811); this was pointed out in the review of feat(libSceNpManager): implement sceNpRegisterGamePresenceCallback and sceNpSetContentRestriction boykopovar/AnyPS5#926.sceNpSetContentRestriction: shadPS4 np_manager.cpp L748-L763, in this order: null restrictionORBIS_NP_ERROR_INVALID_ARGUMENT;size != sizeof(OrbisNpContentRestriction)ORBIS_NP_ERROR_INVALID_SIZE; negative default age or more than0x100age restrictionsINVALID_ARGUMENT; a positive count with a null arrayINVALID_ARGUMENT; otherwiseORBIS_OK. The values are0x80550003and0x80550011(np_error.h L11 and L26);0x80550003is theSCE_NP_ERROR_INVALID_ARGUMENTthis file already uses. KytyPS5 also rejects a null restriction and a wrongsize(network.cpp L3960-L3964), as unimplemented paths.sceNpRegisterGamePresenceCallback(callback, userdata)returns nothing and stores the callback and user data, replacing any earlier registration: shadPS4 np_manager.cpp L1121-L1126; KytyPS5 has the samevoid (void*, void*)signature (network.cpp L4007-L4009). No game presence event is delivered while the model stays signed out, as with the reachability callback merged in fix(npmanager): track reachability callback registration boykopovar/AnyPS5#1322.Changes:
core/libs/SceTypes.hpp:NpAgeRestrictionand the 0x18-byteNpContentRestriction, withstatic_asserts on both sizes.sceNpSetContentRestrictionis the only user of the type.core/libs/prx/libSceNpManager/Export.cpp:sceNpSetContentRestrictionapplies the checks above in shadPS4's order and returns 0 for a valid restriction, which nothing enforces while signed out.sceNpRegisterGamePresenceCallbackstores the callback and user data under its own mutex.SCE_NP_ERROR_INVALID_SIZEis added.core/libs/tests/GuestNpManager.cpp:guest_np_managercovers an empty restriction, two and 256 age entries, 257 entries, a count with a null array, zero count with a null array, a negative default age, a larger and a zerosize,sizechecked before the ages, and a null restriction; and registering, replacing and clearing the presence callback without it being called.docs/dev/debt/libSceNpManager.md: one entry per call under Functional, with the pinned shadPS4 lines and what is unverified.What is unverified: the checks and error codes are from the PS4 library; a negative
age_restriction_countis accepted, as in shadPS4. The restriction is validated and dropped. No case throws.Progress: libSceNpManager 30/34 → 32/34; system libraries 3249/3678 (88.34%) → 3251/3678 (88.39%) by
tools/progress.pyon the branch basecaee23f.Tested
Head
9c961016cddd9d9727d5d7b65b6c47ebf131b8c3, base84b01f9cd042e1d2e9e112f8783aa5a9d26399ee.BUILD_TESTING=ON, tests run under QEMU 8.2 user mode with-cpu EPYC-Romebecause the build host lacks AVX2):guest_np_manager_tests5/5 passes.core/libs/prx/libSceNpManager/Export.cppwith the base version:guest_np_manager_testsfails withsceNpSetContentRestriction not implemented. Restoring the PR source and rebuilding passesguest_np_manager_tests5/5.git diff --checkpass. The Linux job of the Build workflow now targets the project's self-hosted runner, so it was not run on the fork; no title was run.Duplicate and overlap check
Checked the files of all 443 open PRs on 2026-10-14 and searched open, merged and closed PRs for both names. No open PR implements or names either function.
Open PRs sharing a file (pairwise
git merge-treeagainst each PR head):libSceNpManager/Export.cpp,GuestNpManager.cpp,sceNpGetUserIdByAccountId) already conflicts withmainindocs/dev/TechnicalDebt.md; this branch adds no conflict file or block, and its hunks in the two shared files are apart from ours.SceTypes.hpp: no conflict.Earlier PRs on the same functions, all closed: boykopovar#926 (the review asked for the 0x18-byte layout and the
INVALID_SIZEcheck, which this PR has), boykopovar#2398, boykopovar#2829, boykopovar#3187 (null check only) and boykopovar#4531. boykopovar#4531 had the same layout and checks (it also rejected a negative count) and was closed on 2026-10-14 because no title was shown reaching either call onmain; the review said the layout and checks were fine. This PR does not supply a title stop either (Unblocks is none).The branch is one commit on
caee23f; none of the newer commits onmain(84b01f9) touch these files, and it merges without conflicts.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)