COPY_DATA rejected source select 9 (GPU clock count) and any cache
policy bits. PPSA16064 (Minecraft Dungeons II, Unreal Engine)
calibrates its GPU timer at start-up with a submission of five
COPY_DATA packets, control 0x06016209: GPU clock source, memory
destination, 64-bit count, source and destination cache policy 3. The
submission was rejected and the title aborted.
The clock source now writes the same counter as a RELEASE_MEM
timestamp (the host steady clock in 10 ns ticks), read when the packet
runs, through the direct execute path and through ResolveStore for
stores recorded on the GPU. A 32-bit count writes its low half. The
source and destination cache policy fields are accepted and ignored,
as for WRITE_DATA and DMA_DATA. The reference clock (source select 10)
and the other unimplemented sources still throw.
agc_driver_pm4 runs the title's packet twice and checks a nonzero,
non-decreasing counter and an 8-byte resolved store, and that source
select 10 is still rejected.
MinGW's thread_local goes through emutls and winpthreads' pthread_getspecific, which holds a per-thread spinlock. A raise that redirected a thread holding it ran the handler on that same thread, and a handler reading any thread_local, scePthreadSelf for one, spun on the lock forever. A raise that finds the target inside libwinpthread-1.dll now resumes it and suspends it again, as one inside NtContinue does.
guest_raise_exception's new phase raises at a thread that calls scePthreadSelf in a loop and checks that the handler sees its own thread. It hung in every run without the retry. TechnicalDebt records that a handler can still reenter other host code the thread was interrupted in.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The guest's wchar_t is 16 bits, but wcslen, wcscmp, wcsncmp, wcscpy, wcsncpy, wcschr, wcsrchr, wcsstr, wcspbrk, wcsspn and the wmem functions forwarded to the host's wchar_t functions, which use 32-bit units on Linux. Implement them on char16_t. The wide conversions that still use the host's wchar_t are listed in TechnicalDebt.
NVIDIA (595.91.07) refuses VK_EXT_external_memory_host imports of
read-only or executable mappings with VK_ERROR_OUT_OF_DEVICE_MEMORY and
then fails every later vkAllocateMemory on the device. Check the range
is mapped read-write before importing on Linux, as the Windows path
already does for read-only memory, and copy it otherwise.
Refs #1022
Exclude COLOR_INVALID attachments from the effective write mask while preserving later MRT export indices and depth-only rendering. Validated with the graphics tests and Skyrim menu draws.
AI-assisted implementation and testing by OpenAI Codex.
guest_formatting called sprintf with four variadic arguments and
libc_printf with one, all in registers, and did not call sscanf, so only
snprintf had a check that fails with the old Linux register rebuild. sprintf
now formats six integers, sscanf converts eight fields and libc_printf prints
seven integers; on the old code the first gives "1 2 3 4 0 0" and the other
two crash.
Checks suggested by nauroth in #1435.
The host's EHOSTUNREACH was reported as ENETUNREACH (51); FreeBSD's
EHOSTUNREACH is 65, which libkernel's sockets already report. EADDRNOTAVAIL,
ENOBUFS, EISCONN, ENOTCONN and EACCES had no translation and became EIO;
they now map to 49, 55, 56, 57 and 13, as in libkernel/Socket/src/Udp.cpp.
guest_sce_net connects the connected client again and expects EISCONN
(0x80410138); before this change it received EIO.
A CMASK holds 4 KiB per 1024x512-pixel metablock, not one nibble per 8x8
tile of the target: 1920x1080 spans 0x6000 bytes, as titles clear it,
not 16200. The swizzled nibbles of the lower-right tiles lie past the
packed size, so the fast-clear check missed them and the expanded store
left them cleared.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A non-blocking sceNetConnect that cannot complete at once must fail with
EINPROGRESS (36, 0x80410124), as FreeBSD's connect does, and a repeated call
while it is pending with EALREADY (37). On Windows, Winsock reports the
first case as WSAEWOULDBLOCK, which was translated to EAGAIN (0x80410123); on
Linux, EINPROGRESS and EALREADY had no translation and became EIO
(0x80410105). Code that waits for the connection only when connect reports
EINPROGRESS treated both as a failed connection.
guest_sce_net connects a non-blocking socket to the loopback listener and
accepts 0 or EINPROGRESS; before this change it received EAGAIN on Windows.
sceKernelGetModuleInfoForUnwind and sceKernelGetModuleInfoFromAddr each
parsed .ehmeta and the eh_frame_hdr it names. Both now read them through
Module/EhFrame.hpp, so a bad table fails the same way in both: an
eh_frame_hdr version other than 1, an indirect or non-absptr/pcrel
encoding, a 64-bit record length or anything outside the image throws.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01JkiyF6p7oDAaTtVe8ci5zP
tools/nid_names.py resolves 7gxh+5QubhY to sceAppContentAddcontEnqueueDownload
(compute_nid of the name matches). The stub takes that name instead of
sceAppContentUnknown00 with an APS5_EXPORT alias, so its NID is unchanged and
NotImplemented reports the real function.
Detach the device cache buffer attached by sceFontAttachDeviceCacheBuffer. The signature is taken from the IDA type database of Orbital: it takes the library, a pointer to receive the buffer and a pointer to receive its size. When no cache buffer is attached, it reports NOT_ATTACHED_CACHE_BUFFER. If the library allocated the buffer itself and no buffer pointer is passed, the memory is freed. The owned bit is cleared and device_cache_buf is reset to null.
tests/Mesh.cpp called setenv and std::aligned_alloc, which MinGW does not
provide, so agc_driver_mesh_tests did not compile on Windows. The 64 KiB
indirect record block now comes from aligned operator new, and the
environment is set with _putenv_s on Windows, as ShaderDiskCache.cpp does.
The setenv also named APS5_NO_SHADER_DISK_CACHE, which nothing reads; the
shader cache is turned off by ANYPS5_NO_SHADER_CACHE.
The driver copies a submission's packets when it is submitted, but
SET_SH_REG_INDIRECT, SET_UCONFIG_REG_INDIRECT and SET_CONTEXT_REG_INDIRECT
read their (offset, value) lists from guest memory only when the queue
worker reaches the packet. A title that reuses its per-frame memory once
it expects the GPU to be done with it can rewrite a list in between, and
the worker then throws on the data it finds there ("extended register
semantics are not implemented (offset dword 0x3a888889)").
The lists are now read with the packets, after validation, in Submit and
for a rewind tail, and the worker writes the registers from that copy.
Pm4::Execute keeps reading the list itself for direct callers.
PPSA21402 (Balatro) keeps three frame slots and does not wait for the GPU
before reusing one: its slot labels start at 0xffffffff and the GPU only
ever writes 0xffffffff to them, so the poll before a slot is reused never
blocks. When the worker falls more than two frames behind, the title
writes per-draw constants over a SET_CONTEXT_REG_INDIRECT list the worker
has not read yet.
The console's PFP reads the list when it reaches the packet; the
difference is recorded in TechnicalDebt.md.
Both return -1/EINVAL: FreeBSD kern_mprotect (sys/vm/vm_mmap.c) maps only
PROTECTION_FAILURE, RESOURCE_SHORTAGE and OUT_OF_BOUNDS to their own errno, so
KERN_INVALID_ADDRESS falls to EINVAL.
Co-Authored-By: Claude <[email protected]>
mprotect changes the protection of guest memory through the same path
as sceKernelMprotect and reports failures through errno: EINVAL for a
null or overflowing range or a range the allocation tracker rejects,
ENOMEM when allocation fails. A zero length succeeds.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The VA_ARGS parameter list and VarArgsAbi.hpp (RegSaveArea, FillRegSaveArea,
BuildVaList and the Xmm alias in SimdTypes.hpp) were only used by the four
Linux exports that now take their arguments with va_start.
guest_formatting_tests was built on Linux but registered with ctest on
Windows only, so the Linux printf and scanf exports had no coverage: on main
the test fails there at its first vsnprintf check and then crashes in
snprintf with eight integers.
It is registered on every platform now. The %ls checks stay Windows-only,
as glibc reads %ls as 32-bit wchar_t; that gap is recorded in TechnicalDebt.
The Linux vprintf, vsprintf, vsnprintf, vsprintf_s, vfprintf, vasprintf and
vsscanf handed the guest's va_list to the host function, which advanced the
guest's gp_offset, fp_offset and overflow_arg_area. A caller that formats
the same list twice, first to size the output and then to write it, got its
second call's arguments from past the end.
The Windows path reads its arguments from a copy (LibcDetail::FormatArguments)
and guest_formatting checks that vsnprintf leaves the list unchanged. Linux
now does the same with va_copy.