From 4b6f4637514b213664437d21fb537935f229e2c6 Mon Sep 17 00:00:00 2001 From: xXPBSXx <20614131+xXPBSXx@users.noreply.github.com> Date: Mon, 12 Oct 2026 03:22:21 +0200 Subject: [PATCH] feat(libSceAmpr): answer sceAmprAmmGetUsageStatsData Co-Authored-By: Claude Sonnet 5.5 --- core/libs/prx/libSceAmpr/Export.cpp | 21 +++++++++++++++++++-- core/libs/tests/GuestAmpr.cpp | 20 ++++++++++++++++++++ docs/dev/debt/libSceAmpr.md | 1 + docs/dev/debt/libSceJson2.md | 2 +- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/core/libs/prx/libSceAmpr/Export.cpp b/core/libs/prx/libSceAmpr/Export.cpp index db2eb580c..887deb022 100644 --- a/core/libs/prx/libSceAmpr/Export.cpp +++ b/core/libs/prx/libSceAmpr/Export.cpp @@ -223,6 +223,18 @@ static constexpr int ThrdError = 4; static std::atomic_flag sharedPtrSpinLock; +struct AmmUsageStatsData { + std::uint64_t sizeInBytes; + std::uint16_t numPageTablePoolEntries; + std::uint16_t allocatedPageTablePoolEntries; + std::uint16_t highWatermarkAllocatedEntries; + std::uint16_t reserved; + std::uint32_t ringIdleFlags; +}; +static_assert(sizeof(AmmUsageStatsData) == 0x18); +static constexpr std::uint16_t AmmPageTablePoolEntries = 512; +static constexpr std::uint32_t AmmRingIdleFlags = 0x7; + extern "C" { int APS5_VABI pthread_join_nid_postfix(Pthread thread, void** value); int APS5_VABI wcsrtombs_s_nid_postfix(std::size_t* result, char* destination, std::size_t capacity, const std::uint16_t** source, std::size_t limit, void* state); @@ -995,8 +1007,13 @@ int APS5_VABI sceAmprFpclassifyd(double value) { return SonyFpclassifyd(value); } -int APS5_VABI sceAmprAmmGetUsageStatsData() { - NotImplemented_nid_no_patch(__func__); +int APS5_VABI sceAmprAmmGetUsageStatsData(AmmUsageStatsData* stats) { + if (!stats || stats->sizeInBytes > sizeof(AmmUsageStatsData)) return SCE_KERNEL_ERROR_EINVAL; + AmmUsageStatsData out{}; + out.sizeInBytes = stats->sizeInBytes; + out.numPageTablePoolEntries = AmmPageTablePoolEntries; + out.ringIdleFlags = AmmRingIdleFlags; + std::memcpy(stats, &out, static_cast(stats->sizeInBytes)); return 0; } } diff --git a/core/libs/tests/GuestAmpr.cpp b/core/libs/tests/GuestAmpr.cpp index 37bc4c9df..ee508ea89 100644 --- a/core/libs/tests/GuestAmpr.cpp +++ b/core/libs/tests/GuestAmpr.cpp @@ -82,6 +82,7 @@ std::uint64_t APS5_VABI sceAmprMeasureCommandSizeReadFileScatter(void*, std::uin std::uint64_t APS5_VABI sceAmprMeasureCommandSizeReadFileGatherScatter(void*, std::uint64_t, std::uint64_t); std::uint64_t APS5_VABI sceAmprMeasureCommandSizeResetGatherScatterState(); std::size_t APS5_VABI sceKernelGetDirectMemorySize(); +int APS5_VABI sceAmprAmmGetUsageStatsData(void*); int APS5_VABI sceAmprAmmCommandBufferConstructor(Apr::CommandBufferObject*); int APS5_VABI sceAmprAmmCommandBufferMap(Apr::CommandBufferObject*, std::uint64_t, std::uint64_t, std::int32_t, std::int32_t); int APS5_VABI sceAmprAmmCommandBufferMapWithGpuMaskId(Apr::CommandBufferObject*, std::uint64_t, std::uint64_t, std::int32_t, std::int32_t, std::uint8_t); @@ -823,6 +824,24 @@ void TestAmmRangesAboveHintedMaps() { Require(sceKernelMunmap(span, page) == 0); } +void TestAmmUsageStats() { + std::array stats{}; + Require(sceAmprAmmGetUsageStatsData(nullptr) == static_cast(0x80020016)); + stats[0] = 0x19; + Require(sceAmprAmmGetUsageStatsData(stats.data()) == static_cast(0x80020016)); + stats = {0x18, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}; + Require(sceAmprAmmGetUsageStatsData(stats.data()) == 0); + Require(stats[0] == 0x18); + Require((stats[1] & 0xffffu) == 512u && (stats[1] >> 16u) == 0u); + Require((stats[2] & 0xffffffffu) == 7u && (stats[2] >> 32u) == 0u); + stats = {0x8, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}; + Require(sceAmprAmmGetUsageStatsData(stats.data()) == 0); + Require(stats[0] == 0x8 && stats[1] == 0xdeadbeef && stats[2] == 0xdeadbeef); + stats = {0x0, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef}; + Require(sceAmprAmmGetUsageStatsData(stats.data()) == 0); + Require(stats[0] == 0 && stats[1] == 0xdeadbeef); +} + void TestAmm() { std::uint64_t start = 0; std::uint64_t end = 0; @@ -1262,6 +1281,7 @@ int main() { TestResolveSymbolicLink(); TestGatherScatter(); TestAmmRangesAboveHintedMaps(); + TestAmmUsageStats(); TestAmm(); TestAmmRemapAndProtect(); TestAmmPrt(); diff --git a/docs/dev/debt/libSceAmpr.md b/docs/dev/debt/libSceAmpr.md index 237e7028e..72986668b 100644 --- a/docs/dev/debt/libSceAmpr.md +++ b/docs/dev/debt/libSceAmpr.md @@ -9,5 +9,6 @@ ### Functional +- [sceAmprAmmGetUsageStatsData](../../../core/libs/prx/libSceAmpr/Export.cpp) (libSceAmpr) fills the caller-sized 24-byte statistics structure with 512 page-table pool entries, no allocated entries, a zero high watermark and ring idle flags 0x7, the constants of [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/main/src/libs/libAmpr.cpp); they are not measured on a console, and the real call is a pass-through to `sceKernelMapperGetUsageStatsData` per [drakmor/ampr_emu](https://github.com/drakmor/ampr_emu/blob/main/src/ampr_emu_amm.cpp), which this port has no kernel-side counterpart for. - [Dinkumware thread exports](../../../core/libs/prx/libSceAmpr/Export.cpp) (libSceAmpr) follow the Dinkumware threads library shipped with [Visual C++ 2013](https://github.com/adityaramesh/concurrency_runtime/tree/master/VS2013_SP2/crt/src/thr) (`cthread.c`) and its `atomic.c`, [microsoft/STL `cthread.cpp`](https://github.com/microsoft/STL/blob/main/stl/src/cthread.cpp) and C11 Annex K, without console verification. `_Thrd_t` is taken to be the guest `pthread_t`, as the `std::_Pad::_Launch(pthread**)` export suggests: `_Thrd_join` returns `_Thrd_error` (4) when `pthread_join` fails and stores the thread's return value truncated to `int`. `_Thrd_join` (32-bit store of the result, 0 or 4) and the spin lock (byte exchange loop, no yield) match that disassembly. The shared_ptr spin lock is one process-wide flag that yields while it spins. `wcstombs_s` is `wcsrtombs_s` with a fresh conversion state, so `*retval` excludes the terminating null as in Annex K, not as in the Microsoft CRT, and `_TRUNCATE` has no meaning. - [_Cnd_signal, _Cnd_init_with_name](../../../core/libs/prx/libSceAmpr/Export.cpp) (libSceAmpr) - take a pointer to the handle slot like the libc `_Cnd_*` exports from [#3079](https://github.com/boykopovar/AnyPS5/pull/3079) and act on the same conditions. `_Cnd_signal` wakes one waiter and returns `_Thrd_success` (0), as `_Cnd_broadcast` does; whether the console maps a failing internal signal to `_Thrd_error` is not known. The signature `_Cnd_init_with_name(_Cnd_t*, const char* name)` is inferred from [fpPS4 `ps4_mtx_internal.pas`](https://github.com/red-prig/fpPS4/blob/trunk/src/libcinternal/ps4_mtx_internal.pas), where the PS4 `_Mtx_init` is `_Mtx_init_with_name` with the name `SceLibcI_Mtx` and the name only reaches the pthread object; here it is `_Cnd_init` and the name, which may be null, is ignored. Neither is confirmed on a PS5 `libc.prx`. `_Thrd_id` still throws: microsoft/STL returns an `unsigned int` thread id, but whether the PS5 returns the `pthread_t` or a kernel thread id, and at what width, is not known diff --git a/docs/dev/debt/libSceJson2.md b/docs/dev/debt/libSceJson2.md index 72914c631..946784429 100644 --- a/docs/dev/debt/libSceJson2.md +++ b/docs/dev/debt/libSceJson2.md @@ -8,5 +8,5 @@ ### Functional -- PPSA30601 imports declared without parameters, signatures unknown, added without an implementation because the title fails to load without them: [six sce::Json::Object::Pair, sce::Json::Object and sce::Json::Array::iterator members](../../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2), [sceAmprAmmGetUsageStatsData](../../../core/libs/prx/libSceAmpr/Export.cpp) (libSceAmpr), [sceMouseResetAbsolutePosition](../../../core/libs/prx/libSceMouse/Export.cpp) (libSceMouse) and [sceSaveDataDirNameSearch2](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) +- PPSA30601 imports declared without parameters, signatures unknown, added without an implementation because the title fails to load without them: [six sce::Json::Object::Pair, sce::Json::Object and sce::Json::Array::iterator members](../../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2), [sceMouseResetAbsolutePosition](../../../core/libs/prx/libSceMouse/Export.cpp) (libSceMouse) and [sceSaveDataDirNameSearch2](../../../core/libs/prx/libSceSaveData.native/Export.cpp) (libSceSaveData.native) - [sce::Json::InitParameter2 base-object constructor](../../../core/libs/prx/libSceJson2/Export.cpp) (libSceJson2) - forwards to the complete-object constructor and uses its inferred layout and default field values; constructor equivalence and initialization bytes remain unverified on the console