mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-01 12:45:56 +00:00
Under Rosetta the main thread stack lies at about 12 GiB, inside the guest arena, where a title can map fixed addresses; a fixed mapping over it aborts with a host region overlap. - Aps5StartGuest moves the main thread onto a 16 MiB stack at 0x600000000000 when the old stack overlaps a host region of the arena. It copies argv, environ, the program name and the initial block off the old stack, then frees the old stack and releases its range to the arena. - The guest thread keeps the stack size of the original main thread. - The arena gets GuestArenaOverlapsHostRegion and GuestArenaReleaseHostRegion for POSIX hosts. - guest_main_stack_move starts the guest, then requires the main thread outside the arena, a fixed mapping where the old stack was, and argv and the environment intact. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
68 lines
2.2 KiB
C++
68 lines
2.2 KiB
C++
#include "prx/libc/include/GuestArena.hpp"
|
|
#include <crt_externs.h>
|
|
#include <pthread.h>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
extern "C" [[noreturn]] void Aps5StartGuest_nid_no_patch(void (*entry)(void*, void*), void* block);
|
|
extern "C" void Aps5RunOnMainThread_nid_no_patch(void (*function)(void*), void* context);
|
|
|
|
namespace {
|
|
|
|
constexpr std::uintptr_t MappingAlignment = 0x10000;
|
|
constexpr std::size_t MappingBytes = 0x10000;
|
|
|
|
std::uintptr_t originalStack = 0;
|
|
std::string originalArgument;
|
|
bool originalInArena = false;
|
|
|
|
void Require(bool value, const char* what) {
|
|
if (value) return;
|
|
std::fprintf(stderr, "check failed: %s\n", what);
|
|
std::exit(1);
|
|
}
|
|
|
|
bool InArena(std::uintptr_t address) {
|
|
std::uintptr_t base = 0;
|
|
std::size_t bytes = 0;
|
|
GuestArena::GuestArenaRange_nid_postfix(&base, &bytes);
|
|
return address >= base && address < base + bytes;
|
|
}
|
|
|
|
void CheckMainThread(void*) {
|
|
int local = 0;
|
|
Require(pthread_main_np() != 0, "the check runs on the main thread");
|
|
const auto address = reinterpret_cast<std::uintptr_t>(&local);
|
|
if (originalInArena) {
|
|
Require(!InArena(address), "the main thread stack is outside the guest arena");
|
|
Require(address != originalStack, "the main thread stack moved");
|
|
const auto old = reinterpret_cast<const void*>(originalStack & ~(MappingAlignment - 1));
|
|
try {
|
|
GuestArena::GuestArenaMarkUsed_nid_postfix(old, MappingBytes);
|
|
} catch (const std::runtime_error&) {
|
|
Require(false, "a fixed guest mapping fits where the main thread stack was");
|
|
}
|
|
GuestArena::GuestArenaRelease_nid_postfix(old, MappingBytes);
|
|
}
|
|
Require(originalArgument == (*_NSGetArgv())[0], "argv survived the move");
|
|
Require(std::getenv("PATH") != nullptr, "the environment survived the move");
|
|
}
|
|
|
|
void Guest(void*, void*) {
|
|
Aps5RunOnMainThread_nid_no_patch(CheckMainThread, nullptr);
|
|
std::exit(0);
|
|
}
|
|
|
|
}
|
|
|
|
int main(int, char** argv) {
|
|
int local = 0;
|
|
originalStack = reinterpret_cast<std::uintptr_t>(&local);
|
|
originalInArena = InArena(originalStack);
|
|
originalArgument = argv[0];
|
|
Aps5StartGuest_nid_no_patch(Guest, nullptr);
|
|
}
|