Skip to content

fix(memory): validate guest memory fast paths - #1

Draft
mashingaan wants to merge 6 commits into
mainfrom
validation/guest-memory-fastpath
Draft

mashingaan wants to merge 6 commits into
mainfrom
validation/guest-memory-fastpath

Conversation

@mashingaan

@mashingaan mashingaan commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

What

  • Invalidate the Windows guest page-state cache after GuestArenaCommit changes reserved pages to committed pages.
  • Implement the C++ runtime current-thread ID export by delegating to scePthreadGetthreadid.
  • Keep both changes in the validation branch for hosted CI verification.

Tested

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw or are covered by the existing implementation
  • No notes or generated files added to the repository
  • Generic behaviour, not specific to one title
  • AI-assisted: yes
  • Depends on: none

Tamalero and others added 6 commits October 15, 2026 10:14
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.
On Linux kernels without PROCMAP_QUERY (before 6.11, which includes the
stock Ubuntu 24.04 kernel), every guest range check that misses the page
cache reads and parses /proc/self/maps up to the covering mapping. The
cache only covers the guest arena and the image, so ranges in the host
heap always miss. ASTRO BOT (PPSA21564) checks 96-byte shader headers
there from RegisteredHeader (through SameHeader) on every
sceAgcCreatePrimState and interpolant mapping, about 3,700 times per
second while it loads.

A read-only check of at most 4 KiB on such a kernel now first reads the
range into a scratch buffer with process_vm_readv on the own process.
If every byte is read, the range is readable. Anything else (a fault,
a partial read, a refused call, a write check or a larger range) takes
the path it took before, which also builds the failure message.

agc_driver_graphics runs a second time with APS5_NO_PROCMAP_QUERY=1, so
the fallback path is covered on kernels that have PROCMAP_QUERY too, and
LiveStack gains read-only checks: a readable range, and ranges that end
in a guard page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Progress report (f633042 → 75e8795)

📈 System libraries: 88.72% (+0.02%, +1 implemented functions)

✅ 1 implemented
Library Name
libSceAmpr _Thrd_id_nid_postfix

@mashingaan mashingaan changed the title validation: combine guest memory fast paths fix(memory): validate guest memory fast paths Oct 15, 2026
mashingaan pushed a commit that referenced this pull request Oct 18, 2026
…ll or crash

A GPU hang or a crash in a title leaves no record of what the queues
were last given: APS5_TRACE_GPU prints every submission (too much to
leave on), and the WAIT_REG_MEM timeout message shows only the packet
before the wait on the waiting queue.

Each queue now keeps a ring of its last 16 submissions
(APS5_PM4_RING=<n>, 0 to 4096, 0 disables): the TraceMs time in tenths
of a millisecond, serial, size, guest address and a copy of the first
512 dwords after indirect buffers are inlined, recorded under the
driver lock next to the serial, REWIND tails included. The ring of a
queue and the failure report registration are set up at the top of
Submit, before any output is reserved, so recording under the lock
does not allocate. Disabled, Submit only tests a static flag; enabled,
it costs one bounded copy per submission.

