AnyPS5/core/libs/prx/libSceLibcInternal/UserContext.cpp

64 lines
2.6 KiB
C++

#include "prx/libc/include/GuestStacks.hpp"
#include "prx/libc/include/Shutdown.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include "prx/libkernel/System/include/UserContext.hpp"
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
extern "C" int APS5_VABI setcontext_nid_postfix(const UserUcontext* context);
namespace {
using ContextFunction = void (APS5_VABI*)(std::uint64_t, std::uint64_t, std::uint64_t, std::uint64_t, std::uint64_t, std::uint64_t);
constexpr int MaximumArguments = 6;
constexpr std::uint64_t MinimumStackSize = 2048;
}
extern "C" {
[[noreturn]] void APS5_VABI Aps5MakecontextStart_nid_no_patch(UserUcontext* context, ContextFunction function, const std::uint64_t* arguments) {
function(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
if (context->link == nullptr) LibcExit_nid_no_patch(0);
setcontext_nid_postfix(context->link);
std::abort();
}
void APS5_VABI makecontext_nid_postfix(UserUcontext* context, void (APS5_VABI* start)(), int count, ...) {
if (context == nullptr || context->mcontext.len != sizeof(UserMcontext)) return;
if (count < 0 || count > MaximumArguments || context->stackPointer == nullptr || context->stackSize < MinimumStackSize) {
context->mcontext.len = 0;
return;
}
const auto top = (reinterpret_cast<std::uintptr_t>(context->stackPointer) + context->stackSize) & ~static_cast<std::uintptr_t>(15);
auto* arguments = reinterpret_cast<std::uint64_t*>(top) - MaximumArguments;
auto* stack = arguments - 1;
#ifdef _WIN32
__builtin_sysv_va_list list;
__builtin_sysv_va_start(list, count);
for (int index = 0; index < count; ++index) arguments[index] = __builtin_va_arg(list, std::uint64_t);
__builtin_sysv_va_end(list);
#else
std::va_list list;
va_start(list, count);
for (int index = 0; index < count; ++index) arguments[index] = va_arg(list, std::uint64_t);
va_end(list);
#endif
for (int index = count; index < MaximumArguments; ++index) arguments[index] = 0;
*stack = 0;
auto& machine = context->mcontext;
machine.rdi = reinterpret_cast<std::uint64_t>(context);
machine.rsi = reinterpret_cast<std::uint64_t>(start);
machine.rdx = reinterpret_cast<std::uint64_t>(arguments);
machine.rbp = 0;
machine.rbx = reinterpret_cast<std::uint64_t>(stack);
machine.rsp = reinterpret_cast<std::uint64_t>(stack);
machine.rip = reinterpret_cast<std::uint64_t>(&Aps5MakecontextStart_nid_no_patch);
GuestStacks::GuestStackRegister_nid_no_patch(context->stackPointer, context->stackSize);
}
}