From cb43a4c306ebf33b360bf00af5fb7e12554f4b60 Mon Sep 17 00:00:00 2001 From: LuisBiceps <54749472+LuisBiceps@users.noreply.github.com> Date: Fri, 9 Oct 2026 12:10:19 +0800 Subject: [PATCH 1/3] feat(libSceSystemService): let the running title close itself with sceSystemServiceKillApp Report an app ID for the running title from sceSystemServiceGetAppIdOfRunningBigApp, and shut the guest down and exit when sceSystemServiceKillApp receives that ID with the arguments -1, 0 and 0. SwanStationPS5 (PPSA98510) 1.0.6 closes itself this way and stops on both imports on main. --- .../prx/libSceSystemService/CMakeLists.txt | 12 +++++ core/libs/prx/libSceSystemService/Export.cpp | 15 +++++++ .../prx/libSceSystemService/SystemService.hpp | 2 + core/libs/tests/GuestSystemKillApp.cpp | 44 +++++++++++++++++++ docs/dev/TechnicalDebt.md | 1 + 5 files changed, 74 insertions(+) create mode 100644 core/libs/tests/GuestSystemKillApp.cpp diff --git a/core/libs/prx/libSceSystemService/CMakeLists.txt b/core/libs/prx/libSceSystemService/CMakeLists.txt index b1676e0f5..b8055ddfe 100644 --- a/core/libs/prx/libSceSystemService/CMakeLists.txt +++ b/core/libs/prx/libSceSystemService/CMakeLists.txt @@ -29,4 +29,16 @@ if(BUILD_TESTING) set_tests_properties(guest_system_service PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_test_executable(guest_system_kill_app_tests ${LIBS_INCLUDE_DIR}/tests/GuestSystemKillApp.cpp) + target_include_directories(guest_system_kill_app_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_system_kill_app_tests PRIVATE libSceSystemService libc) + configure_windows_unwind(guest_system_kill_app_tests) + add_test(NAME guest_system_kill_app_parameters COMMAND guest_system_kill_app_tests) + add_test(NAME guest_system_kill_app COMMAND guest_system_kill_app_tests --kill) + set_tests_properties(guest_system_kill_app PROPERTIES + PASS_REGULAR_EXPRESSION "Guest shutdown and atexit completed") + if(WIN32) + set_tests_properties(guest_system_kill_app guest_system_kill_app_parameters PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() endif() diff --git a/core/libs/prx/libSceSystemService/Export.cpp b/core/libs/prx/libSceSystemService/Export.cpp index 0de0c37f4..094509823 100644 --- a/core/libs/prx/libSceSystemService/Export.cpp +++ b/core/libs/prx/libSceSystemService/Export.cpp @@ -158,4 +158,19 @@ int APS5_VABI sceSystemServiceShowControllerSettings(void) { return 0; } +int APS5_VABI sceSystemServiceGetAppIdOfRunningBigApp(void) { + return SYSTEM_SERVICE_RUNNING_APP_ID; +} + +int APS5_VABI sceSystemServiceKillApp(int appId, int how, int reason, int coreDump) { + if (appId != SYSTEM_SERVICE_RUNNING_APP_ID) { + NotImplemented_nid_no_patch("sceSystemServiceKillApp: application other than the running title"); + } + if (how != -1 || reason != 0 || coreDump != 0) { + NotImplemented_nid_no_patch("sceSystemServiceKillApp: arguments other than -1, 0 and 0"); + } + LibcRunShutdown_nid_postfix(); + std::exit(0); +} + } diff --git a/core/libs/prx/libSceSystemService/SystemService.hpp b/core/libs/prx/libSceSystemService/SystemService.hpp index e86820da4..109d1c269 100644 --- a/core/libs/prx/libSceSystemService/SystemService.hpp +++ b/core/libs/prx/libSceSystemService/SystemService.hpp @@ -8,6 +8,8 @@ constexpr int SYSTEM_SERVICE_OK = 0; constexpr int SYSTEM_SERVICE_ERROR_PARAMETER = -2136932349; constexpr int SYSTEM_SERVICE_ERROR_NO_EVENT = -2136932348; +constexpr int SYSTEM_SERVICE_RUNNING_APP_ID = 1; + constexpr int SYSTEM_SERVICE_PARAM_ID_LANG = 1; constexpr int SYSTEM_SERVICE_PARAM_ID_DATE_FORMAT = 2; constexpr int SYSTEM_SERVICE_PARAM_ID_TIME_FORMAT = 3; diff --git a/core/libs/tests/GuestSystemKillApp.cpp b/core/libs/tests/GuestSystemKillApp.cpp new file mode 100644 index 000000000..980fd0093 --- /dev/null +++ b/core/libs/tests/GuestSystemKillApp.cpp @@ -0,0 +1,44 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include "prx/libc/include/Shutdown.hpp" +#include +#include +#include +#include +extern "C" int APS5_VABI sceSystemServiceGetAppIdOfRunningBigApp(void); +extern "C" int APS5_VABI sceSystemServiceKillApp(int, int, int, int); +namespace { +bool cleaned = false; +bool finished = false; +void Cleanup() { cleaned = true; } +void VerifyExit() { + if (!cleaned) std::_Exit(1); + std::puts("Guest shutdown and atexit completed"); +} +void UnexpectedShutdown() { + if (!finished) std::_Exit(3); +} +void Require(bool value) { if (!value) std::abort(); } +bool Rejects(int appId, int how, int reason, int coreDump) { + try { sceSystemServiceKillApp(appId, how, reason, coreDump); } + catch (const std::runtime_error&) { return true; } + return false; +} +} +int main(int argc, char** argv) { + const int appId = sceSystemServiceGetAppIdOfRunningBigApp(); + Require(appId > 0 && sceSystemServiceGetAppIdOfRunningBigApp() == appId); + if (argc > 1 && std::strcmp(argv[1], "--kill") == 0) { + LibcRegisterShutdown_nid_postfix(Cleanup); + Require(std::atexit(VerifyExit) == 0); + sceSystemServiceKillApp(appId, -1, 0, 0); + return 2; + } + LibcRegisterShutdown_nid_postfix(UnexpectedShutdown); + Require(std::atexit(UnexpectedShutdown) == 0); + Require(Rejects(appId + 1, -1, 0, 0)); + Require(Rejects(-1, -1, 0, 0)); + Require(Rejects(appId, 0, 0, 0)); + Require(Rejects(appId, -1, 1, 0)); + Require(Rejects(appId, -1, 0, 1)); + finished = true; +} diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 81b674366..a212d7cb2 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -348,6 +348,7 @@ Throughout the project, every function at every stage either **does exactly what - [sceImeKeyboardGetResourceId](../../core/libs/prx/libSceIme/Export.cpp) (libSceIme) reports that no USB keyboard is connected (`0x80bc0004`, as [shadPS4](https://github.com/shadps4-emu/shadPS4) does) because IME keyboard events are not delivered to the handler, although [libSceKeyboard](../../core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp) exposes the host keyboard - [Player review dialog](../../core/libs/prx/libSceCdlgPlayerReview/Export.cpp) (libSceCdlgPlayerReview) shows nothing: `scePlayerReviewDialogOpen` finishes at once and the result reports that the user canceled, as `sceWebBrowserDialogOpen` does - [NP reachability callbacks](../../core/libs/prx/libSceNpManager/Export.cpp) retain one callback and its user data; duplicate registration and unregistering an absent callback return the errors used by [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/945dbc3cc3eee80ac3e053b438502ed936fa6bb2/src/core/libraries/np/np_manager.cpp). No callback is delivered because the existing NP model remains signed out with reachability unavailable. +- [Running application ID](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - `sceSystemServiceGetAppIdOfRunningBigApp` reports 1 as the running title's app ID; the console's shell assigns app IDs, and their values are not known here. `sceSystemServiceKillApp` with that ID and the arguments -1, 0 and 0, which [SwanStationPS5](https://github.com/darkxex/SwanStationPS5/blob/4cdc981d1a64ffb7f2af73f7a27a9e91a3cb5eb4/src/main.c#L1050-L1058) passes to close itself, shuts the guest down and exits the process with status 0, as `sceSystemServiceLoadExec("exit")` does. Another app ID or other arguments throw. - [Temporary app-content storage](../../core/libs/prx/libSceAppContent/Export.cpp) tracks one `/temp0` mount, preserves its files on unmount, and rejects new path resolutions until remount. Mount, format, space-query and unmount errors follow [fpPS4](https://github.com/red-prig/fpPS4/blob/04cefd43e6fddd1ab033e7980cd356d14c964905/sys/sys_path.pas); the pointer ABI is also declared by [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/AppContent/AppContent.cs). Existing open host descriptors remain usable after unmount; console behaviour with open files is unverified. Host filesystem failures still throw. - [Guest path resolution](../../core/libs/prx/libc/src/General.cpp) falls back to ASCII case-insensitive component lookup, following [shadPS4's host filesystem](https://github.com/shadps4-emu/shadPS4/blob/945dbc3cc3eee80ac3e053b438502ed936fa6bb2/src/core/file_sys/backends/host_fs.cpp). PPSA03747 requests `Skyrim.INI`, `Data/Video` and lowercase archive/plugin names that differ from the dump's filenames. Exact host names take precedence; multiple fallback matches throw instead of selecting an arbitrary file. Existing parent names are resolved when creating a new file, and guest mount aliases use the same ASCII comparison. Results are not cached, so renames and newly created files remain visible. Unicode case folding and PS5 behaviour for case-colliding host entries are unverified; host roots are used as supplied. - [Static scalar calls](../../core/shader/recompiler/ControlFlow/src/GraphBuilder.cpp) (`s_call_b64` and `s_swappc_b64`) require one call per ordinary even-aligned SGPR link pair (s0:s1 through s104:s105) and one later `s_setpc_b64` return reading that exact pair. Regions must nest or be disjoint; recursion, shared links, escaping link values (including overlapping tuples and resource descriptors), invalid targets, interleaved regions, cross-region branches or fall-through, relative SGPR reads and dynamic `s_setpc_b64` in a program with calls throw. The analysis checks all decoded instructions, including unreachable code. Arbitrary indirect calls and general call frames are not implemented. From 38cbdfe34c01cc11d44dc85681f0bafc11b4767c Mon Sep 17 00:00:00 2001 From: LuisBiceps <54749472+LuisBiceps@users.noreply.github.com> Date: Fri, 9 Oct 2026 12:21:09 +0800 Subject: [PATCH 2/3] fix(libSceSystemService): close the title through the libc exit coordinator sceSystemServiceKillApp now ends the title as guest exit() does, so driver calls that wait for the exit park instead of throwing ProcessShutdown, and a second exit waits for the first. The test now fails when the kill returns, exits with a status other than 0 or bypasses the coordinator, and checks why a rejected call throws. --- .../prx/libSceSystemService/CMakeLists.txt | 3 ++- core/libs/prx/libSceSystemService/Export.cpp | 3 +-- core/libs/tests/GuestSystemKillApp.cpp | 24 ++++++++++++------- docs/dev/TechnicalDebt.md | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/core/libs/prx/libSceSystemService/CMakeLists.txt b/core/libs/prx/libSceSystemService/CMakeLists.txt index b8055ddfe..e90856e4e 100644 --- a/core/libs/prx/libSceSystemService/CMakeLists.txt +++ b/core/libs/prx/libSceSystemService/CMakeLists.txt @@ -35,10 +35,11 @@ if(BUILD_TESTING) configure_windows_unwind(guest_system_kill_app_tests) add_test(NAME guest_system_kill_app_parameters COMMAND guest_system_kill_app_tests) add_test(NAME guest_system_kill_app COMMAND guest_system_kill_app_tests --kill) + add_test(NAME guest_system_kill_app_status COMMAND guest_system_kill_app_tests --kill) set_tests_properties(guest_system_kill_app PROPERTIES PASS_REGULAR_EXPRESSION "Guest shutdown and atexit completed") if(WIN32) - set_tests_properties(guest_system_kill_app guest_system_kill_app_parameters PROPERTIES ENVIRONMENT_MODIFICATION + set_tests_properties(guest_system_kill_app guest_system_kill_app_status guest_system_kill_app_parameters PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() endif() diff --git a/core/libs/prx/libSceSystemService/Export.cpp b/core/libs/prx/libSceSystemService/Export.cpp index 094509823..49713afb1 100644 --- a/core/libs/prx/libSceSystemService/Export.cpp +++ b/core/libs/prx/libSceSystemService/Export.cpp @@ -169,8 +169,7 @@ int APS5_VABI sceSystemServiceKillApp(int appId, int how, int reason, int coreDu if (how != -1 || reason != 0 || coreDump != 0) { NotImplemented_nid_no_patch("sceSystemServiceKillApp: arguments other than -1, 0 and 0"); } - LibcRunShutdown_nid_postfix(); - std::exit(0); + LibcExit_nid_no_patch(0); } } diff --git a/core/libs/tests/GuestSystemKillApp.cpp b/core/libs/tests/GuestSystemKillApp.cpp index 980fd0093..3d5db1ae8 100644 --- a/core/libs/tests/GuestSystemKillApp.cpp +++ b/core/libs/tests/GuestSystemKillApp.cpp @@ -9,7 +9,11 @@ extern "C" int APS5_VABI sceSystemServiceKillApp(int, int, int, int); namespace { bool cleaned = false; bool finished = false; -void Cleanup() { cleaned = true; } +void Cleanup() { + try { LibcAwaitExit_nid_postfix(); } + catch (const ProcessShutdown&) { return; } + catch (const std::runtime_error&) { cleaned = true; } +} void VerifyExit() { if (!cleaned) std::_Exit(1); std::puts("Guest shutdown and atexit completed"); @@ -18,9 +22,9 @@ void UnexpectedShutdown() { if (!finished) std::_Exit(3); } void Require(bool value) { if (!value) std::abort(); } -bool Rejects(int appId, int how, int reason, int coreDump) { +bool Rejects(int appId, int how, int reason, int coreDump, const char* expected) { try { sceSystemServiceKillApp(appId, how, reason, coreDump); } - catch (const std::runtime_error&) { return true; } + catch (const std::runtime_error& error) { return std::strstr(error.what(), expected) != nullptr; } return false; } } @@ -31,14 +35,16 @@ int main(int argc, char** argv) { LibcRegisterShutdown_nid_postfix(Cleanup); Require(std::atexit(VerifyExit) == 0); sceSystemServiceKillApp(appId, -1, 0, 0); - return 2; + std::_Exit(4); } LibcRegisterShutdown_nid_postfix(UnexpectedShutdown); Require(std::atexit(UnexpectedShutdown) == 0); - Require(Rejects(appId + 1, -1, 0, 0)); - Require(Rejects(-1, -1, 0, 0)); - Require(Rejects(appId, 0, 0, 0)); - Require(Rejects(appId, -1, 1, 0)); - Require(Rejects(appId, -1, 0, 1)); + constexpr char otherApp[] = "sceSystemServiceKillApp: application other than the running title"; + constexpr char otherArguments[] = "sceSystemServiceKillApp: arguments other than -1, 0 and 0"; + Require(Rejects(appId + 1, -1, 0, 0, otherApp)); + Require(Rejects(-1, -1, 0, 0, otherApp)); + Require(Rejects(appId, 0, 0, 0, otherArguments)); + Require(Rejects(appId, -1, 1, 0, otherArguments)); + Require(Rejects(appId, -1, 0, 1, otherArguments)); finished = true; } diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index a212d7cb2..3d35406a6 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -348,7 +348,7 @@ Throughout the project, every function at every stage either **does exactly what - [sceImeKeyboardGetResourceId](../../core/libs/prx/libSceIme/Export.cpp) (libSceIme) reports that no USB keyboard is connected (`0x80bc0004`, as [shadPS4](https://github.com/shadps4-emu/shadPS4) does) because IME keyboard events are not delivered to the handler, although [libSceKeyboard](../../core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp) exposes the host keyboard - [Player review dialog](../../core/libs/prx/libSceCdlgPlayerReview/Export.cpp) (libSceCdlgPlayerReview) shows nothing: `scePlayerReviewDialogOpen` finishes at once and the result reports that the user canceled, as `sceWebBrowserDialogOpen` does - [NP reachability callbacks](../../core/libs/prx/libSceNpManager/Export.cpp) retain one callback and its user data; duplicate registration and unregistering an absent callback return the errors used by [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/945dbc3cc3eee80ac3e053b438502ed936fa6bb2/src/core/libraries/np/np_manager.cpp). No callback is delivered because the existing NP model remains signed out with reachability unavailable. -- [Running application ID](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - `sceSystemServiceGetAppIdOfRunningBigApp` reports 1 as the running title's app ID; the console's shell assigns app IDs, and their values are not known here. `sceSystemServiceKillApp` with that ID and the arguments -1, 0 and 0, which [SwanStationPS5](https://github.com/darkxex/SwanStationPS5/blob/4cdc981d1a64ffb7f2af73f7a27a9e91a3cb5eb4/src/main.c#L1050-L1058) passes to close itself, shuts the guest down and exits the process with status 0, as `sceSystemServiceLoadExec("exit")` does. Another app ID or other arguments throw. +- [Running application ID](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - `sceSystemServiceGetAppIdOfRunningBigApp` reports 1 as the running title's app ID. The value is AnyPS5's own: the console's shell assigns app IDs and their values are not known here, so other calls that take an app ID must use the same one. `sceSystemServiceKillApp` with that ID and the arguments -1, 0 and 0, which [SwanStationPS5](https://github.com/darkxex/SwanStationPS5/blob/4cdc981d1a64ffb7f2af73f7a27a9e91a3cb5eb4/src/main.c#L1050-L1058) passes to close itself and [ps5-payload-dev's hbldr](https://github.com/ps5-payload-dev/websrv/blob/46374edee6627885abac717de24da7a1d73af6f1/src/ps5/hbldr.c#L425-L435) passes to close the running game, ends the title as its own `exit(0)` would: the guest's shutdown and `atexit` handlers run and the process exits with status 0. On the console the shell ends the title instead, and whether those handlers run there is unknown. Another app ID or other arguments throw. - [Temporary app-content storage](../../core/libs/prx/libSceAppContent/Export.cpp) tracks one `/temp0` mount, preserves its files on unmount, and rejects new path resolutions until remount. Mount, format, space-query and unmount errors follow [fpPS4](https://github.com/red-prig/fpPS4/blob/04cefd43e6fddd1ab033e7980cd356d14c964905/sys/sys_path.pas); the pointer ABI is also declared by [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/AppContent/AppContent.cs). Existing open host descriptors remain usable after unmount; console behaviour with open files is unverified. Host filesystem failures still throw. - [Guest path resolution](../../core/libs/prx/libc/src/General.cpp) falls back to ASCII case-insensitive component lookup, following [shadPS4's host filesystem](https://github.com/shadps4-emu/shadPS4/blob/945dbc3cc3eee80ac3e053b438502ed936fa6bb2/src/core/file_sys/backends/host_fs.cpp). PPSA03747 requests `Skyrim.INI`, `Data/Video` and lowercase archive/plugin names that differ from the dump's filenames. Exact host names take precedence; multiple fallback matches throw instead of selecting an arbitrary file. Existing parent names are resolved when creating a new file, and guest mount aliases use the same ASCII comparison. Results are not cached, so renames and newly created files remain visible. Unicode case folding and PS5 behaviour for case-colliding host entries are unverified; host roots are used as supplied. - [Static scalar calls](../../core/shader/recompiler/ControlFlow/src/GraphBuilder.cpp) (`s_call_b64` and `s_swappc_b64`) require one call per ordinary even-aligned SGPR link pair (s0:s1 through s104:s105) and one later `s_setpc_b64` return reading that exact pair. Regions must nest or be disjoint; recursion, shared links, escaping link values (including overlapping tuples and resource descriptors), invalid targets, interleaved regions, cross-region branches or fall-through, relative SGPR reads and dynamic `s_setpc_b64` in a program with calls throw. The analysis checks all decoded instructions, including unreachable code. Arbitrary indirect calls and general call frames are not implemented. From 75345b07b97f9e5f20da3d25c0da2c4c823d67a8 Mon Sep 17 00:00:00 2001 From: LuisBiceps <54749472+LuisBiceps@users.noreply.github.com> Date: Fri, 9 Oct 2026 12:22:29 +0800 Subject: [PATCH 3/3] test(libSceSystemService): reject app ID 0 and how -2 in the kill test Also say in the debt entry that on the console sceSystemServiceKillApp returns and the shell ends the title, while here the call does not return. --- core/libs/tests/GuestSystemKillApp.cpp | 2 ++ docs/dev/TechnicalDebt.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/libs/tests/GuestSystemKillApp.cpp b/core/libs/tests/GuestSystemKillApp.cpp index 3d5db1ae8..300d6524f 100644 --- a/core/libs/tests/GuestSystemKillApp.cpp +++ b/core/libs/tests/GuestSystemKillApp.cpp @@ -43,7 +43,9 @@ int main(int argc, char** argv) { constexpr char otherArguments[] = "sceSystemServiceKillApp: arguments other than -1, 0 and 0"; Require(Rejects(appId + 1, -1, 0, 0, otherApp)); Require(Rejects(-1, -1, 0, 0, otherApp)); + Require(Rejects(0, -1, 0, 0, otherApp)); Require(Rejects(appId, 0, 0, 0, otherArguments)); + Require(Rejects(appId, -2, 0, 0, otherArguments)); Require(Rejects(appId, -1, 1, 0, otherArguments)); Require(Rejects(appId, -1, 0, 1, otherArguments)); finished = true; diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index 3d35406a6..4da6d2a38 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -348,7 +348,7 @@ Throughout the project, every function at every stage either **does exactly what - [sceImeKeyboardGetResourceId](../../core/libs/prx/libSceIme/Export.cpp) (libSceIme) reports that no USB keyboard is connected (`0x80bc0004`, as [shadPS4](https://github.com/shadps4-emu/shadPS4) does) because IME keyboard events are not delivered to the handler, although [libSceKeyboard](../../core/libs/prx/libSceKeyboard/src/keyboard_impl.cpp) exposes the host keyboard - [Player review dialog](../../core/libs/prx/libSceCdlgPlayerReview/Export.cpp) (libSceCdlgPlayerReview) shows nothing: `scePlayerReviewDialogOpen` finishes at once and the result reports that the user canceled, as `sceWebBrowserDialogOpen` does - [NP reachability callbacks](../../core/libs/prx/libSceNpManager/Export.cpp) retain one callback and its user data; duplicate registration and unregistering an absent callback return the errors used by [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/945dbc3cc3eee80ac3e053b438502ed936fa6bb2/src/core/libraries/np/np_manager.cpp). No callback is delivered because the existing NP model remains signed out with reachability unavailable. -- [Running application ID](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - `sceSystemServiceGetAppIdOfRunningBigApp` reports 1 as the running title's app ID. The value is AnyPS5's own: the console's shell assigns app IDs and their values are not known here, so other calls that take an app ID must use the same one. `sceSystemServiceKillApp` with that ID and the arguments -1, 0 and 0, which [SwanStationPS5](https://github.com/darkxex/SwanStationPS5/blob/4cdc981d1a64ffb7f2af73f7a27a9e91a3cb5eb4/src/main.c#L1050-L1058) passes to close itself and [ps5-payload-dev's hbldr](https://github.com/ps5-payload-dev/websrv/blob/46374edee6627885abac717de24da7a1d73af6f1/src/ps5/hbldr.c#L425-L435) passes to close the running game, ends the title as its own `exit(0)` would: the guest's shutdown and `atexit` handlers run and the process exits with status 0. On the console the shell ends the title instead, and whether those handlers run there is unknown. Another app ID or other arguments throw. +- [Running application ID](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - `sceSystemServiceGetAppIdOfRunningBigApp` reports 1 as the running title's app ID. The value is AnyPS5's own: the console's shell assigns app IDs and their values are not known here, so other calls that take an app ID must use the same one. `sceSystemServiceKillApp` with that ID and the arguments -1, 0 and 0, which [SwanStationPS5](https://github.com/darkxex/SwanStationPS5/blob/4cdc981d1a64ffb7f2af73f7a27a9e91a3cb5eb4/src/main.c#L1050-L1058) passes to close itself and [ps5-payload-dev's hbldr](https://github.com/ps5-payload-dev/websrv/blob/46374edee6627885abac717de24da7a1d73af6f1/src/ps5/hbldr.c#L425-L435) passes to close the running game, ends the title as its own `exit(0)` would: the guest's shutdown and `atexit` handlers run and the process exits with status 0. On the console the call returns and the shell then ends the title, and whether those handlers run there is unknown; here there is no shell, so the call does not return. Another app ID or other arguments throw. - [Temporary app-content storage](../../core/libs/prx/libSceAppContent/Export.cpp) tracks one `/temp0` mount, preserves its files on unmount, and rejects new path resolutions until remount. Mount, format, space-query and unmount errors follow [fpPS4](https://github.com/red-prig/fpPS4/blob/04cefd43e6fddd1ab033e7980cd356d14c964905/sys/sys_path.pas); the pointer ABI is also declared by [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/AppContent/AppContent.cs). Existing open host descriptors remain usable after unmount; console behaviour with open files is unverified. Host filesystem failures still throw. - [Guest path resolution](../../core/libs/prx/libc/src/General.cpp) falls back to ASCII case-insensitive component lookup, following [shadPS4's host filesystem](https://github.com/shadps4-emu/shadPS4/blob/945dbc3cc3eee80ac3e053b438502ed936fa6bb2/src/core/file_sys/backends/host_fs.cpp). PPSA03747 requests `Skyrim.INI`, `Data/Video` and lowercase archive/plugin names that differ from the dump's filenames. Exact host names take precedence; multiple fallback matches throw instead of selecting an arbitrary file. Existing parent names are resolved when creating a new file, and guest mount aliases use the same ASCII comparison. Results are not cached, so renames and newly created files remain visible. Unicode case folding and PS5 behaviour for case-colliding host entries are unverified; host roots are used as supplied. - [Static scalar calls](../../core/shader/recompiler/ControlFlow/src/GraphBuilder.cpp) (`s_call_b64` and `s_swappc_b64`) require one call per ordinary even-aligned SGPR link pair (s0:s1 through s104:s105) and one later `s_setpc_b64` return reading that exact pair. Regions must nest or be disjoint; recursion, shared links, escaping link values (including overlapping tuples and resource descriptors), invalid targets, interleaved regions, cross-region branches or fall-through, relative SGPR reads and dynamic `s_setpc_b64` in a program with calls throw. The analysis checks all decoded instructions, including unreachable code. Arbitrary indirect calls and general call frames are not implemented.