diff --git a/include/services/gsp_gpu.hpp b/include/services/gsp_gpu.hpp index fd1b3e4f..3a7c684e 100644 --- a/include/services/gsp_gpu.hpp +++ b/include/services/gsp_gpu.hpp @@ -2,11 +2,23 @@ #include "helpers.hpp" #include "kernel_types.hpp" #include "memory.hpp" +#include + +enum class GPUInterrupt : u8 { + PSC0 = 0, // Memory fill completed + PSC1 = 1, // ? + VBlank0 = 2, // ? + VBlank1 = 3, // ? + PPF = 4, // Display transfer finished + P3D = 5, // Command list processing finished + DMA = 6 +}; class GPUService { Handle handle = KernelHandles::GPU; Memory& mem; u32& currentPID; // Process ID of the current process + u8* sharedMem; // Pointer to GSP shared memory // At any point in time only 1 process has privileges to use rendering functions // This is the PID of that process @@ -22,4 +34,11 @@ public: GPUService(Memory& mem, u32& currentPID) : mem(mem), currentPID(currentPID) {} void reset(); void handleSyncRequest(u32 messagePointer); + void requestInterrupt(GPUInterrupt type); + void setSharedMem(u8* ptr) { + sharedMem = ptr; + if (ptr != nullptr) { // Zero-fill shared memory in case the process tries to read stale service data or vice versa + std::memset(ptr, 0, 0x1000); + } + } }; \ No newline at end of file diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index d19260a1..abf731c1 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -29,4 +29,6 @@ public: // Forward a SendSyncRequest IPC message to the service with the respective handle void sendCommandToService(u32 messagePointer, Handle handle); + void requestGPUInterrupt(GPUInterrupt type) { gsp_gpu.requestInterrupt(type); } + void setGSPSharedMem(u8* ptr) { gsp_gpu.setSharedMem(ptr); } }; \ No newline at end of file diff --git a/src/core/kernel/events.cpp b/src/core/kernel/events.cpp index 0762cde2..40244a06 100644 --- a/src/core/kernel/events.cpp +++ b/src/core/kernel/events.cpp @@ -57,5 +57,6 @@ void Kernel::waitSynchronization1() { } printf("WaitSynchronization1(handle = %X, ns = %lld) (STUBBED)\n", handle, ns); + serviceManager.requestGPUInterrupt(GPUInterrupt::VBlank0); regs[0] = SVCResult::Success; } \ No newline at end of file diff --git a/src/core/kernel/memory_management.cpp b/src/core/kernel/memory_management.cpp index c6787441..7c986187 100644 --- a/src/core/kernel/memory_management.cpp +++ b/src/core/kernel/memory_management.cpp @@ -105,6 +105,7 @@ void Kernel::mapMemoryBlock() { if (block == KernelHandles::GSPSharedMemHandle) { mem.mapGSPSharedMemory(addr, myPerms, otherPerms); + serviceManager.setGSPSharedMem(static_cast(mem.getReadPointer(addr))); } else { Helpers::panic("MapMemoryBlock where the handle does not refer to GSP memory"); } diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 535af09c..0323ab75 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -18,6 +18,7 @@ namespace Result { void GPUService::reset() { privilegedProcess = 0xFFFFFFFF; // Set the privileged process to an invalid handle + sharedMem = nullptr; } void GPUService::handleSyncRequest(u32 messagePointer) { @@ -63,6 +64,19 @@ void GPUService::registerInterruptRelayQueue(u32 messagePointer) { mem.write32(messagePointer + 16, KernelHandles::GSPSharedMemHandle); } +void GPUService::requestInterrupt(GPUInterrupt type) { + if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet + return; + } + + u8 index = sharedMem[0]; + u8& interruptCount = sharedMem[1]; + u8 flagIndex = (index + interruptCount) % 0x34; + interruptCount++; + + sharedMem[0xC + flagIndex] = static_cast(type); +} + void GPUService::writeHwRegs(u32 messagePointer) { u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned const u32 size = mem.read32(messagePointer + 8); // Size in bytes