A blind re-review of the previous commit (six lenses, fresh reviewers)
found real gaps in the hardening itself. Addressed here:
- The EVTSTRM gate failed open to the spin: with the event stream absent
on a core whose armed WFE does not park, disabling the fallback
reinstated the original full-rate spin. The paced tier now degrades to
a 100 us scheduler sleep instead, which also keeps the timeout and
service polls running at a bounded cadence.
- Gate the FIFO-idle wait_for_event() the same way (three reviewers
independently flagged the contradiction between asm.hpp's new
precondition and this ungated sibling). Without the stream it yields,
which is that path's pre-WFE behavior.
- Non-Linux ARM64 now defaults to the previous commit's behavior instead
of silently disabling the fallback: the false default was a regression
against 002a9b274 on the Apple Silicon and Windows-on-ARM targets, and
no HWCAP equivalent exists there to probe.
- The loop's snapshot is now read through the existing atomic reference
(relaxed observe()) instead of a plain reference: the previous form was
a formal data race whose correct codegen depended on an unrelated
virtual call staying opaque to the optimizer.
- Guard unaligned semaphore addresses on the acquire path: exclusive
loads fault on unaligned addresses, semaphore_release already rejects
them, and acquire did not. Unaligned waits now use the paced tier only,
with a warning.
- Surface the probe in the startup capability string (EVTSTRM-on/off) so
every log records which wait shape was selected; previously the three
possible states were indistinguishable in any output.
- Log the first-observed semaphore value in the recovery-timeout message
as well; the previous message could not distinguish a value that
changed during the wait from one that never moved.
- Comment corrections: the post-budget wake-on-write claim now states the
pacing-period bound honestly; the x86 note names the yield fallback on
CPUs without waitpkg/mwaitx; the event-stream period is stated as a
kernel-dependent range. Note the previous commit's claim that x86 was
unaffected was wrong: the snapshot change lets the x86 early-out fire
where it previously compared a value against itself; the direction is
an earlier return when the semaphore changed during the prologue.
Device check (Odin 3, ME menu, 30 s): 168.0G instructions, and the new
capability line reads EVTSTRM-on, proving the paced branch was live in
the measured run. Known residuals (ledgered, out of scope): HWCAP is a
boot-time global while the stream enable is per-CPU (migration edge);
no parking-core device has been measured; no automated test covers the
path.
ARMSX3
Uses the latest RPCS3 upstream code (the recent ARM64 improvements included).
Building
Only arm64-v8a is supported. You need the Android SDK with NDK r27 or newer, CMake 3.30 or newer, and a JDK 17. Android Studio ships all of these.
Clone with submodules, then fetch the two third party checkouts that are not submodules:
git clone --recursive https://github.com/ARMSX2/ARMSX3.git
cd ARMSX3
git clone https://github.com/SnowflakePowered/librashader 3rdparty/librashader
git clone https://github.com/bylaws/libadrenotools android/armsx3-ui/app/src/main/cpp/libadrenotools
Build the core. This is the long part and produces an unstripped library of around 1.3 GB:
export ANDROID_HOME=$HOME/Library/Android/sdk
cmake -B build-android -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/<version>/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-31 \
-DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build-android --target rpcsx-android -j8
Strip it and put it where the app expects it:
llvm-strip --strip-unneeded build-android/android/libarmsx3-core.so
cp build-android/android/libarmsx3-core.so \
android/armsx3-ui/app/src/main/jniLibs/arm64-v8a/
Then build the app:
cd android/armsx3-ui
export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"
./gradlew :app:assembleRelease
The apk lands in app/build/outputs/apk/release/.
Note that the core library has to be rebuilt and copied again whenever anything under rpcs3/ or android/src/ changes. Gradle does not build it for you.
The Discord Social SDK is proprietary and is not redistributed here. Get it from Discord's developer portal and drop it in app/libs/ and app/src/main/cpp/discord_sdk/ if you want that feature. The build skips it otherwise.
Running it needs PS3 firmware, which is not included. License
GPL-2.0-only, the same as RPCS3. See LICENSE. Some files may be licensed differently, check the file headers.
Based on RPCS3, https://github.com/RPCS3/rpcs3