DumpSubmissionRings decodes the kept dwords with Pm4::PacketWords and
the new Pm4::KnownName, which returns the decoder's names as views of
static strings (empty for an unknown opcode, printed as UNKNOWN_0x%02x);
Pm4::Name now builds its std::string from it. Every line is formatted
with integer and string conversions only into a 512-byte stack buffer
and written with one WriteFile / write(2) on the stderr handle, so the
dump does not allocate from the C runtime heap, lines from other
threads do not interleave and the CRT stream lock is not taken (the
rule of boykopovar#3871). The header gives the number of queues and the ring
size, and each queue line the submissions recorded and kept.

libc gets a small registry of failure reports
(LibcRegisterFailureReport_nid_no_patch, Unregister, Run); Run runs
the registered reports the first time it is called and returns at once
after that. The Windows crash report runs it after the thread dump of
an unhandled exception, after SIGABRT (which also covers the
APS5_HANG_DUMP_SECS timed dump, since it aborts) and after an invalid
CRT parameter, so an abort after a reported exception does not print
the rings twice. The driver registers its dump at the first submission
and unregisters at static destruction; the dump there waits a bounded
time for each ring lock. What the crash-path dump cannot do (a ring
held by the crashed thread, rings corrupted by the crash, Linux) is
recorded in technical debt.

APS5_STALL_WATCHDOG_SECS=<n> (0 to 86400, 0 disables) makes a waiter
that has not progressed for n seconds dump the rings once per wait: a
WAIT_REG_MEM (progress as for APS5_GPU_WAIT_TIMEOUT_MS: another packet
runs or completes), a REWIND waiting for the title, and a compute
submission held behind queue 0. The last one prints under the driver
lock, so submissions and the other queues wait for it (USAGE.md says
so). Both variables are read at the top of Submit, so an invalid value
of either throws at the first submission and never later inside a GPU
worker. The order wait behind queue 0 releases its order hold on scope
exit, so a throwing dump cannot leave it counted.

No packet semantics change; packet sizes and names are those of the
existing decoder (PM4 type-3 header layout as in Mesa
src/amd/common/sid.h). The queue bound of Submit and of the rings is
one constant, SubmissionQueueEnd.

Tests: agc_driver_pm4_tests gets ten modes, each its own ctest:
agc_driver_pm4_ring (APS5_PM4_RING=4, six submissions on queue 0 and
two on 0x20: the dump holds #3..boykopovar#6 and #1..#2 in order, nothing
older), agc_driver_pm4_ring_empty (one line), _ring_disabled (one
line), _ring_invalid and agc_driver_pm4_stall_watchdog_invalid
(APS5_STALL_WATCHDOG_SECS=1x: the submission throws and is not
executed), _ring_report (LibcRunFailureReports_nid_no_patch dumps the
rings), _ring_report_heap (Windows: with ucrtbase.dll's HeapAlloc and
HeapReAlloc imports counting calls from the reporting thread, the
failure report of a submission holding INDEX_BUFFER_SIZE names it and
allocates nothing, while Pm4::Name of the same header is seen
allocating), and with APS5_STALL_WATCHDOG_SECS=1 a WAIT_REG_MEM
(agc_driver_pm4_stall_watchdog), a REWIND (_stall_watchdog_rewind) and
a compute submission held behind a queue 0 rendering wait
(_stall_watchdog_order), each held for about 2.5 s, dump once and
complete when released. The PM4 catalog test checks KnownName against
every opcode and custom name. windows_backtrace_failure_report checks
that abort() runs the registered reports once and not an unregistered
one; windows_backtrace_failure_report_once that abort() does not run
them again after an earlier run. With the dump decoding through
Pm4::Name, agc_driver_pm4_ring_report_heap fails with "the failure
report allocated from the C runtime heap"; with Run resetting its
flag, windows_backtrace_failure_report_once prints the report twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mashingaan pushed a commit that referenced this pull request Oct 18, 2026
feat(ssl): run TLS 1.2 client connections over Mbed TLS
mashingaan pushed a commit that referenced this pull request Oct 18, 2026
mashingaan pushed a commit that referenced this pull request Oct 18, 2026
…stages

Since boykopovar#3878 every vertex program that exports a position also writes
gl_ClipDistance for the all-zero position distance. The tessellation
stages generated for rect lists declared only gl_Position in gl_in, so
their input interface no longer matched the vertex outputs; on MoltenVK
the control stage then reads all-zero positions and every rect-list
draw stops with "rect-list requires finite nondegenerate axis-aligned
positions" (reported in #1).

The control and evaluation stages now declare the vertex program's
gl_ClipDistance array in their per-vertex blocks and forward it. The
generated fourth corner gets the clip distances interpolated with the
same weights as its position, so the all-zero position clip keeps
working for rect lists. Validation accepts gl_ClipDistance as a
tessellation input and as a tessellation-control output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QXdkh9PHBCPqGcGQPeikAe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants