Skip to content

Commit

Permalink
equeue: sceGnmGetEqEventType/sceKernelGetEventData impl
Browse files Browse the repository at this point in the history
  • Loading branch information
Nenkai committed Dec 21, 2024
1 parent 8d8bb05 commit d71a86b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 23 deletions.
26 changes: 16 additions & 10 deletions src/core/libraries/gnmdriver/gnmdriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace Libraries::GnmDriver {

using namespace AmdGpu;

enum GnmEventIdents : u64 {
enum GnmEqEventType : u64 {
Compute0RelMem = 0x00,
Compute1RelMem = 0x01,
Compute2RelMem = 0x02,
Expand Down Expand Up @@ -357,11 +357,17 @@ s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata) {
Platform::IrqC::Instance()->Register(
static_cast<Platform::InterruptId>(id),
[=](Platform::InterruptId irq) {
ASSERT_MSG(irq == static_cast<Platform::InterruptId>(id),
"An unexpected IRQ occured"); // We need to convert IRQ# to event id and do
// proper filtering in trigger function
eq->TriggerEvent(static_cast<GnmEventIdents>(id), SceKernelEvent::Filter::GraphicsCore,
nullptr);
ASSERT_MSG(irq == static_cast<Platform::InterruptId>(id), "An unexpected IRQ occured");

// We need to convert IRQ# to event id
// Exclude ids we shouldn't care about as they aren't a valid EqEventType.
if (irq == Platform::InterruptId::GpuIdle || irq == Platform::InterruptId::GfxFlip)
return;

// Event data is expected to be EqEventType as per sceGnmGetEqEventType.
auto event_type = static_cast<GnmEqEventType>(id);
eq->TriggerEvent(event_type, SceKernelEvent::Filter::GraphicsCore,
reinterpret_cast<void*>(event_type));
},
eq);
return ORBIS_OK;
Expand Down Expand Up @@ -476,7 +482,7 @@ s32 PS4_SYSV_ABI sceGnmDeleteEqEvent(SceKernelEqueue eq, u64 id) {
return ORBIS_KERNEL_ERROR_EBADF;
}

eq->RemoveEvent(id);
eq->RemoveEvent(id, SceKernelEvent::Filter::GraphicsCore);

Platform::IrqC::Instance()->Unregister(static_cast<Platform::InterruptId>(id), eq);
return ORBIS_OK;
Expand Down Expand Up @@ -1000,9 +1006,9 @@ int PS4_SYSV_ABI sceGnmGetDebugTimestamp() {
return ORBIS_OK;
}

int PS4_SYSV_ABI sceGnmGetEqEventType() {
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev) {
LOG_TRACE(Lib_GnmDriver, "called");
return sceKernelGetEventData(ev);
}

int PS4_SYSV_ABI sceGnmGetEqTimeStamp() {
Expand Down
2 changes: 1 addition & 1 deletion src/core/libraries/gnmdriver/gnmdriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ int PS4_SYSV_ABI sceGnmGetCoredumpMode();
int PS4_SYSV_ABI sceGnmGetCoredumpProtectionFaultTimestamp();
int PS4_SYSV_ABI sceGnmGetDbgGcHandle();
int PS4_SYSV_ABI sceGnmGetDebugTimestamp();
int PS4_SYSV_ABI sceGnmGetEqEventType();
int PS4_SYSV_ABI sceGnmGetEqEventType(const SceKernelEvent* ev);
int PS4_SYSV_ABI sceGnmGetEqTimeStamp();
int PS4_SYSV_ABI sceGnmGetGpuBlockStatus();
u32 PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency();
Expand Down
32 changes: 23 additions & 9 deletions src/core/libraries/kernel/equeue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,36 @@

namespace Libraries::Kernel {

// All events are uniquely identified by their id and filter.

bool EqueueInternal::AddEvent(EqueueEvent& event) {
std::scoped_lock lock{m_mutex};

event.time_added = std::chrono::steady_clock::now();

const auto& it = std::ranges::find(m_events, event);
if (it != m_events.cend()) {
*it = std::move(event);
} else {
bool has_event = false;
for (auto& ev : m_events) {
if (ev.event.ident == event.event.ident && ev.event.filter == event.event.filter) {
ev = std::move(event);
has_event = true;
break;
}
}

if (!has_event) {
m_events.emplace_back(std::move(event));
}

return true;
}

bool EqueueInternal::RemoveEvent(u64 id) {
bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
bool has_found = false;
std::scoped_lock lock{m_mutex};

const auto& it =
std::ranges::find_if(m_events, [id](auto& ev) { return ev.event.ident == id; });
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
return ev.event.ident == id && ev.event.filter == filter;
});
if (it != m_events.cend()) {
m_events.erase(it);
has_found = true;
Expand Down Expand Up @@ -66,7 +75,7 @@ int EqueueInternal::WaitForEvents(SceKernelEvent* ev, int num, u32 micros) {

if (ev->flags & SceKernelEvent::Flags::OneShot) {
for (auto ev_id = 0u; ev_id < count; ++ev_id) {
RemoveEvent(ev->ident);
RemoveEvent(ev->ident, ev->filter);
}
}

Expand Down Expand Up @@ -332,7 +341,7 @@ int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id) {
return ORBIS_KERNEL_ERROR_EBADF;
}

if (!eq->RemoveEvent(id)) {
if (!eq->RemoveEvent(id, SceKernelEvent::Filter::User)) {
return ORBIS_KERNEL_ERROR_ENOENT;
}
return ORBIS_OK;
Expand All @@ -342,6 +351,10 @@ s16 PS4_SYSV_ABI sceKernelGetEventFilter(const SceKernelEvent* ev) {
return ev->filter;
}

u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev) {
return ev->data;
}

void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue);
LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEqueue);
Expand All @@ -354,6 +367,7 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
LIB_FUNCTION("23CPPI1tyBY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventFilter);
LIB_FUNCTION("kwGyyjohI50", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventData);
}

} // namespace Libraries::Kernel
13 changes: 10 additions & 3 deletions src/core/libraries/kernel/equeue.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ struct EqueueEvent {
void Reset() {
is_triggered = false;
event.fflags = 0;
event.data = 0;

// Ensure not to clear event data for Eq events, as it'll be fetched by
// sceGnmGetEqEventType.
if (event.filter != SceKernelEvent::Filter::GraphicsCore) {
event.data = 0;
}
}

void Trigger(void* data) {
Expand All @@ -83,7 +88,7 @@ struct EqueueEvent {
}

bool operator==(const EqueueEvent& ev) const {
return ev.event.ident == event.ident;
return ev.event.ident == event.ident && ev.event.filter == event.filter;
}

private:
Expand All @@ -99,7 +104,7 @@ class EqueueInternal {
}

bool AddEvent(EqueueEvent& event);
bool RemoveEvent(u64 id);
bool RemoveEvent(u64 id, s16 filter);
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
int GetTriggeredEvents(SceKernelEvent* ev, int num);
Expand All @@ -122,6 +127,8 @@ class EqueueInternal {
using SceKernelUseconds = u32;
using SceKernelEqueue = EqueueInternal*;

u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);

void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);

} // namespace Libraries::Kernel

0 comments on commit d71a86b

Please sign in to comment.