Merge pull request #4207 from xXPBSXx/fix/ampr-amm-usage-stats

feat(libSceAmpr): answer sceAmprAmmGetUsageStatsData
This commit is contained in:
Adrià 2026-10-12 22:57:04 +02:00 committed by GitHub
commit 955f4fbffe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 41 additions and 3 deletions

View File

@ -228,6 +228,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);
@ -1000,8 +1012,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<std::size_t>(stats->sizeInBytes));
return 0;
}
}

View File

@ -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);
@ -853,6 +854,24 @@ void TestAmmRangesAboveHintedMaps() {
Require(sceKernelMunmap(span, page) == 0);
}
void TestAmmUsageStats() {
std::array<std::uint64_t, 4> stats{};
Require(sceAmprAmmGetUsageStatsData(nullptr) == static_cast<int>(0x80020016));
stats[0] = 0x19;
Require(sceAmprAmmGetUsageStatsData(stats.data()) == static_cast<int>(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;
@ -1293,6 +1312,7 @@ int main() {
TestResolveSymbolicLink();
TestGatherScatter();
TestAmmRangesAboveHintedMaps();
TestAmmUsageStats();
TestAmm();
TestAmmRemapAndProtect();
TestAmmPrt();

View File

@ -10,5 +10,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

View File

@ -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