Files
AnyPS5/core/libs/prx/libc/src/JumpBuffer.cpp
T
DariusHQ cf1545d751 feat(libkernel): implement getcontext, setcontext and makecontext
PSXS5, SwanStationPS5 and Nuvio stop at start-up on setcontext on main,
and EVO Player and ProsperoStore do on Windows. The three are imported
by the statically linked OpenSSL's ASYNC code.

The three use FreeBSD 11's amd64 ucontext_t (mcontext at 0x10, mc_len
800, uc_link at 0x330, 0x370 bytes), which the titles are built
against: EVO Player's ASYNC_is_capable captures into a 0x370-byte stack
buffer, and async_fibre_makecontext sets uc_link at 0x330 and uc_stack
at 0x338. getcontext saves every register at its call in assembly and
stores the context as FreeBSD's sys_getcontext does: rax and rdx as 0,
the carry flag clear, the FXSAVE image and the signal mask, and nothing
from uc_link on. setcontext checks mc_len and mc_flags as set_mcontext
does, installs the signal mask, masks MXCSR with the host's MXCSR_MASK
and returns through iretq, so every general register and the flags are
restored and nothing is written below the target stack pointer.
makecontext follows FreeBSD 11's amd64 libc.

Windows checks guard-page growth and exception unwinding against the
stack bounds in the TEB. setcontext and longjmp now set them to the
stack they switch to, which makecontext registers and pins writable as
libSceFiber does for fiber stacks. OpenSSL enters a context with
setcontext and then switches with _setjmp and _longjmp.
2026-10-11 13:00:38 +03:00

49 lines
1.5 KiB
C++

#include "prx/libc/include/General.hpp"
#include "prx/libc/include/general/AsmMacros.hpp"
// setjmp/longjmp must capture the guest's own frame, so they are written directly in assembly with
// the guest (System V) calling convention. The saved state fits the guest's 96-byte jmp_buf:
// return address, rbx, rsp, rbp, r12-r15, MXCSR and the x87 control word.
asm(".text\n"
APS5_ASM_FUNCTION("setjmp_nid_postfix")
" mov (%rsp), %rax\n"
" mov %rax, 0(%rdi)\n"
" mov %rbx, 8(%rdi)\n"
" lea 8(%rsp), %rax\n"
" mov %rax, 16(%rdi)\n"
" mov %rbp, 24(%rdi)\n"
" mov %r12, 32(%rdi)\n"
" mov %r13, 40(%rdi)\n"
" mov %r14, 48(%rdi)\n"
" mov %r15, 56(%rdi)\n"
" stmxcsr 64(%rdi)\n"
" fnstcw 68(%rdi)\n"
" xor %eax, %eax\n"
" ret\n"
APS5_ASM_FUNCTION("longjmp_nid_postfix")
#ifdef _WIN32
" mov %rdi, %rbx\n"
" mov %esi, %r12d\n"
" mov 16(%rdi), %rdi\n"
" and $-16, %rsp\n"
" call GuestStackSwitch_nid_no_patch\n"
" mov %rbx, %rdi\n"
" mov %r12d, %esi\n"
#endif
" mov %esi, %eax\n"
" test %eax, %eax\n"
" jnz 1f\n"
" inc %eax\n"
"1:\n"
" mov 8(%rdi), %rbx\n"
" mov 16(%rdi), %rsp\n"
" mov 24(%rdi), %rbp\n"
" mov 32(%rdi), %r12\n"
" mov 40(%rdi), %r13\n"
" mov 48(%rdi), %r14\n"
" mov 56(%rdi), %r15\n"
" ldmxcsr 64(%rdi)\n"
" fldcw 68(%rdi)\n"
" jmp *0(%rdi)\n");