Skip to content

fix(libkernel): report the current CPU within the thread's guest affinity - #1477

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
awake-devel:fix/current-cpu-in-guest-mask
Oct 9, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
awake-devel:fix/current-cpu-in-guest-mask

Conversation

@awake-devel

Copy link
Copy Markdown
Contributor

⚠️ Needs testing on Windows before merge. The shared mapping is tested on Linux, but the Windows branch of sceKernelGetCurrentCpu was not built or run on Windows: the author has no Windows machine. Please build it on Windows and run guest_current_cpu and the full ctest before merging.

What

sceKernelGetCurrentCpu returned the raw host CPU index (sched_getcpu, or the Windows group-adjusted processor number). Guest thread affinities are only recorded, not applied to host threads, and sceKernelGetAvailableCpumask advertises CPUs 0 to 12 (0x1FFF). So on a host with more than 13 logical CPUs (a 16-thread Ryzen, for example) a title could be told it runs on CPU 13, 14, 15 or higher, outside the mask it was given, and index per-CPU data sized from that mask out of bounds. On any host, a thread the title pinned with scePthreadSetaffinity to one CPU could be told it runs on another one, which the console's FreeBSD cpuset never allows.

The host index now selects a CPU of the calling thread's guest affinity clipped to the available mask (the available mask when they do not overlap): host CPU n reports the (n modulo the number of CPUs in that mask)-th CPU of the mask. The result is always an advertised CPU, it stays within the thread's affinity, and a thread pinned to one CPU reports that CPU. Which CPU the console reports for a thread allowed on several is not known; this is recorded in TechnicalDebt. For comparison, shadPS4 returns 0 and fpPS4's older kernel returns the raw host processor number.

This PR was investigated and written by Claude Code (AI), and posted by me after review.

Tested

Linux (Arch), Intel 6-core / 12-thread laptop CPU, GTX 1050 Ti (NVIDIA 580.178.04), GCC, Release, APS5_WRITE_WATCH_IMPORTS=watch.

New guest_current_cpu test:

  • the mapping, for host CPUs 0 to 255 and the masks 0x1FFF, 0x1FFB, 0x3, 0x3F, 0x1000, 0x1, 0xFFFF and 0x10000: the result is always in the clipped mask, and every CPU of the mask is reached once the host has as many CPUs as the mask;
  • sceKernelGetCurrentCpu from the main thread is within sceKernelGetAvailableCpumask;
  • a thread pinned with scePthreadSetaffinity to each available CPU in turn reports exactly that CPU, 64 calls each.

Without the change to sceKernelGetCurrentCpu the test fails on this 12-thread machine (a thread pinned to CPU 12, or to a CPU it is not running on, reports the host CPU).

ctest -j4: 424/424 passed, 0 failed, 0 skipped (unmodified main: 423/423, 0 failed, 0 skipped; the only difference is the new test).
VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ctest -j2 -V: 424/424 passed, 27 Validation Error lines with the same VUIDs and counts as unmodified main (27).
Not tested on Windows; the Windows path only changes where the group-adjusted index is returned.

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 (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

🤖 Generated with Claude Code

https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8

…nity

sceKernelGetCurrentCpu returned the raw host CPU index. Guest affinities
are bookkeeping only and sceKernelGetAvailableCpumask advertises CPUs 0
to 12, so on a host with more than 13 logical CPUs a title could get 13
or higher, and a thread pinned to one CPU could get another one.

The host index now selects a CPU of the calling thread's affinity
clipped to the available mask, so the result is always an advertised
CPU and a thread pinned to one CPU reports that CPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HeC9bA3n74TzJRYv9AgBE8
@popcoder565

Copy link
Copy Markdown
Contributor

Tested on Windows 10 (19045), MinGW-w64 GCC 15.2.0 (WinLibs r7), Release, Intel Core i7-12700H (20 logical CPUs). I merged it onto main 73ac9ef together with #1477, #1482 and #1490 to share one build.

Tested with AI assistance (Claude Code).

@hikazey

hikazey commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Windows run, since the description says the Windows branch wasn't compiled: Windows 11 Pro (26200), MinGW-w64 GCC 15.2.0 (WinLibs r7, the CI build), Release, configured like CI, AMD Ryzen 9 5900X (12 cores / 24 threads, so host CPU numbers run past the 13-CPU guest mask). This commit merged onto main 73ac9ef7, which merges cleanly.

build guest_current_cpu
this PR 10/10 passed
Process.cpp from main (the sceKernelGetCurrentCpu change reverted, test and Pthread.hpp kept) 10/10 failed
full suite with this PR 430/430 passed (main alone: 429/429, plus the new test)

The Windows branch compiles, the processor-group index feeds GuestCpuFromHost as on Linux, and the new test catches the old behaviour on a host with more CPUs than the guest mask.

AI-assisted: yes (Claude Code).

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#1675 core/libs/prx/libkernel/System/src/Process.cpp L15

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Could you rebase onto current main? The full build checks out this branch with main's workflow, and it stops at tools/check_test_registration.py not being on the branch yet, so nothing gets compiled. After a rebase it can get a full build and go in.

@Mouhand-Kaddo

Copy link
Copy Markdown
Contributor

Windows validation of PR head 2ba8f75e15ece357424501f01f13e6d43991d61b, applied unchanged to current main 0fdda7be. This was an isolated validation branch; no other compatibility PRs were included.

Environment: Windows 11 Pro build 26300, Intel i7-13700K (24 logical CPUs), AMD Radeon RX 6900 XT, WinLibs GCC 15.2.0 r7 (x86_64-ucrt-posix-seh), Ninja, Release with BUILD_TESTING=ON and debug symbols. SPIR-V Tools were disabled.

  • Full default build and the separate libs target passed.
  • ctest --output-on-failure -R '^guest_current_cpu$' --timeout 30: passed (0.03 s).
  • An independent runtime reproduction pinned the native thread to host CPU 23 and then set guest affinity to CPU 2. Before the change it reported guest CPU 23, outside the advertised 0x1fff mask, and still reported 23 after the guest affinity change. With this PR it reported guest CPU 10 within the advertised mask and then CPU 2 as requested.
  • Full ctest --output-on-failure --parallel 4 --timeout 30: 508 tests, 504 passed, one skipped, three failed, 82.26 s. The skip was guest_video_out_wqhd_detection_no_vulkan.

The full suite is not clean on this GPU. Its failures were agc_driver_pixel_interlock, agc_driver_sdwa_float_selectors, and agc_driver_sdwa_ldexp_f16. I then checked out unchanged main 0fdda7be, rebuilt the runtime libraries with the same toolchain, and reran those three tests: all three reproduced the same assertion failures (1.04 s). These are baseline failures rather than evidence of a regression introduced by this PR.

This confirms the Windows CPU-reporting contract covered by the PR, including the advertised mask and single-CPU guest affinity. It does not establish a retail-game compatibility result. Validation performed with Codex assistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants