Merge pull request #3448 from Feuris/carry/agc-debug-raise-exception

feat(libSceAgc): implement sceAgcDebugRaiseException
This commit is contained in:
Adrià 2026-10-11 13:43:54 +02:00 committed by GitHub
commit 077eeb05ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 32 additions and 5 deletions

View File

@ -29,6 +29,7 @@ add_library(libSceAgc SHARED EXCLUDE_FROM_ALL
${CMAKE_CURRENT_SOURCE_DIR}/DcbState/src/Predication.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DcbState/src/Registers.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DcbState/src/Workload.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/Debug.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/PacketInfo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/Platform.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/RegisterDefaults.cpp

View File

@ -0,0 +1,4 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_DEBUG_HPP
#define CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_DEBUG_HPP
#endif

View File

@ -0,0 +1,14 @@
#include "prx/libSceAgc/Misc/include/Debug.hpp"
#include <cstdint>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
extern "C" {
int APS5_VABI sceAgcDebugRaiseException(std::uint32_t exceptionId) {
APS5_LOG_OUT("sceAgcDebugRaiseException exceptionId=0x%08x", static_cast<unsigned>(exceptionId));
return 0;
}
}

View File

@ -50,11 +50,6 @@ int APS5_VABI sceAgcDcbSetWorkloadStreamInactive() {
return 0;
}
int APS5_VABI sceAgcDebugRaiseException() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceAgcGetDefaultCxStateFlat() {
NotImplemented_nid_no_patch(__func__);
return 0;

View File

@ -36,6 +36,7 @@ extern "C" std::uint32_t* APS5_VABI sceAgcAcbSetMarker(CommandBuffer* buf, const
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetIndexBuffer(CommandBuffer* buf, std::uint64_t indexAddress);
extern "C" std::uint32_t* APS5_VABI sceAgcDcbSetBaseIndirectArgs(CommandBuffer* buf, std::uint32_t shaderType, const volatile void* indirectBaseAddr);
extern "C" std::uint32_t* APS5_VABI sceAgcSetNop(CommandBuffer* buf, std::uint32_t sizeDw);
extern "C" int APS5_VABI sceAgcDebugRaiseException(std::uint32_t exceptionId);
namespace {
@ -403,6 +404,16 @@ void testMemory() {
check(storage.words == beforeMask, "invalid mask patch modified packet memory");
}
void testDebugRaiseException() {
int result = -1;
try {
result = sceAgcDebugRaiseException(0x1234abcdu);
} catch (const std::exception& error) {
throw std::runtime_error(std::string("debug exception stopped the caller: ") + error.what());
}
check(result == 0, "debug exception did not return 0");
}
void testDefaults() {
std::uint32_t state = 0x12345678;
check(sceAgcInit_0090(&state, 8) == 0 && state == 0x12345678, "AGC initialization failed or modified caller state");
@ -448,6 +459,7 @@ int main(int argc, char** argv) {
testRegisterRange();
testPacketPayloadAddress();
testMemory();
testDebugRaiseException();
testDefaults();
LibcRunShutdown_nid_postfix();
std::puts("AGC command tests passed");

View File

@ -397,6 +397,7 @@ Throughout the project, every function at every stage either **does exactly what
- [pthread_sigmask](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) shares the process-wide mask of `sigprocmask` and `_sigprocmask`, which keeps only the first 32 signals; FreeBSD keeps a mask per thread
- [sceKernelRaiseException](../../core/libs/prx/libkernel/System/src/Exception.cpp) reaches a thread that waits in an alertable `TimedWait` wait through an APC. A thread blocked anywhere else, including all waits under `APS5_COARSE_TIMED_WAITS` and host waits inside the emulator, is redirected and runs the handler only when that wait returns
- [sceKernelRaiseException](../../core/libs/prx/libkernel/System/src/Exception.cpp) on Windows runs the handler wherever the target thread was interrupted. It waits only while the thread is inside winpthreads or restoring a context through `NtContinue`, and throws if that lasts 1 s, so a handler that calls into other host code the thread was interrupted in, such as the C runtime's heap or a lock of the emulator, can deadlock on it or reenter it
- [sceAgcDebugRaiseException](../../core/libs/prx/libSceAgc/Misc/src/Debug.cpp) (libSceAgc) - logs the exception id and returns 0, as retail hardware does nothing per [OpenAGC](https://github.com/OpenAGC/OpenAGC/blob/3c7e8072f0d7684e930454794fd5c02056946d73/src/game_compat.c); the trap (`ud2`) OpenAGC describes for development hardware is not reproduced. Neither is verified on a console. The `uint32` exception id is [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/6f0cddd4404ec5203e71fea77e75fc373299ba3f/src/libs/agc.cpp)'s claim; OpenAGC declares no arguments, so the logged id may be leftover register contents
- [sigaltstack](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) records each thread's alternate signal stack and reports it back, following FreeBSD's `kern_sigaltstack` (`EINVAL` for flags other than `SS_DISABLE`, `ENOMEM` below `MINSIGSTKSZ` 2048), but handlers never run on it, so `SS_ONSTACK` and `EPERM` are never reported
- [libSceUlt queues](../../core/libs/prx/libSceUlt/Export.cpp) use preallocated host storage instead of the supplied guest work area; its existing size formula and the 512-byte object layouts remain unverified. Waiting-queue pool thread limits and waiter priority ordering are not implemented. Finalization wakes blocked queue callers with `ULT_ERROR_STATE`.
- [Thread cancellation](../../core/libs/prx/libkernel/Pthread/src/Thread.cpp) (libkernel) follows FreeBSD libthr (states and types 0/1 and 0/2, `PTHREAD_CANCELED` 1, the `_pthread_cleanup_info` node layout), not measured on the console. A request is acted on only in `scePthreadTestcancel`, the condition variable, `sem` and `scePthreadSem` waits, `scePthreadJoin` and the sleeps, and their POSIX names; file and socket calls are not cancellation points. A sleep is not interrupted: the thread exits when it ends. The asynchronous type acts like the deferred one, except at the two set calls.