fix(libkernel): report AMPR completion events with the AMPR filter

AMPR events were registered and raised as EVFILT_USER. Titles that
dispatch their AMPR queue by filter ignore those events, so reads that
complete through WriteKernelEventQueue never finish. Add, delete and
trigger them with EVFILT_AMPR (-25).
This commit is contained in:
Gjon Gojcevic 2026-10-07 19:37:40 -04:00
parent df16c4c256
commit c95721f701
4 changed files with 33 additions and 3 deletions

View File

@ -590,7 +590,7 @@ void _execute(const Apr::CommandBufferObject& buffer) {
}
case Apr::Opcode::WriteKernelEventQueue: {
const auto command = _read<Apr::WriteKernelEventQueueCommand>(buffer, cursor);
EqueueTriggerEvent_nid_postfix(static_cast<KernelEqueue>(command.equeue), static_cast<uintptr_t>(command.ident), EVFILT_USER, reinterpret_cast<void*>(command.data));
EqueueTriggerEvent_nid_postfix(static_cast<KernelEqueue>(command.equeue), static_cast<uintptr_t>(command.ident), EVFILT_AMPR, reinterpret_cast<void*>(command.data));
break;
}
case Apr::Opcode::WriteAddressFromTimeCounter: {

View File

@ -441,7 +441,7 @@ int APS5_VABI sceKernelAddAmprEvent(KernelEqueue eq, int id, void* udata) {
}
KernelEqueueEvent event{};
event.event.ident = static_cast<uintptr_t>(id);
event.event.filter = EVFILT_USER;
event.event.filter = EVFILT_AMPR;
event.event.flags = EV_ADD | EV_CLEAR;
event.event.udata = udata;
event.filter.triggerFunc = [](KernelEqueueEvent* e, void* data) {
@ -473,7 +473,7 @@ int APS5_VABI sceKernelDeleteAmprEvent(KernelEqueue eq, int id) {
if (eq == 0) {
return EQUEUE_OK;
}
EqueueDeleteEvent_nid_postfix(eq, static_cast<uintptr_t>(id), EVFILT_USER);
EqueueDeleteEvent_nid_postfix(eq, static_cast<uintptr_t>(id), EVFILT_AMPR);
return EQUEUE_OK;
}

View File

@ -18,6 +18,7 @@ static constexpr int16_t EVFILT_TIMER = -7;
static constexpr int16_t EVFILT_USER = -11;
static constexpr int16_t EVFILT_VIDEO_OUT = -13;
static constexpr int16_t EVFILT_HRTIMER = -15;
static constexpr int16_t EVFILT_AMPR = -25;
static constexpr uint16_t EV_ADD = 0x0001;
static constexpr uint16_t EV_ONESHOT = 0x0010;

View File

@ -1,3 +1,4 @@
#include "SceTypes.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libkernel/Apr/include/AprCommandBuffer.hpp"
#include <array>
@ -112,6 +113,15 @@ std::int64_t APS5_VABI sceAmprAmmMeasureAmmCommandSizeModifyProtect(std::uint64_
std::int64_t APS5_VABI sceAmprAmmMeasureAmmCommandSizeModifyProtectWithGpuMaskId(std::uint64_t, std::uint64_t, std::int32_t, std::int32_t, std::uint8_t);
std::int64_t APS5_VABI sceAmprAmmMeasureAmmCommandSizeModifyMtypeProtect(std::uint64_t, std::uint64_t, std::int32_t, std::int32_t, std::int32_t);
std::int64_t APS5_VABI sceAmprAmmMeasureAmmCommandSizeModifyMtypeProtectWithGpuMaskId(std::uint64_t, std::uint64_t, std::int32_t, std::int32_t, std::int32_t, std::uint8_t);
int APS5_VABI sceKernelCreateEqueue(KernelEqueue*, const char*);
int APS5_VABI sceKernelDeleteEqueue(KernelEqueue);
int APS5_VABI sceKernelWaitEqueue(KernelEqueue, KernelEvent*, int, int*, const KernelUseconds*);
int APS5_VABI sceKernelAddAmprEvent(KernelEqueue, int, void*);
int APS5_VABI sceKernelDeleteAmprEvent(KernelEqueue, int);
int APS5_VABI sceKernelGetEventFilter(const KernelEvent*);
std::uintptr_t APS5_VABI sceKernelGetEventId(const KernelEvent*);
std::intptr_t APS5_VABI sceKernelGetEventData(const KernelEvent*);
void* APS5_VABI sceKernelGetEventUserData(const KernelEvent*);
}
static void RequireAt(bool value, int line) {
@ -247,6 +257,24 @@ void TestSubmission() {
Require(first == 0x1111 && second == 0x2222);
}
void TestKernelEventQueue() {
KernelEqueue eq = 0;
int userData = 0;
Require(sceKernelCreateEqueue(&eq, "ampr") == 0);
Require(sceKernelAddAmprEvent(eq, 7, &userData) == 0);
Recorder recorder;
Require(sceAmprCommandBufferWriteKernelEventQueue_04_00(&recorder.buffer, static_cast<std::uint64_t>(eq), 7, 0x1234, 0) == 0);
Require(sceKernelAprSubmitCommandBuffer(&recorder.buffer, 0) == 0);
KernelEvent event{};
int count = 0;
const KernelUseconds poll = 0;
Require(sceKernelWaitEqueue(eq, &event, 1, &count, &poll) == 0 && count == 1);
Require(sceKernelGetEventFilter(&event) == -25);
Require(sceKernelGetEventId(&event) == 7 && sceKernelGetEventData(&event) == 0x1234 && sceKernelGetEventUserData(&event) == &userData);
Require(sceKernelDeleteAmprEvent(eq, 7) == 0);
Require(sceKernelDeleteEqueue(eq) == 0);
}
void TestWaits() {
Recorder recorder;
alignas(8) std::uint64_t value = 5;
@ -902,6 +930,7 @@ int main() {
TestRejectedArguments();
TestFullBuffer();
TestSubmission();
TestKernelEventQueue();
TestWaits();
TestCounters();
TestRejectedWaitsAndCounters();