rpcsx/rpcsx-os/main.cpp

724 lines
20 KiB
C++
Raw Normal View History

2023-07-13 16:50:36 +02:00
#include "align.hpp"
2023-06-24 22:48:25 +02:00
#include "amdgpu/bridge/bridge.hpp"
2023-07-07 13:23:54 +02:00
#include "backtrace.hpp"
2023-06-24 22:48:25 +02:00
#include "bridge.hpp"
2023-06-23 02:28:14 +02:00
#include "io-device.hpp"
#include "io-devices.hpp"
#include "linker.hpp"
#include "ops.hpp"
2023-07-06 18:16:25 +02:00
#include "thread.hpp"
2023-06-23 02:28:14 +02:00
#include "vfs.hpp"
#include "vm.hpp"
#include <atomic>
2023-07-07 13:23:54 +02:00
#include <elf.h>
2023-06-24 22:48:25 +02:00
#include <filesystem>
2023-06-23 02:28:14 +02:00
#include <orbis/KernelContext.hpp>
#include <orbis/module.hpp>
#include <orbis/module/Module.hpp>
#include <orbis/sys/sysentry.hpp>
#include <orbis/sys/sysproto.hpp>
#include <orbis/thread/Process.hpp>
#include <orbis/thread/ProcessOps.hpp>
#include <orbis/thread/Thread.hpp>
#include <fcntl.h>
#include <pthread.h>
#include <sys/mman.h>
2023-07-06 13:26:57 +02:00
#include <ucontext.h>
2023-06-23 02:28:14 +02:00
#include <csignal>
#include <cstddef>
#include <cstdint>
2023-06-24 22:48:25 +02:00
static int g_gpuPid;
2023-06-23 02:28:14 +02:00
__attribute__((no_stack_protector)) static void
handle_signal(int sig, siginfo_t *info, void *ucontext) {
if (auto hostFs = _readgsbase_u64()) {
2023-06-24 22:48:25 +02:00
_writefsbase_u64(hostFs);
}
2023-06-23 02:28:14 +02:00
auto signalAddress = reinterpret_cast<std::uintptr_t>(info->si_addr);
if (rx::thread::g_current != nullptr && sig == SIGSEGV &&
signalAddress >= 0x40000 && signalAddress < 0x100'0000'0000) {
auto ctx = reinterpret_cast<ucontext_t *>(ucontext);
bool isWrite = (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) != 0;
auto origVmProt = rx::vm::getPageProtection(signalAddress);
int prot = 0;
auto page = signalAddress / amdgpu::bridge::kHostPageSize;
if (origVmProt & rx::vm::kMapProtCpuRead) {
prot |= PROT_READ;
}
if (origVmProt & rx::vm::kMapProtCpuWrite) {
prot |= PROT_WRITE;
}
if (origVmProt & rx::vm::kMapProtCpuExec) {
prot |= PROT_EXEC;
}
if (prot & (isWrite ? PROT_WRITE : PROT_READ)) {
auto bridge = rx::bridge.header;
while (true) {
auto flags = bridge->cachePages[page].load(std::memory_order::relaxed);
if ((flags & amdgpu::bridge::kPageReadWriteLock) != 0) {
2023-08-06 16:18:40 +02:00
if ((flags & amdgpu::bridge::kPageLazyLock) != 0) {
if (std::uint32_t gpuCommand = 0;
!bridge->gpuCacheCommand.compare_exchange_weak(gpuCommand,
page)) {
continue;
}
while (!bridge->cachePages[page].compare_exchange_weak(
flags, flags & ~amdgpu::bridge::kPageLazyLock,
std::memory_order::relaxed)) {
}
}
continue;
}
if ((flags & amdgpu::bridge::kPageWriteWatch) == 0) {
break;
}
if (!isWrite) {
prot &= ~PROT_WRITE;
break;
}
if (bridge->cachePages[page].compare_exchange_weak(
flags, amdgpu::bridge::kPageInvalidated,
std::memory_order::relaxed)) {
break;
}
}
if (::mprotect((void *)(page * amdgpu::bridge::kHostPageSize),
amdgpu::bridge::kHostPageSize, prot)) {
std::perror("cache reprotection error");
std::abort();
}
_writefsbase_u64(rx::thread::g_current->fsBase);
return;
}
std::fprintf(stderr, "SIGSEGV, address %lx, access %s, prot %s\n",
signalAddress, isWrite ? "write" : "read",
rx::vm::mapProtToString(origVmProt).c_str());
}
2023-06-24 22:48:25 +02:00
if (g_gpuPid > 0) {
// stop gpu thread
::kill(g_gpuPid, SIGINT);
}
if (sig != SIGINT) {
char buf[128] = "";
int len = snprintf(buf, sizeof(buf), " [%s] %u: Signal address=%p\n",
2023-07-06 18:16:25 +02:00
rx::thread::g_current ? "guest" : "host",
rx::thread::g_current ? rx::thread::g_current->tid
: ::gettid(),
info->si_addr);
2023-06-24 22:48:25 +02:00
write(2, buf, len);
2023-07-06 18:16:25 +02:00
if (std::size_t printed =
2023-07-07 13:23:54 +02:00
rx::printAddressLocation(buf, sizeof(buf), rx::thread::g_current,
2023-07-08 20:47:06 +02:00
(std::uint64_t)info->si_addr)) {
2023-06-24 22:48:25 +02:00
printed += std::snprintf(buf + printed, sizeof(buf) - printed, "\n");
write(2, buf, printed);
}
2023-06-23 02:28:14 +02:00
2023-07-06 13:26:57 +02:00
if (rx::thread::g_current) {
2023-07-07 13:23:54 +02:00
rx::printStackTrace(reinterpret_cast<ucontext_t *>(ucontext),
2023-07-08 20:47:06 +02:00
rx::thread::g_current, 2);
2023-06-24 22:48:25 +02:00
} else {
2023-07-07 13:23:54 +02:00
rx::printStackTrace(reinterpret_cast<ucontext_t *>(ucontext), 2);
2023-06-24 22:48:25 +02:00
}
2023-06-23 02:28:14 +02:00
}
struct sigaction act {};
sigset_t mask;
sigemptyset(&mask);
act.sa_handler = SIG_DFL;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
act.sa_mask = mask;
if (sigaction(sig, &act, NULL)) {
perror("Error sigaction:");
std::exit(-1);
}
2023-06-24 22:48:25 +02:00
if (sig == SIGINT) {
std::raise(SIGINT);
2023-06-23 02:28:14 +02:00
}
}
static void setupSigHandlers() {
stack_t ss;
2023-07-13 16:50:36 +02:00
auto sigStackSize = std::max<std::size_t>(
SIGSTKSZ, utils::alignUp(8 * 1024 * 1024, sysconf(_SC_PAGE_SIZE)));
ss.ss_sp = malloc(sigStackSize);
if (ss.ss_sp == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
2023-07-13 16:50:36 +02:00
ss.ss_size = sigStackSize;
ss.ss_flags = 0;
if (sigaltstack(&ss, NULL) == -1) {
perror("sigaltstack");
exit(EXIT_FAILURE);
}
2023-07-06 18:16:25 +02:00
struct sigaction act {};
2023-06-23 02:28:14 +02:00
act.sa_sigaction = handle_signal;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
if (sigaction(SIGSYS, &act, NULL)) {
perror("Error sigaction:");
exit(-1);
}
if (sigaction(SIGILL, &act, NULL)) {
perror("Error sigaction:");
exit(-1);
}
if (sigaction(SIGSEGV, &act, NULL)) {
perror("Error sigaction:");
exit(-1);
}
if (sigaction(SIGBUS, &act, NULL)) {
perror("Error sigaction:");
exit(-1);
}
if (sigaction(SIGABRT, &act, NULL)) {
perror("Error sigaction:");
exit(-1);
}
2023-06-24 22:48:25 +02:00
if (sigaction(SIGINT, &act, NULL)) {
perror("Error sigaction:");
exit(-1);
}
2023-06-23 02:28:14 +02:00
}
struct StackWriter {
std::uint64_t address;
template <typename T> std::uint64_t push(T value) {
address -= sizeof(value);
address &= ~(alignof(T) - 1);
*reinterpret_cast<T *>(address) = value;
return address;
}
void align(std::uint64_t alignment) { address &= ~(alignment - 1); }
std::uint64_t pushString(const char *value) {
auto len = std::strlen(value);
address -= len + 1;
std::memcpy(reinterpret_cast<void *>(address), value, len + 1);
return address;
}
std::uint64_t alloc(std::uint64_t size, std::uint64_t alignment) {
address -= size;
address &= ~(alignment - 1);
return address;
}
};
static bool g_traceSyscalls = false;
static const char *getSyscallName(orbis::Thread *thread, int sysno) {
auto sysvec = thread->tproc->sysent;
if (sysno >= sysvec->size) {
return nullptr;
}
return orbis::getSysentName(sysvec->table[sysno].call);
}
static void onSysEnter(orbis::Thread *thread, int id, uint64_t *args,
int argsCount) {
if (true || !g_traceSyscalls) {
return;
}
2023-07-18 14:56:22 +02:00
flockfile(stderr);
std::fprintf(stderr, " [%u] ", thread->tid);
2023-06-23 02:28:14 +02:00
if (auto name = getSyscallName(thread, id)) {
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, "%s(", name);
2023-06-23 02:28:14 +02:00
} else {
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, "sys_%u(", id);
2023-06-23 02:28:14 +02:00
}
for (int i = 0; i < argsCount; ++i) {
if (i != 0) {
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, ", ");
2023-06-23 02:28:14 +02:00
}
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, "%#lx", args[i]);
2023-06-23 02:28:14 +02:00
}
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, ")\n");
funlockfile(stderr);
2023-06-23 02:28:14 +02:00
}
static void onSysExit(orbis::Thread *thread, int id, uint64_t *args,
int argsCount, orbis::SysResult result) {
if (!result.isError() && !g_traceSyscalls) {
return;
}
2023-07-18 14:56:22 +02:00
flockfile(stderr);
std::fprintf(stderr, "%c: [%u] ", result.isError() ? 'E' : 'S', thread->tid);
2023-06-23 02:28:14 +02:00
if (auto name = getSyscallName(thread, id)) {
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, "%s(", name);
2023-06-23 02:28:14 +02:00
} else {
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, "sys_%u(", id);
2023-06-23 02:28:14 +02:00
}
for (int i = 0; i < argsCount; ++i) {
if (i != 0) {
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, ", ");
2023-06-23 02:28:14 +02:00
}
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, "%#lx", args[i]);
2023-06-23 02:28:14 +02:00
}
2023-07-18 14:56:22 +02:00
std::fprintf(stderr, ") -> Status %d, Value %lx:%lx\n", result.value(),
thread->retval[0], thread->retval[1]);
thread->where();
2023-07-18 14:56:22 +02:00
funlockfile(stderr);
2023-06-23 02:28:14 +02:00
}
static int ps4Exec(orbis::Thread *mainThread,
2023-06-23 02:28:14 +02:00
orbis::utils::Ref<orbis::Module> executableModule,
std::span<const char *> argv, std::span<const char *> envp) {
const auto stackEndAddress = 0x7'ffff'c000ull;
const auto stackSize = 0x40000 * 16;
auto stackStartAddress = stackEndAddress - stackSize;
mainThread->stackStart =
2023-06-23 02:28:14 +02:00
rx::vm::map(reinterpret_cast<void *>(stackStartAddress), stackSize,
2023-07-06 18:16:25 +02:00
rx::vm::kMapProtCpuWrite | rx::vm::kMapProtCpuRead,
rx::vm::kMapFlagAnonymous | rx::vm::kMapFlagFixed |
rx::vm::kMapFlagPrivate | rx::vm::kMapFlagStack);
2023-06-23 02:28:14 +02:00
mainThread->stackEnd =
reinterpret_cast<std::byte *>(mainThread->stackStart) + stackSize;
2023-06-23 02:28:14 +02:00
2023-07-30 00:30:36 +02:00
auto dmem1 = createDmemCharacterDevice(1);
orbis::g_context.dmemDevice = dmem1;
2023-06-23 02:28:14 +02:00
rx::vfs::mount("/dev/dmem0", createDmemCharacterDevice(0));
rx::vfs::mount("/dev/npdrm", createNpdrmCharacterDevice());
rx::vfs::mount("/dev/icc_configuration", createIccConfigurationCharacterDevice());
rx::vfs::mount("/dev/console", createConsoleCharacterDevice());
rx::vfs::mount("/dev/camera", createCameraCharacterDevice());
2023-07-30 00:30:36 +02:00
rx::vfs::mount("/dev/dmem1", dmem1);
2023-06-23 02:28:14 +02:00
rx::vfs::mount("/dev/dmem2", createDmemCharacterDevice(2));
rx::vfs::mount("/dev/stdout", createFdWrapDevice(STDOUT_FILENO));
rx::vfs::mount("/dev/stderr", createFdWrapDevice(STDERR_FILENO));
rx::vfs::mount("/dev/stdin", createFdWrapDevice(STDIN_FILENO));
2023-06-23 02:28:14 +02:00
rx::vfs::mount("/dev/zero", createZeroCharacterDevice());
rx::vfs::mount("/dev/null", createNullCharacterDevice());
rx::vfs::mount("/dev/dipsw", createDipswCharacterDevice());
rx::vfs::mount("/dev/dce", createDceCharacterDevice());
rx::vfs::mount("/dev/hmd_cmd", createHmdCmdCharacterDevice());
rx::vfs::mount("/dev/hmd_snsr", createHmdSnsrCharacterDevice());
rx::vfs::mount("/dev/hmd_3da", createHmd3daCharacterDevice());
rx::vfs::mount("/dev/hmd_dist", createHmdMmapCharacterDevice());
rx::vfs::mount("/dev/hid", createHidCharacterDevice());
rx::vfs::mount("/dev/gc", createGcCharacterDevice());
rx::vfs::mount("/dev/rng", createRngCharacterDevice());
2023-07-29 22:31:54 +02:00
rx::vfs::mount("/dev/sbl_srv", createSblSrvCharacterDevice());
2023-07-26 13:35:40 +02:00
rx::vfs::mount("/dev/ajm", createAjmCharacterDevice());
2023-10-18 00:11:01 +02:00
rx::vfs::mount("/dev/urandom", createUrandomCharacterDevice());
2023-06-23 02:28:14 +02:00
orbis::Ref<orbis::File> stdinFile;
orbis::Ref<orbis::File> stdoutFile;
orbis::Ref<orbis::File> stderrFile;
rx::procOpsTable.open(mainThread, "/dev/stdin", 0, 0, &stdinFile);
rx::procOpsTable.open(mainThread, "/dev/stdout", 0, 0, &stdoutFile);
rx::procOpsTable.open(mainThread, "/dev/stderr", 0, 0, &stderrFile);
mainThread->tproc->fileDescriptors.insert(stdinFile);
mainThread->tproc->fileDescriptors.insert(stdoutFile);
mainThread->tproc->fileDescriptors.insert(stderrFile);
2023-06-23 02:28:14 +02:00
2023-07-29 21:46:28 +02:00
orbis::g_context.shmDevice = createShmDevice();
2023-07-30 13:56:25 +02:00
orbis::g_context.blockpoolDevice = createBlockPoolDevice();
2023-07-29 21:46:28 +02:00
2023-06-23 02:28:14 +02:00
std::vector<std::uint64_t> argvOffsets;
std::vector<std::uint64_t> envpOffsets;
auto libSceLibcInternal = rx::linker::loadModuleFile(
"/system/common/lib/libSceLibcInternal.sprx", mainThread);
if (libSceLibcInternal == nullptr) {
std::fprintf(stderr, "libSceLibcInternal not found\n");
return 1;
}
libSceLibcInternal->id = mainThread->tproc->modulesMap.insert(libSceLibcInternal);
2023-06-23 02:28:14 +02:00
auto libkernel = rx::linker::loadModuleFile(
"/system/common/lib/libkernel_sys.sprx", mainThread);
2023-06-23 02:28:14 +02:00
if (libkernel == nullptr) {
std::fprintf(stderr, "libkernel not found\n");
return 1;
}
libkernel->id = mainThread->tproc->modulesMap.insert(libkernel);
2023-06-23 02:28:14 +02:00
// *reinterpret_cast<std::uint32_t *>(
// reinterpret_cast<std::byte *>(libkernel->base) + 0x6c2e4) = ~0;
StackWriter stack{reinterpret_cast<std::uint64_t>(mainThread->stackEnd)};
2023-06-23 02:28:14 +02:00
for (auto elem : argv) {
argvOffsets.push_back(stack.pushString(elem));
}
argvOffsets.push_back(0);
for (auto elem : envp) {
envpOffsets.push_back(stack.pushString(elem));
}
envpOffsets.push_back(0);
// clang-format off
std::uint64_t auxv[] = {
AT_ENTRY, executableModule->entryPoint,
AT_BASE, reinterpret_cast<std::uint64_t>(libkernel->base),
AT_NULL, 0
};
// clang-format on
std::size_t argSize =
sizeof(std::uint64_t) + sizeof(std::uint64_t) * argvOffsets.size() +
sizeof(std::uint64_t) * envpOffsets.size() + sizeof(auxv);
auto sp = stack.alloc(argSize, 32);
auto arg = reinterpret_cast<std::uint64_t *>(sp);
*arg++ = argvOffsets.size() - 1;
for (auto argvOffsets : argvOffsets) {
*arg++ = argvOffsets;
}
for (auto envpOffset : envpOffsets) {
*arg++ = envpOffset;
}
executableModule = {};
memcpy(arg, auxv, sizeof(auxv));
2023-07-06 13:26:57 +02:00
auto context = new ucontext_t{};
2023-06-23 02:28:14 +02:00
2023-07-06 13:26:57 +02:00
context->uc_mcontext.gregs[REG_RDI] = sp;
context->uc_mcontext.gregs[REG_RSP] = sp;
// FIXME: should be at guest user space
2023-07-06 18:16:25 +02:00
context->uc_mcontext.gregs[REG_RDX] =
reinterpret_cast<std::uint64_t>(+[] { std::printf("At exit\n"); });
;
2023-07-06 13:26:57 +02:00
context->uc_mcontext.gregs[REG_RIP] = libkernel->entryPoint;
mainThread->context = context;
rx::thread::invoke(mainThread);
2023-07-06 13:26:57 +02:00
std::abort();
2023-06-23 02:28:14 +02:00
}
static void usage(const char *argv0) {
std::printf("%s [<options>...] <virtual path to elf> [args...]\n", argv0);
std::printf(" options:\n");
std::printf(" -m, --mount <host path> <virtual path>\n");
std::printf(" -a, --enable-audio\n");
2023-07-06 18:16:25 +02:00
std::printf(" -o, --override <original module name> <virtual path to "
"overriden module>\n");
2023-06-23 02:28:14 +02:00
std::printf(" --trace\n");
}
2023-06-24 22:48:25 +02:00
static std::filesystem::path getSelfDir() {
char path[PATH_MAX];
int len = ::readlink("/proc/self/exe", path, sizeof(path));
if (len < 0 || len >= sizeof(path)) {
// TODO
return std::filesystem::current_path();
}
return std::filesystem::path(path).parent_path();
}
static bool isRpsxGpuPid(int pid) {
if (pid <= 0 || ::kill(pid, 0) != 0) {
return false;
}
char path[PATH_MAX];
std::string procPath = "/proc/" + std::to_string(pid) + "/exe";
auto len = ::readlink(procPath.c_str(), path, sizeof(path));
if (len < 0 || len >= std::size(path)) {
return false;
}
path[len] = 0;
2023-07-06 18:16:25 +02:00
std::printf("filename is '%s'\n",
std::filesystem::path(path).filename().c_str());
2023-06-24 22:48:25 +02:00
return std::filesystem::path(path).filename() == "rpcsx-gpu";
}
static void runRpsxGpu() {
const char *cmdBufferName = "/rpcsx-gpu-cmds";
2023-07-06 18:16:25 +02:00
amdgpu::bridge::BridgeHeader *bridgeHeader =
amdgpu::bridge::openShmCommandBuffer(cmdBufferName);
2023-06-24 22:48:25 +02:00
2023-07-06 18:16:25 +02:00
if (bridgeHeader != nullptr && bridgeHeader->pullerPid > 0 &&
isRpsxGpuPid(bridgeHeader->pullerPid)) {
2023-06-24 22:48:25 +02:00
bridgeHeader->pusherPid = ::getpid();
g_gpuPid = bridgeHeader->pullerPid;
rx::bridge = bridgeHeader;
return;
}
std::printf("Starting rpcsx-gpu\n");
if (bridgeHeader == nullptr) {
bridgeHeader = amdgpu::bridge::createShmCommandBuffer(cmdBufferName);
}
bridgeHeader->pusherPid = ::getpid();
rx::bridge = bridgeHeader;
auto rpcsxGpuPath = getSelfDir() / "rpcsx-gpu";
if (!std::filesystem::is_regular_file(rpcsxGpuPath)) {
std::printf("failed to find rpcsx-gpu, continue without GPU emulation\n");
return;
}
g_gpuPid = ::fork();
if (g_gpuPid == 0) {
// TODO
const char *argv[] = {rpcsxGpuPath.c_str(), nullptr};
::execv(rpcsxGpuPath.c_str(), const_cast<char **>(argv));
}
}
2023-06-23 02:28:14 +02:00
int main(int argc, const char *argv[]) {
if (argc == 2) {
if (std::strcmp(argv[1], "-h") == 0 ||
std::strcmp(argv[1], "--help") == 0) {
usage(argv[0]);
return 1;
}
}
if (argc < 2) {
usage(argv[0]);
return 1;
}
setupSigHandlers();
rx::vfs::initialize();
2023-08-15 02:04:25 +02:00
bool enableAudio = false;
2023-09-03 21:23:50 +02:00
bool asRoot = false;
2023-08-15 02:04:25 +02:00
2023-06-23 02:28:14 +02:00
int argIndex = 1;
while (argIndex < argc) {
if (argv[argIndex] == std::string_view("--mount") ||
argv[argIndex] == std::string_view("-m")) {
if (argc <= argIndex + 2) {
usage(argv[0]);
return 1;
}
std::printf("mounting '%s' to virtual '%s'\n", argv[argIndex + 1],
argv[argIndex + 2]);
if (!std::filesystem::is_directory(argv[argIndex + 1])) {
std::fprintf(stderr, "Directory '%s' not exists\n", argv[argIndex + 1]);
return 1;
}
2023-07-06 18:16:25 +02:00
rx::vfs::mount(argv[argIndex + 2],
createHostIoDevice(argv[argIndex + 1]));
2023-06-23 02:28:14 +02:00
argIndex += 3;
continue;
}
if (argv[argIndex] == std::string_view("--trace")) {
argIndex++;
g_traceSyscalls = true;
continue;
}
2023-09-03 21:23:50 +02:00
if (argv[argIndex] == std::string_view("--root")) {
argIndex++;
asRoot = true;
continue;
}
if (argv[argIndex] == std::string_view("--override") ||
argv[argIndex] == std::string_view("-o")) {
if (argc <= argIndex + 2) {
usage(argv[0]);
return 1;
}
rx::linker::override(argv[argIndex + 1], argv[argIndex + 2]);
argIndex += 3;
continue;
}
if (argv[argIndex] == std::string_view("--enable-audio") ||
argv[argIndex] == std::string_view("-a")) {
argIndex++;
2023-08-15 02:04:25 +02:00
enableAudio = true;
continue;
}
2023-06-23 02:28:14 +02:00
break;
}
if (argIndex >= argc) {
usage(argv[0]);
return 1;
}
2023-07-06 13:26:57 +02:00
rx::thread::initialize();
2023-06-23 02:28:14 +02:00
rx::vm::initialize();
2023-06-24 22:48:25 +02:00
runRpsxGpu();
2023-08-15 02:04:25 +02:00
if (enableAudio) {
orbis::g_context.audioOut = orbis::knew<orbis::AudioOut>();
}
2023-06-23 02:28:14 +02:00
// rx::vm::printHostStats();
2023-09-03 21:23:50 +02:00
auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 10);
2023-07-13 16:53:13 +02:00
pthread_setname_np(pthread_self(), "10.MAINTHREAD");
2023-06-23 02:28:14 +02:00
std::thread{[] {
pthread_setname_np(pthread_self(), "Bridge");
auto bridge = rx::bridge.header;
std::vector<std::uint64_t> fetchedCommands;
fetchedCommands.reserve(std::size(bridge->cacheCommands));
while (true) {
for (auto &command : bridge->cacheCommands) {
std::uint64_t value = command.load(std::memory_order::relaxed);
if (value != 0) {
fetchedCommands.push_back(value);
command.store(0, std::memory_order::relaxed);
}
}
if (fetchedCommands.empty()) {
continue;
}
for (auto command : fetchedCommands) {
auto page = static_cast<std::uint32_t>(command);
auto count = static_cast<std::uint32_t>(command >> 32) + 1;
auto pageFlags =
bridge->cachePages[page].load(std::memory_order::relaxed);
auto address =
static_cast<std::uint64_t>(page) * amdgpu::bridge::kHostPageSize;
auto origVmProt = rx::vm::getPageProtection(address);
int prot = 0;
if (origVmProt & rx::vm::kMapProtCpuRead) {
prot |= PROT_READ;
}
if (origVmProt & rx::vm::kMapProtCpuWrite) {
prot |= PROT_WRITE;
}
if (origVmProt & rx::vm::kMapProtCpuExec) {
prot |= PROT_EXEC;
}
if (pageFlags & amdgpu::bridge::kPageReadWriteLock) {
prot &= ~(PROT_READ | PROT_WRITE);
} else if (pageFlags & amdgpu::bridge::kPageWriteWatch) {
prot &= ~PROT_WRITE;
}
// std::fprintf(stderr, "protection %lx-%lx\n", address,
// address + amdgpu::bridge::kHostPageSize * count);
if (::mprotect(reinterpret_cast<void *>(address),
amdgpu::bridge::kHostPageSize * count, prot)) {
perror("protection failed");
std::abort();
}
}
fetchedCommands.clear();
}
}}.detach();
2023-06-23 02:28:14 +02:00
int status = 0;
initProcess->sysent = &orbis::ps4_sysvec;
initProcess->onSysEnter = onSysEnter;
initProcess->onSysExit = onSysExit;
initProcess->ops = &rx::procOpsTable;
auto [baseId, mainThread] = initProcess->threadsMap.emplace();
mainThread->tproc = initProcess;
mainThread->tid = initProcess->pid + baseId;
mainThread->state = orbis::ThreadState::RUNNING;
auto executableModule =
rx::linker::loadModuleFile(argv[argIndex], mainThread);
if (executableModule == nullptr) {
std::fprintf(stderr, "Failed to open '%s'\n", argv[argIndex]);
std::abort();
}
executableModule->id = initProcess->modulesMap.insert(executableModule);
initProcess->processParam = executableModule->processParam;
initProcess->processParamSize = executableModule->processParamSize;
2023-06-23 02:28:14 +02:00
if (executableModule->type == rx::linker::kElfTypeSceDynExec ||
executableModule->type == rx::linker::kElfTypeSceExec) {
status = ps4Exec(mainThread, std::move(executableModule),
2023-06-23 02:28:14 +02:00
std::span(argv + argIndex, argc - argIndex),
std::span<const char *>());
} else {
std::fprintf(stderr, "Unexpected executable type\n");
status = 1;
}
// rx::vm::printHostStats();
rx::vm::deinitialize();
2023-07-06 13:26:57 +02:00
rx::thread::deinitialize();
2023-06-23 02:28:14 +02:00
return status;
}