Merge pull request #1040 from Sonicadvance1/more_syscalls_5_12

Implements more syscalls for supporting a higher guest kernel version
This commit is contained in:
Ryan Houdek authored and GitHub committed 2021-06-01 00:27:50 -07:00
commit edd1dfdfe8
22 files changed
+568 -238

No files matched your search

@@ -175,16 +175,23 @@ bool Dispatcher::HandleGuestSignal(int Signal, void *info, void *ucontext, Guest
// siginfo_t
siginfo_t *HostSigInfo = reinterpret_cast<siginfo_t*>(info);
guest_siginfo->si_signo = Signal;
switch (Signal) {
case SIGSEGV:
case SIGBUS:
guest_siginfo->si_code = HostSigInfo->si_code;
guest_siginfo->si_errno = HostSigInfo->si_errno;
// Macro expansion to get the si_addr
guest_siginfo->si_addr = HostSigInfo->si_addr;
break;
default: LogMan::Msg::D("Unhandled siginfo_t signal: %d", Signal); break;
if (HostSigInfo->si_code == SI_USER) {
// If the signal was a user signal then we need to pass this struct through unaltered
// Guest might be doing something with it
*guest_siginfo = *HostSigInfo;
}
else {
guest_siginfo->si_signo = Signal;
switch (Signal) {
case SIGSEGV:
case SIGBUS:
guest_siginfo->si_code = HostSigInfo->si_code;
guest_siginfo->si_errno = HostSigInfo->si_errno;
// Macro expansion to get the si_addr
guest_siginfo->si_addr = HostSigInfo->si_addr;
break;
default: LogMan::Msg::D("Unhandled siginfo_t signal: %d", Signal); break;
}
}
Frame->State.gregs[X86State::REG_RSI] = SigInfoLocation;
@@ -107,7 +107,7 @@ namespace FEXCore::Core {
alignas(16) FEXCore::Core::CpuStateFrame BaseFrameState{};
};
static_assert(std::is_standard_layout<InternalThreadState>::value, "This needs to be standard layout");
// static_assert(std::is_standard_layout<InternalThreadState>::value, "This needs to be standard layout");
}
@@ -41,6 +41,7 @@ add_library(LinuxEmulation STATIC
Syscalls/FS.cpp
Syscalls/Info.cpp
Syscalls/IO.cpp
Syscalls/IOUring.cpp
Syscalls/Key.cpp
Syscalls/Memory.cpp
Syscalls/Msg.cpp
@@ -600,8 +600,12 @@ namespace FEX::EmulatedFile {
FDReadCreators["/proc/sys/kernel/osrelease"] = [&](FEXCore::Context::Context *ctx, int32_t fd, const char *pathname, int32_t flags, mode_t mode) -> int32_t {
FILE *fp = tmpfile();
const char kernel_version[] = "5.0.0\0";
fwrite(kernel_version, sizeof(uint8_t), strlen(kernel_version) + 1, fp);
uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion();
fprintf(fp, "%d.%d.%d\n",
FEX::HLE::SyscallHandler::KernelMajor(GuestVersion),
FEX::HLE::SyscallHandler::KernelMinor(GuestVersion),
FEX::HLE::SyscallHandler::KernelPatch(GuestVersion));
fputc('\0', fp);
fseek(fp, 0, SEEK_SET);
int32_t f = fileno(fp);
return f;
@@ -611,8 +615,13 @@ namespace FEX::EmulatedFile {
FILE *fp = tmpfile();
// UTS version NEEDS to be in a format that can pass to `date -d`
// Format of this is Linux version <Release> (<Compile By>@<Compile Host>) (<Linux Compiler>) #<version> {SMP, PREEMPT, PREEMPT_RT} <UTS version>\n"
const char kernel_version[] = "Linux version 5.0.0 (FEX@FEX) (clang) #" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__ "\n\0";
fwrite(kernel_version, sizeof(uint8_t), strlen(kernel_version) + 1, fp);
const char kernel_version[] = "Linux version %d.%d.%d (FEX@FEX) (clang) #" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__ "\n";
uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion();
fprintf(fp, kernel_version,
FEX::HLE::SyscallHandler::KernelMajor(GuestVersion),
FEX::HLE::SyscallHandler::KernelMinor(GuestVersion),
FEX::HLE::SyscallHandler::KernelPatch(GuestVersion));
fputc('\0', fp);
fseek(fp, 0, SEEK_SET);
int32_t f = fileno(fp);
return f;
@@ -6,6 +6,7 @@ $end_info$
*/
#include "Tests/LinuxSyscalls/FileManagement.h"
#include "Tests/LinuxSyscalls/Syscalls.h"
#include <FEXCore/Utils/LogManager.h>
#include <cstring>
@@ -184,6 +185,26 @@ uint64_t FileManager::Close(int fd) {
return ::close(fd);
}
uint64_t FileManager::CloseRange(unsigned int first, unsigned int last, unsigned int flags) {
#ifndef SYS_close_range
#define SYS_close_range 436
#endif
#ifndef CLOSE_RANGE_CLOEXEC
#define CLOSE_RANGE_CLOEXEC (1U << 2)
#endif
if (!(flags & CLOSE_RANGE_CLOEXEC)) {
// If the flag was set then it doesn't actually close the FDs
// Just sets the flag on a range
std::lock_guard<std::mutex> lk(FDLock);
for (unsigned int i = first; i <= last; ++i) {
// We remove from first to last inclusive
FDToNameMap.erase(i);
}
}
return ::syscall(SYS_close_range, first, last, flags);
}
uint64_t FileManager::Stat(const char *pathname, void *buf) {
auto NewPath = GetSelf(pathname);
const char *SelfPath = NewPath ? NewPath->c_str() : nullptr;
@@ -335,6 +356,36 @@ uint64_t FileManager::Openat([[maybe_unused]] int dirfs, const char *pathname, i
return fd;
}
uint64_t FileManager::Openat2(int dirfs, const char *pathname, FEX::HLE::open_how *how, size_t usize) {
#ifndef SYS_openat2
#define SYS_openat2 437
#endif
auto NewPath = GetSelf(pathname);
const char *SelfPath = NewPath ? NewPath->c_str() : nullptr;
int32_t fd = -1;
fd = EmuFD.OpenAt(dirfs, SelfPath, how->flags, how->mode);
if (fd == -1) {
auto Path = GetEmulatedPath(SelfPath, true);
if (!Path.empty()) {
fd = ::syscall(SYS_openat2, dirfs, Path.c_str(), how, usize);
}
if (fd == -1)
fd = ::syscall(SYS_openat2, dirfs, SelfPath, how, usize);
}
if (fd != -1) {
std::lock_guard<std::mutex> lk(FDLock);
FDToNameMap[fd] = SelfPath;
}
return fd;
}
uint64_t FileManager::Statx(int dirfd, const char *pathname, int flags, uint32_t mask, struct statx *statxbuf) {
auto NewPath = GetSelf(pathname);
const char *SelfPath = NewPath ? NewPath->c_str() : nullptr;
@@ -23,6 +23,8 @@ struct Context;
namespace FEX::HLE {
struct open_how;
class FileManager final {
public:
FileManager() = delete;
@@ -32,6 +34,7 @@ public:
~FileManager();
uint64_t Open(const char *pathname, int flags, uint32_t mode);
uint64_t Close(int fd);
uint64_t CloseRange(unsigned int first, unsigned int last, unsigned int flags);
uint64_t Stat(const char *pathname, void *buf);
uint64_t Lstat(const char *path, void *buf);
uint64_t Access(const char *pathname, int mode);
@@ -41,6 +44,7 @@ public:
uint64_t Chmod(const char *pathname, mode_t mode);
uint64_t Readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
uint64_t Openat(int dirfs, const char *pathname, int flags, uint32_t mode);
uint64_t Openat2(int dirfs, const char *pathname, FEX::HLE::open_how *how, size_t usize);
uint64_t Statx(int dirfd, const char *pathname, int flags, uint32_t mask, struct statx *statxbuf);
uint64_t Mknod(const char *pathname, mode_t mode, dev_t dev);
uint64_t NewFSStatAt(int dirfd, const char *pathname, struct stat *buf, int flag);
+148 -4
View File
@@ -10,11 +10,13 @@ $end_info$
#include "Common/MathUtils.h"
#include "Tests/LinuxSyscalls/Syscalls.h"
#include "Tests/LinuxSyscalls/Syscalls/Thread.h"
#include "Tests/LinuxSyscalls/x64/Syscalls.h"
#include "Tests/LinuxSyscalls/x32/Syscalls.h"
#include <FEXCore/Core/X86Enums.h>
#include <FEXCore/Core/CodeLoader.h>
#include <FEXCore/Debug/InternalThreadState.h>
#include <FEXCore/Utils/Allocator.h>
#include <FEXCore/Utils/ELFContainer.h>
#include <fcntl.h>
@@ -95,7 +97,7 @@ static bool IsSupportedByInterpreter(std::string const &Filename) {
return false;
}
uint64_t ExecveHandler(const char *pathname, std::vector<const char*> &argv, std::vector<const char*> &envp) {
uint64_t ExecveHandler(const char *pathname, std::vector<const char*> &argv, std::vector<const char*> &envp, ExecveAtArgs *Args) {
std::string Filename{};
std::error_code ec;
@@ -134,7 +136,12 @@ uint64_t ExecveHandler(const char *pathname, std::vector<const char*> &argv, std
uint64_t Result{};
if (FEX::HLE::_SyscallHandler->IsInterpreterInstalled()) {
// If the FEX interpreter is installed then just execve the thing
Result = execve(Filename.c_str(), const_cast<char *const *>(&argv.at(0)), const_cast<char *const *>(&envp.at(0)));
if (Args) {
Result = ::syscall(SYS_execveat, Args->dirfd, Filename.c_str(), const_cast<char *const *>(&argv.at(0)), const_cast<char *const *>(&envp.at(0)), Args->flags);
}
else {
Result = execve(Filename.c_str(), const_cast<char *const *>(&argv.at(0)), const_cast<char *const *>(&envp.at(0)));
}
SYSCALL_ERRNO();
}
@@ -153,7 +160,12 @@ uint64_t ExecveHandler(const char *pathname, std::vector<const char*> &argv, std
// We are trying to execute an ELF of a different architecture
// We can't know if we can support this without architecture specific checks and binfmt_misc parsing
// Just execve it and let the kernel handle the process
Result = execve(Filename.c_str(), const_cast<char *const *>(&argv.at(0)), const_cast<char *const *>(&envp.at(0)));
if (Args) {
Result = ::syscall(SYS_execveat, Args->dirfd, Filename.c_str(), const_cast<char *const *>(&argv.at(0)), const_cast<char *const *>(&envp.at(0)), Args->flags);
}
else {
Result = execve(Filename.c_str(), const_cast<char *const *>(&argv.at(0)), const_cast<char *const *>(&envp.at(0)));
}
SYSCALL_ERRNO();
}
@@ -172,11 +184,136 @@ uint64_t ExecveHandler(const char *pathname, std::vector<const char*> &argv, std
// Append the arguments together
ExecveArgs.insert(ExecveArgs.end(), argv.begin(), argv.end());
Result = execve("/proc/self/exe", const_cast<char *const *>(&ExecveArgs.at(0)), const_cast<char *const *>(&envp.at(0)));
if (Args) {
Result = ::syscall(SYS_execveat, Args->dirfd, "/proc/self/exe", const_cast<char *const *>(&ExecveArgs.at(0)), const_cast<char *const *>(&envp.at(0)), Args->flags);
}
else {
Result = execve("/proc/self/exe", const_cast<char *const *>(&ExecveArgs.at(0)), const_cast<char *const *>(&envp.at(0)));
}
SYSCALL_ERRNO();
}
static bool AnyFlagsSet(uint64_t Flags, uint64_t Mask) {
return (Flags & Mask) != 0;
}
static bool AllFlagsSet(uint64_t Flags, uint64_t Mask) {
return (Flags & Mask) == Mask;
}
uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args) {
uint64_t flags = args->flags;
#define FLAGPRINT(x, y) if (args->flags & (y)) LogMan::Msg::I("\tFlag: " #x)
FLAGPRINT(CSIGNAL, 0x000000FF);
FLAGPRINT(CLONE_VM, 0x00000100);
FLAGPRINT(CLONE_FS, 0x00000200);
FLAGPRINT(CLONE_FILES, 0x00000400);
FLAGPRINT(CLONE_SIGHAND, 0x00000800);
FLAGPRINT(CLONE_PTRACE, 0x00002000);
FLAGPRINT(CLONE_VFORK, 0x00004000);
FLAGPRINT(CLONE_PARENT, 0x00008000);
FLAGPRINT(CLONE_THREAD, 0x00010000);
FLAGPRINT(CLONE_NEWNS, 0x00020000);
FLAGPRINT(CLONE_SYSVSEM, 0x00040000);
FLAGPRINT(CLONE_SETTLS, 0x00080000);
FLAGPRINT(CLONE_PARENT_SETTID, 0x00100000);
FLAGPRINT(CLONE_CHILD_CLEARTID, 0x00200000);
FLAGPRINT(CLONE_DETACHED, 0x00400000);
FLAGPRINT(CLONE_UNTRACED, 0x00800000);
FLAGPRINT(CLONE_CHILD_SETTID, 0x01000000);
FLAGPRINT(CLONE_NEWCGROUP, 0x02000000);
FLAGPRINT(CLONE_NEWUTS, 0x04000000);
FLAGPRINT(CLONE_NEWIPC, 0x08000000);
FLAGPRINT(CLONE_NEWUSER, 0x10000000);
FLAGPRINT(CLONE_NEWPID, 0x20000000);
FLAGPRINT(CLONE_NEWNET, 0x40000000);
FLAGPRINT(CLONE_IO, 0x80000000);
auto Thread = Frame->Thread;
if (AnyFlagsSet(flags, CLONE_UNTRACED | CLONE_PTRACE)) {
LogMan::Msg::D("clone: Ptrace* not supported");
}
// Clone3 flags
#ifndef CLONE_CLEAR_SIGHAND
#define CLONE_CLEAR_SIGHAND 0x100000000ULL
#endif
#ifndef CLONE_INTO_CGROUP
#define CLONE_INTO_CGROUP 0x200000000ULL
#endif
if (AnyFlagsSet(flags, CLONE_CLEAR_SIGHAND)) {
LogMan::Msg::D("clone3: CLONE_CLEAR_SIGHAND unsupported");
}
if (AnyFlagsSet(flags, CLONE_INTO_CGROUP)) {
LogMan::Msg::D("clone3: CLONE_INTO_CGROUP unsupported");
return -EOPNOTSUPP;
}
if (args->set_tid_size > 0) {
LogMan::Msg::D("clone3: set_tid unsupported");
return -EPERM;
}
if (AnyFlagsSet(flags, CLONE_NEWNS | CLONE_NEWCGROUP | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET)) {
// NEWUSER doesn't need any privileges from 3.8 onward
// We just don't support it yet
LogMan::Msg::I("Unconditionally returning EPERM on clone namespace");
return -EPERM;
}
if (!(flags & CLONE_THREAD)) {
if (flags & CLONE_VFORK) {
flags &= ~CLONE_VFORK;
flags &= ~CLONE_VM;
LogMan::Msg::D("clone: WARNING: CLONE_VFORK w/o CLONE_THREAD");
}
if (AnyFlagsSet(flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM)) {
LogMan::Msg::I("clone: Unsuported flags w/o CLONE_THREAD (Shared Resources), %X", flags);
return -EPERM;
}
// CLONE_PARENT is ignored (Implied by CLONE_THREAD)
return FEX::HLE::ForkGuest(Thread, Frame, flags,
reinterpret_cast<void*>(args->stack),
reinterpret_cast<pid_t*>(args->parent_tid),
reinterpret_cast<pid_t*>(args->child_tid),
reinterpret_cast<void*>(args->tls));
} else {
if (!AllFlagsSet(flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) {
LogMan::Msg::I("clone: CLONE_THREAD: Unsuported flags w/ CLONE_THREAD (Shared Resources), %X", flags);
return -EPERM;
}
auto NewThread = FEX::HLE::CreateNewThread(Thread->CTX, Frame, args);
// Return the new threads TID
uint64_t Result = NewThread->ThreadManager.GetTID();
if (flags & CLONE_VFORK) {
NewThread->DestroyedByParent = true;
}
// Actually start the thread
FEXCore::Context::RunThread(Thread->CTX, NewThread);
if (flags & CLONE_VFORK) {
// If VFORK is set then the calling process is suspended until the thread exits with execve or exit
NewThread->ExecutionThread->join(nullptr);
// Normally a thread cleans itself up on exit. But because we need to join, we are now responsible
FEXCore::Context::DestroyThread(Thread->CTX, NewThread);
}
SYSCALL_ERRNO();
}
};
uint64_t SyscallHandler::HandleBRK(FEXCore::Core::CpuStateFrame *Frame, void *Addr) {
std::lock_guard<std::mutex> lk(MMapMutex);
@@ -253,6 +390,8 @@ SyscallHandler::SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalD
, SignalDelegation {_SignalDelegation} {
FEX::HLE::_SyscallHandler = this;
HostKernelVersion = CalculateHostKernelVersion();
GuestKernelVersion = CalculateGuestKernelVersion();
}
SyscallHandler::~SyscallHandler() {
@@ -278,6 +417,11 @@ uint32_t SyscallHandler::CalculateHostKernelVersion() {
return (Major << 24) | (Minor << 16) | Patch;
}
uint32_t SyscallHandler::CalculateGuestKernelVersion() {
// We currently only emulate a kernel between the ranges of Kernel 5.0.0 and 5.12.0
return std::max(KernelVersion(5, 0), std::min(KernelVersion(5, 12), GetHostKernelVersion()));
}
uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args) {
if (Args->Argument[0] >= Definitions.size()) {
return -ENOSYS;
+37 -2
View File
@@ -35,6 +35,7 @@ class SyscallHandler;
void RegisterFS();
void RegisterInfo();
void RegisterIO();
void RegisterIOUring(FEX::HLE::SyscallHandler *const Handler);
void RegisterKey();
void RegisterMemory();
void RegisterMsg();
@@ -42,7 +43,7 @@ class SyscallHandler;
void RegisterSched();
void RegisterSemaphore();
void RegisterSHM();
void RegisterSignals();
void RegisterSignals(FEX::HLE::SyscallHandler *const Handler);
void RegisterSocket();
void RegisterThread();
void RegisterTime();
@@ -53,7 +54,12 @@ class SyscallHandler;
uint64_t UnimplementedSyscall(FEXCore::Core::CpuStateFrame *Frame, uint64_t SyscallNumber);
uint64_t UnimplementedSyscallSafe(FEXCore::Core::CpuStateFrame *Frame, uint64_t SyscallNumber);
uint64_t ExecveHandler(const char *pathname, std::vector<const char*> &argv, std::vector<const char*> &envp);
struct ExecveAtArgs {
int dirfd;
int flags;
};
uint64_t ExecveHandler(const char *pathname, std::vector<const char*> &argv, std::vector<const char*> &envp, ExecveAtArgs *Args);
class SyscallHandler : public FEXCore::HLE::SyscallHandler {
public:
@@ -114,12 +120,19 @@ public:
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
uint32_t GetHostKernelVersion() const { return HostKernelVersion; }
uint32_t GetGuestKernelVersion() const { return GuestKernelVersion; }
static uint32_t CalculateHostKernelVersion();
uint32_t CalculateGuestKernelVersion();
static uint32_t KernelVersion(uint32_t Major, uint32_t Minor = 0, uint32_t Patch = 0) {
return (Major << 24) | (Minor << 16) | Patch;
}
static uint32_t KernelMajor(uint32_t Version) { return Version >> 24; }
static uint32_t KernelMinor(uint32_t Version) { return (Version >> 16) & 0xFF; }
static uint32_t KernelPatch(uint32_t Version) { return Version & 0xFFFF; }
protected:
std::vector<SyscallFunctionDefinition> Definitions{};
std::mutex MMapMutex;
@@ -132,6 +145,7 @@ protected:
// (Major << 24) | (Minor << 16) | Patch
uint32_t HostKernelVersion{};
uint32_t GuestKernelVersion{};
private:
@@ -247,6 +261,27 @@ struct __attribute__((packed)) epoll_event_x86 {
static_assert(std::is_trivial<epoll_event_x86>::value, "Needs to be trivial");
static_assert(sizeof(epoll_event_x86) == 12, "Incorrect size");
struct open_how {
uint64_t flags;
uint64_t mode;
uint64_t resolve;
};
struct clone3_args {
uint64_t flags;
uint64_t pidfd;
uint64_t child_tid;
uint64_t parent_tid;
uint64_t exit_signal;
uint64_t stack;
uint64_t stack_size;
uint64_t tls;
uint64_t set_tid;
uint64_t set_tid_size;
uint64_t cgroup;
};
uint64_t CloneHandler(FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args);
inline static int RemapFromX86Flags(int flags) {
#ifdef _M_X86_64
// Nothing to change here
@@ -220,10 +220,21 @@ namespace FEX::HLE {
uint64_t Result = ::syscall(SYS_pidfd_getfd, pidfd, fd, flags);
SYSCALL_ERRNO();
});
REGISTER_SYSCALL_IMPL(openat2, [](FEXCore::Core::CpuStateFrame *Frame, int dirfs, const char *pathname, struct open_how *how, size_t usize) -> uint64_t {
open_how HostHow{};
size_t HostSize = std::min(sizeof(open_how), usize);
memcpy(&HostHow, how, HostSize);
HostHow.flags = FEX::HLE::RemapFromX86Flags(HostHow.flags);
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Openat2(dirfs, pathname, &HostHow, HostSize);
SYSCALL_ERRNO();
});
}
else {
REGISTER_SYSCALL_IMPL(faccessat2, UnimplementedSyscallSafe);
REGISTER_SYSCALL_IMPL(pidfd_getfd, UnimplementedSyscallSafe);
REGISTER_SYSCALL_IMPL(openat2, UnimplementedSyscallSafe);
}
REGISTER_SYSCALL_IMPL(splice, [](FEXCore::Core::CpuStateFrame *Frame, int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) -> uint64_t {
@@ -319,5 +330,25 @@ namespace FEX::HLE {
uint64_t Result = ::copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
SYSCALL_ERRNO();
});
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 3, 0)) {
REGISTER_SYSCALL_IMPL(pidfd_open, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, unsigned int flags) -> uint64_t {
uint64_t Result = ::syscall(SYS_pidfd_open, pid, flags);
SYSCALL_ERRNO();
});
}
else {
REGISTER_SYSCALL_IMPL(pidfd_open, UnimplementedSyscallSafe);
}
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 9, 0)) {
REGISTER_SYSCALL_IMPL(close_range, [](FEXCore::Core::CpuStateFrame *Frame, unsigned int first, unsigned int last, unsigned int flags) -> uint64_t {
uint64_t Result = FEX::HLE::_SyscallHandler->FM.CloseRange(first, last, flags);
SYSCALL_ERRNO();
});
}
else {
REGISTER_SYSCALL_IMPL(close_range, UnimplementedSyscallSafe);
}
}
}
@@ -0,0 +1,45 @@
/*
$info$
tags: LinuxSyscalls|syscalls-shared
$end_info$
*/
#include "Tests/LinuxSyscalls/Syscalls.h"
#include "Tests/LinuxSyscalls/Syscalls/Thread.h"
#include "Tests/LinuxSyscalls/x64/Syscalls.h"
#include "Tests/LinuxSyscalls/x32/Syscalls.h"
#include <signal.h>
#include <sys/syscall.h>
#include <unistd.h>
namespace SignalDelegator {
struct GuestSigAction;
}
namespace FEX::HLE {
void RegisterIOUring(FEX::HLE::SyscallHandler *const Handler) {
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 1, 0)) {
REGISTER_SYSCALL_IMPL(io_uring_setup, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t entries, void* params) -> uint64_t {
uint64_t Result = ::syscall(SYS_io_uring_setup, entries, params);
SYSCALL_ERRNO();
});
REGISTER_SYSCALL_IMPL(io_uring_enter, [](FEXCore::Core::CpuStateFrame *Frame, unsigned int fd, uint32_t to_submit, uint32_t min_complete, uint32_t flags, void *argp, size_t argsz) -> uint64_t {
uint64_t Result = ::syscall(SYS_io_uring_enter, fd, to_submit, min_complete, flags, argp, argsz);
SYSCALL_ERRNO();
});
REGISTER_SYSCALL_IMPL(io_uring_register, [](FEXCore::Core::CpuStateFrame *Frame, unsigned int fd, unsigned int opcode, void *arg, uint32_t nr_args) -> uint64_t {
uint64_t Result = ::syscall(SYS_io_uring_register, fd, opcode, arg, nr_args);
SYSCALL_ERRNO();
});
}
else {
REGISTER_SYSCALL_IMPL(io_uring_setup, UnimplementedSyscallSafe);
REGISTER_SYSCALL_IMPL(io_uring_enter, UnimplementedSyscallSafe);
REGISTER_SYSCALL_IMPL(io_uring_register, UnimplementedSyscallSafe);
}
}
}
+6 -1
View File
@@ -42,7 +42,12 @@ namespace FEX::HLE {
LogMan::Msg::E("Couldn't determine host nodename. Defaulting to '%s'", buf->nodename);
}
strcpy(buf->sysname, "Linux");
strcpy(buf->release, "5.0.0");
uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion();
snprintf(buf->release, sizeof(buf->release), "%d.%d.%d",
FEX::HLE::SyscallHandler::KernelMajor(GuestVersion),
FEX::HLE::SyscallHandler::KernelMinor(GuestVersion),
FEX::HLE::SyscallHandler::KernelPatch(GuestVersion));
const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__;
strcpy(buf->version, version);
static_assert(sizeof(version) <= sizeof(buf->version), "uname version define became too large!");
@@ -21,7 +21,7 @@ namespace SignalDelegator {
}
namespace FEX::HLE {
void RegisterSignals() {
void RegisterSignals(FEX::HLE::SyscallHandler *const Handler) {
REGISTER_SYSCALL_IMPL(rt_sigprocmask, [](FEXCore::Core::CpuStateFrame *Frame, int how, const uint64_t *set, uint64_t *oldset) -> uint64_t {
return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(how, set, oldset);
});
@@ -41,5 +41,15 @@ namespace FEX::HLE {
uint64_t Result = ::syscall(SYS_userfaultfd, flags);
SYSCALL_ERRNO();
});
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 1, 0)) {
REGISTER_SYSCALL_IMPL(pidfd_send_signal, [](FEXCore::Core::CpuStateFrame *Frame, int pidfd, int sig, siginfo_t *info, unsigned int flags) -> uint64_t {
uint64_t Result = ::syscall(SYS_pidfd_send_signal);
SYSCALL_ERRNO();
});
}
else {
REGISTER_SYSCALL_IMPL(pidfd_send_signal, UnimplementedSyscallSafe);
}
}
}
@@ -64,11 +64,6 @@ namespace FEX::HLE {
SYSCALL_STUB(rt_tgsigqueueinfo);
});
// execute program relative to a directory file descriptor
REGISTER_SYSCALL_IMPL(execveat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, char *const argv[], char *const envp[], int flags) -> uint64_t {
SYSCALL_STUB(execveat);
});
REGISTER_SYSCALL_IMPL(rseq, [](FEXCore::Core::CpuStateFrame *Frame, struct rseq *rseq, uint32_t rseq_len, int flags, uint32_t sig) -> uint64_t {
SYSCALL_STUB(rseq);
});
+28 -9
View File
@@ -33,7 +33,8 @@ $end_info$
ARG_TO_STR(idtype_t, "%u")
namespace FEX::HLE {
FEXCore::Core::InternalThreadState *CreateNewThread(FEXCore::Context:: Context *CTX, FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls) {
FEXCore::Core::InternalThreadState *CreateNewThread(FEXCore::Context:: Context *CTX, FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args) {
uint64_t flags = args->flags;
FEXCore::Core::CPUState NewThreadState{};
// Clone copies the parent thread's state
memcpy(&NewThreadState, Frame, sizeof(FEXCore::Core::CPUState));
@@ -41,21 +42,21 @@ namespace FEX::HLE {
NewThreadState.gregs[FEXCore::X86State::REG_RAX] = 0;
NewThreadState.gregs[FEXCore::X86State::REG_RBX] = 0;
NewThreadState.gregs[FEXCore::X86State::REG_RBP] = 0;
NewThreadState.gregs[FEXCore::X86State::REG_RSP] = reinterpret_cast<uint64_t>(stack);
NewThreadState.gregs[FEXCore::X86State::REG_RSP] = args->stack;
auto NewThread = FEXCore::Context::CreateThread(CTX, &NewThreadState, reinterpret_cast<uint64_t>(parent_tid));
auto NewThread = FEXCore::Context::CreateThread(CTX, &NewThreadState, args->parent_tid);
FEXCore::Context::InitializeThread(CTX, NewThread);
if (FEX::HLE::_SyscallHandler->Is64BitMode()) {
if (flags & CLONE_SETTLS) {
x64::SetThreadArea(NewThread->CurrentFrame, tls);
x64::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast<void*>(args->tls));
}
// Set us to start just after the syscall instruction
x64::AdjustRipForNewThread(NewThread->CurrentFrame);
}
else {
if (flags & CLONE_SETTLS) {
x32::SetThreadArea(NewThread->CurrentFrame, tls);
x32::SetThreadArea(NewThread->CurrentFrame, reinterpret_cast<void*>(args->tls));
}
x32::AdjustRipForNewThread(NewThread->CurrentFrame);
}
@@ -65,20 +66,32 @@ namespace FEX::HLE {
// Sets the child TID to pointer in ParentTID
if (flags & CLONE_PARENT_SETTID) {
*parent_tid = Result;
*reinterpret_cast<pid_t*>(args->parent_tid) = Result;
}
// Sets the child TID to the pointer in ChildTID
if (flags & CLONE_CHILD_SETTID) {
NewThread->ThreadManager.set_child_tid = child_tid;
*child_tid = Result;
NewThread->ThreadManager.set_child_tid = reinterpret_cast<int32_t*>(args->child_tid);
*reinterpret_cast<pid_t*>(args->child_tid) = Result;
}
// When the thread exits, clear the child thread ID at ChildTID
// Additionally wakeup a futex at that address
// Address /may/ be changed with SET_TID_ADDRESS syscall
if (flags & CLONE_CHILD_CLEARTID) {
NewThread->ThreadManager.clear_child_tid = child_tid;
NewThread->ThreadManager.clear_child_tid = reinterpret_cast<int32_t*>(args->child_tid);
}
// clone3 flag
if (flags & CLONE_PIDFD) {
// Use pidfd_open to emulate this flag
int pidfd = ::syscall(SYS_pidfd_open, Result, 0);
if (Result == ~0ULL) {
LogMan::Msg::E("Couldn't get pidfd of TID %d\n", Result);
}
else {
*reinterpret_cast<int*>(args->pidfd) = pidfd;
}
}
return NewThread;
@@ -162,6 +175,12 @@ namespace FEX::HLE {
return ForkGuest(Frame->Thread, Frame, 0, 0, 0, 0, 0);
});
REGISTER_SYSCALL_IMPL(clone3, ([](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *cl_args, size_t size) -> uint64_t {
FEX::HLE::clone3_args args{};
memcpy(&args, cl_args, std::min(sizeof(FEX::HLE::clone3_args), size));
return CloneHandler(Frame, &args);
}));
REGISTER_SYSCALL_IMPL(exit, [](FEXCore::Core::CpuStateFrame *Frame, int status) -> uint64_t {
auto Thread = Frame->Thread;
if (Thread->ThreadManager.clear_child_tid) {
+1 -1
View File
@@ -14,6 +14,6 @@ struct CPUState;
}
namespace FEX::HLE {
FEXCore::Core::InternalThreadState *CreateNewThread(FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls);
FEXCore::Core::InternalThreadState *CreateNewThread(FEXCore::Context::Context *CTX, FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::clone3_args *args);
uint64_t ForkGuest(FEXCore::Core::InternalThreadState *Thread, FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls);
}
+38 -1
View File
@@ -21,7 +21,7 @@ $end_info$
ARG_TO_STR(FEX::HLE::x32::compat_ptr<FEX::HLE::epoll_event_x86>, "%lx")
namespace FEX::HLE::x32 {
void RegisterEpoll() {
void RegisterEpoll(FEX::HLE::SyscallHandler *const Handler) {
REGISTER_SYSCALL_IMPL_X32(epoll_wait, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, compat_ptr<epoll_event_x86> events, int maxevents, int timeout) -> uint64_t {
std::vector<struct epoll_event> Events;
Events.resize(maxevents);
@@ -64,5 +64,42 @@ namespace FEX::HLE::x32 {
SYSCALL_ERRNO();
});
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 11, 0)) {
#ifndef SYS_epoll_pwait2
#define SYS_epoll_pwait2 354
#endif
REGISTER_SYSCALL_IMPL_X32(epoll_pwait2, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, compat_ptr<epoll_event_x86> events, int maxevent, compat_ptr<timespec32> timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t {
std::vector<struct epoll_event> Events;
Events.resize(maxevent);
struct timespec tp64{};
struct timespec *timed_ptr{};
if (timeout) {
tp64 = *timeout;
timed_ptr = &tp64;
}
uint64_t Result = ::syscall(SYS_epoll_pwait2,
epfd,
&Events.at(0),
maxevent,
timed_ptr,
sigmask,
sigsetsize);
if (Result != -1) {
for (size_t i = 0; i < Result; ++i) {
events[i] = Events[i];
}
}
SYSCALL_ERRNO();
});
}
else {
REGISTER_SYSCALL_IMPL_X32(epoll_pwait2, UnimplementedSyscallSafe);
}
}
}
+4 -3
View File
@@ -580,7 +580,7 @@ public:
}
};
void RegisterEpoll();
void RegisterEpoll(FEX::HLE::SyscallHandler *const Handler);
void RegisterFD();
void RegisterFS();
void RegisterInfo();
@@ -662,13 +662,14 @@ public:
FEX::HLE::RegisterFS();
FEX::HLE::RegisterInfo();
FEX::HLE::RegisterIO();
FEX::HLE::RegisterIOUring(this);
FEX::HLE::RegisterKey();
FEX::HLE::RegisterMemory();
FEX::HLE::RegisterMsg();
FEX::HLE::RegisterSched();
FEX::HLE::RegisterSemaphore();
FEX::HLE::RegisterSHM();
FEX::HLE::RegisterSignals();
FEX::HLE::RegisterSignals(this);
FEX::HLE::RegisterSocket();
FEX::HLE::RegisterThread();
FEX::HLE::RegisterTime();
@@ -677,7 +678,7 @@ public:
FEX::HLE::RegisterStubs();
// 32bit specific
FEX::HLE::x32::RegisterEpoll();
FEX::HLE::x32::RegisterEpoll(this);
FEX::HLE::x32::RegisterFD();
FEX::HLE::x32::RegisterFS();
FEX::HLE::x32::RegisterInfo();
+40 -93
View File
@@ -43,99 +43,23 @@ namespace FEX::HLE::x32 {
Frame->State.rip += 2;
}
static bool AnyFlagsSet(uint64_t Flags, uint64_t Mask) {
return (Flags & Mask) != 0;
}
static bool AllFlagsSet(uint64_t Flags, uint64_t Mask) {
return (Flags & Mask) == Mask;
}
void RegisterThread() {
REGISTER_SYSCALL_IMPL_X32(clone, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, void *tls, pid_t *child_tid) -> uint64_t {
#define FLAGPRINT(x, y) if (flags & (y)) LogMan::Msg::I("\tFlag: " #x)
FLAGPRINT(CSIGNAL, 0x000000FF);
FLAGPRINT(CLONE_VM, 0x00000100);
FLAGPRINT(CLONE_FS, 0x00000200);
FLAGPRINT(CLONE_FILES, 0x00000400);
FLAGPRINT(CLONE_SIGHAND, 0x00000800);
FLAGPRINT(CLONE_PTRACE, 0x00002000);
FLAGPRINT(CLONE_VFORK, 0x00004000);
FLAGPRINT(CLONE_PARENT, 0x00008000);
FLAGPRINT(CLONE_THREAD, 0x00010000);
FLAGPRINT(CLONE_NEWNS, 0x00020000);
FLAGPRINT(CLONE_SYSVSEM, 0x00040000);
FLAGPRINT(CLONE_SETTLS, 0x00080000);
FLAGPRINT(CLONE_PARENT_SETTID, 0x00100000);
FLAGPRINT(CLONE_CHILD_CLEARTID, 0x00200000);
FLAGPRINT(CLONE_DETACHED, 0x00400000);
FLAGPRINT(CLONE_UNTRACED, 0x00800000);
FLAGPRINT(CLONE_CHILD_SETTID, 0x01000000);
FLAGPRINT(CLONE_NEWCGROUP, 0x02000000);
FLAGPRINT(CLONE_NEWUTS, 0x04000000);
FLAGPRINT(CLONE_NEWIPC, 0x08000000);
FLAGPRINT(CLONE_NEWUSER, 0x10000000);
FLAGPRINT(CLONE_NEWPID, 0x20000000);
FLAGPRINT(CLONE_NEWNET, 0x40000000);
FLAGPRINT(CLONE_IO, 0x80000000);
auto Thread = Frame->Thread;
if (AnyFlagsSet(flags, CLONE_UNTRACED | CLONE_PTRACE)) {
LogMan::Msg::D("clone: Ptrace* not supported");
}
if (AnyFlagsSet(flags, CLONE_NEWNS | CLONE_NEWCGROUP | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET)) {
// NEWUSER doesn't need any privileges from 3.8 onward
// We just don't support it yet
LogMan::Msg::I("Unconditionally returning EPERM on clone namespace");
return -EPERM;
}
if (!(flags & CLONE_THREAD)) {
if (flags & CLONE_VFORK) {
flags &= ~CLONE_VFORK;
flags &= ~CLONE_VM;
LogMan::Msg::D("clone: WARNING: CLONE_VFORK w/o CLONE_THREAD");
}
if (AnyFlagsSet(flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM)) {
LogMan::Msg::I("clone: Unsuported flags w/o CLONE_THREAD (Shared Resources), %X", flags);
return -EPERM;
}
// CLONE_PARENT is ignored (Implied by CLONE_THREAD)
return FEX::HLE::ForkGuest(Thread, Frame, flags, stack, parent_tid, child_tid, tls);
} else {
if (!AllFlagsSet(flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) {
LogMan::Msg::I("clone: CLONE_THREAD: Unsuported flags w/ CLONE_THREAD (Shared Resources), %X", flags);
return -EPERM;
}
auto NewThread = FEX::HLE::CreateNewThread(Thread->CTX, Frame, flags, stack, parent_tid, child_tid, tls);
// Return the new threads TID
uint64_t Result = NewThread->ThreadManager.GetTID();
if (flags & CLONE_VFORK) {
NewThread->DestroyedByParent = true;
}
// Actually start the thread
FEXCore::Context::RunThread(Thread->CTX, NewThread);
if (flags & CLONE_VFORK) {
// If VFORK is set then the calling process is suspended until the thread exits with execve or exit
NewThread->ExecutionThread->join(nullptr);
// Normally a thread cleans itself up on exit. But because we need to join, we are now responsible
FEXCore::Context::DestroyThread(Thread->CTX, NewThread);
}
SYSCALL_ERRNO();
}
});
REGISTER_SYSCALL_IMPL_X32(clone, ([](FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, void *tls, pid_t *child_tid) -> uint64_t {
FEX::HLE::clone3_args args {
.flags = flags & ~CSIGNAL, // This no longer contains CSIGNAL
.pidfd = reinterpret_cast<uint64_t>(parent_tid), // For clone, pidfd is duplicated here
.child_tid = reinterpret_cast<uint64_t>(child_tid),
.parent_tid = reinterpret_cast<uint64_t>(parent_tid),
.exit_signal = flags & CSIGNAL,
.stack = reinterpret_cast<uint64_t>(stack),
.stack_size = ~0ULL, // This syscall isn't able to see the stack size
.tls = reinterpret_cast<uint64_t>(tls),
.set_tid = 0, // This syscall isn't able to select TIDs
.set_tid_size = 0,
.cgroup = 0, // This syscall can't select cgroups
};
return CloneHandler(Frame, &args);
}));
REGISTER_SYSCALL_IMPL_X32(waitpid, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int32_t *status, int32_t options) -> uint64_t {
uint64_t Result = ::waitpid(pid, status, options);
@@ -294,9 +218,32 @@ namespace FEX::HLE::x32 {
}
Envp.push_back(nullptr);
return FEX::HLE::ExecveHandler(pathname, Args, Envp);
return FEX::HLE::ExecveHandler(pathname, Args, Envp, nullptr);
});
REGISTER_SYSCALL_IMPL_X32(execveat, ([](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, uint32_t *argv, uint32_t *envp, int flags) -> uint64_t {
std::vector<const char*> Args;
std::vector<const char*> Envp;
for (int i = 0; argv[i]; i++) {
Args.push_back(reinterpret_cast<const char*>(static_cast<uintptr_t>(argv[i])));
}
Args.push_back(nullptr);
for (int i = 0; envp[i]; i++) {
Envp.push_back(reinterpret_cast<const char*>(static_cast<uintptr_t>(envp[i])));
}
Envp.push_back(nullptr);
FEX::HLE::ExecveAtArgs AtArgs {
.dirfd = dirfd,
.flags = flags,
};
return FEX::HLE::ExecveHandler(pathname, Args, Envp, &AtArgs);
}));
REGISTER_SYSCALL_IMPL_X32(wait4, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int *wstatus, int options, struct rusage_32 *rusage) -> uint64_t {
struct rusage usage64{};
struct rusage *usage64_p{};
+30 -1
View File
@@ -19,7 +19,7 @@ $end_info$
#include <unistd.h>
namespace FEX::HLE::x64 {
void RegisterEpoll() {
void RegisterEpoll(FEX::HLE::SyscallHandler *const Handler) {
REGISTER_SYSCALL_IMPL_X64(epoll_wait, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, epoll_event_x86 *events, int maxevents, int timeout) -> uint64_t {
std::vector<struct epoll_event> Events;
Events.resize(maxevents);
@@ -67,5 +67,34 @@ namespace FEX::HLE::x64 {
SYSCALL_ERRNO();
});
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 11, 0)) {
#ifndef SYS_epoll_pwait2
#define SYS_epoll_pwait2 354
#endif
REGISTER_SYSCALL_IMPL_X64(epoll_pwait2, [](FEXCore::Core::CpuStateFrame *Frame, int epfd, epoll_event_x86 *events, int maxevent, timespec *timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t {
std::vector<struct epoll_event> Events;
Events.resize(maxevent);
uint64_t Result = ::syscall(SYS_epoll_pwait2,
epfd,
&Events.at(0),
maxevent,
timeout,
sigmask,
sigsetsize);
if (Result != -1) {
for (size_t i = 0; i < Result; ++i) {
events[i] = Events[i];
}
}
SYSCALL_ERRNO();
});
}
else {
REGISTER_SYSCALL_IMPL_X64(epoll_pwait2, UnimplementedSyscallSafe);
}
}
}
+14 -1
View File
@@ -27,7 +27,7 @@ static std::string get_fdpath(int fd)
}
namespace FEX::HLE::x64 {
void RegisterMemory() {
void RegisterMemory(FEX::HLE::SyscallHandler *const Handler) {
REGISTER_SYSCALL_IMPL_X64(munmap, [](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t length) -> uint64_t {
uint64_t Result = FEXCore::Allocator::munmap(addr, length);
@@ -106,5 +106,18 @@ namespace FEX::HLE::x64 {
uint64_t Result = reinterpret_cast<uint64_t>(shmat(shmid, shmaddr, shmflg));
SYSCALL_ERRNO();
});
#ifndef SYS_process_madvise
#define SYS_process_madvise 440
#endif
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 10, 0)) {
REGISTER_SYSCALL_IMPL_X64(process_madvise, [](FEXCore::Core::CpuStateFrame *Frame, int pidfd, const struct iovec *iovec, size_t vlen, int advice, unsigned int flags) -> uint64_t {
uint64_t Result = ::syscall(SYS_process_madvise, pidfd, iovec, vlen, advice, flags);
SYSCALL_ERRNO();
});
}
else {
REGISTER_SYSCALL_IMPL_X64(process_madvise, UnimplementedSyscallSafe);
}
}
}
+6 -5
View File
@@ -13,12 +13,12 @@ $end_info$
#include <map>
namespace FEX::HLE::x64 {
void RegisterEpoll();
void RegisterEpoll(FEX::HLE::SyscallHandler *const Handler);
void RegisterFD();
void RegisterInfo();
void RegisterIO();
void RegisterIoctl();
void RegisterMemory();
void RegisterMemory(FEX::HLE::SyscallHandler *const Handler);
void RegisterMsg();
void RegisterSched();
void RegisterSocket();
@@ -103,13 +103,14 @@ namespace FEX::HLE::x64 {
FEX::HLE::RegisterFS();
FEX::HLE::RegisterInfo();
FEX::HLE::RegisterIO();
FEX::HLE::RegisterIOUring(this);
FEX::HLE::RegisterKey();
FEX::HLE::RegisterMemory();
FEX::HLE::RegisterMsg();
FEX::HLE::RegisterSched();
FEX::HLE::RegisterSemaphore();
FEX::HLE::RegisterSHM();
FEX::HLE::RegisterSignals();
FEX::HLE::RegisterSignals(this);
FEX::HLE::RegisterSocket();
FEX::HLE::RegisterThread();
FEX::HLE::RegisterTime();
@@ -118,12 +119,12 @@ namespace FEX::HLE::x64 {
FEX::HLE::RegisterStubs();
// 64bit specific
FEX::HLE::x64::RegisterEpoll();
FEX::HLE::x64::RegisterEpoll(this);
FEX::HLE::x64::RegisterFD();
FEX::HLE::x64::RegisterInfo();
FEX::HLE::x64::RegisterIO();
FEX::HLE::x64::RegisterIoctl();
FEX::HLE::x64::RegisterMemory();
FEX::HLE::x64::RegisterMemory(this);
FEX::HLE::x64::RegisterMsg();
FEX::HLE::x64::RegisterSched();
FEX::HLE::x64::RegisterSocket();
+42 -96
View File
@@ -32,15 +32,24 @@ namespace FEX::HLE::x64 {
Frame->State.rip += 2;
}
static bool AnyFlagsSet(uint64_t Flags, uint64_t Mask) {
return (Flags & Mask) != 0;
}
static bool AllFlagsSet(uint64_t Flags, uint64_t Mask) {
return (Flags & Mask) == Mask;
}
void RegisterThread() {
REGISTER_SYSCALL_IMPL_X64(clone, ([](FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls) -> uint64_t {
FEX::HLE::clone3_args args {
.flags = flags & ~CSIGNAL, // This no longer contains CSIGNAL
.pidfd = reinterpret_cast<uint64_t>(parent_tid), // For clone, pidfd is duplicated here
.child_tid = reinterpret_cast<uint64_t>(child_tid),
.parent_tid = reinterpret_cast<uint64_t>(parent_tid),
.exit_signal = flags & CSIGNAL,
.stack = reinterpret_cast<uint64_t>(stack),
.stack_size = ~0ULL, // This syscall isn't able to see the stack size
.tls = reinterpret_cast<uint64_t>(tls),
.set_tid = 0, // This syscall isn't able to select TIDs
.set_tid_size = 0,
.cgroup = 0, // This syscall can't select cgroups
};
return CloneHandler(Frame, &args);
}));
REGISTER_SYSCALL_IMPL_X64(futex, [](FEXCore::Core::CpuStateFrame *Frame, int *uaddr, int futex_op, int val, const struct timespec *timeout, int *uaddr2, uint32_t val3) -> uint64_t {
uint64_t Result = syscall(SYS_futex,
uaddr,
@@ -52,93 +61,6 @@ namespace FEX::HLE::x64 {
SYSCALL_ERRNO();
});
REGISTER_SYSCALL_IMPL_X64(clone, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t flags, void *stack, pid_t *parent_tid, pid_t *child_tid, void *tls) -> uint64_t {
#define FLAGPRINT(x, y) if (flags & (y)) LogMan::Msg::I("\tFlag: " #x)
FLAGPRINT(CSIGNAL, 0x000000FF);
FLAGPRINT(CLONE_VM, 0x00000100);
FLAGPRINT(CLONE_FS, 0x00000200);
FLAGPRINT(CLONE_FILES, 0x00000400);
FLAGPRINT(CLONE_SIGHAND, 0x00000800);
FLAGPRINT(CLONE_PTRACE, 0x00002000);
FLAGPRINT(CLONE_VFORK, 0x00004000);
FLAGPRINT(CLONE_PARENT, 0x00008000);
FLAGPRINT(CLONE_THREAD, 0x00010000);
FLAGPRINT(CLONE_NEWNS, 0x00020000);
FLAGPRINT(CLONE_SYSVSEM, 0x00040000);
FLAGPRINT(CLONE_SETTLS, 0x00080000);
FLAGPRINT(CLONE_PARENT_SETTID, 0x00100000);
FLAGPRINT(CLONE_CHILD_CLEARTID, 0x00200000);
FLAGPRINT(CLONE_DETACHED, 0x00400000);
FLAGPRINT(CLONE_UNTRACED, 0x00800000);
FLAGPRINT(CLONE_CHILD_SETTID, 0x01000000);
FLAGPRINT(CLONE_NEWCGROUP, 0x02000000);
FLAGPRINT(CLONE_NEWUTS, 0x04000000);
FLAGPRINT(CLONE_NEWIPC, 0x08000000);
FLAGPRINT(CLONE_NEWUSER, 0x10000000);
FLAGPRINT(CLONE_NEWPID, 0x20000000);
FLAGPRINT(CLONE_NEWNET, 0x40000000);
FLAGPRINT(CLONE_IO, 0x80000000);
auto Thread = Frame->Thread;
if (AnyFlagsSet(flags, CLONE_UNTRACED | CLONE_PTRACE)) {
LogMan::Msg::D("clone: Ptrace* not supported");
}
if (AnyFlagsSet(flags, CLONE_NEWNS | CLONE_NEWCGROUP | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET)) {
// NEWUSER doesn't need any privileges from 3.8 onward
// We just don't support it yet
LogMan::Msg::I("Unconditionally returning EPERM on clone namespace");
return -EPERM;
}
if (!(flags & CLONE_THREAD)) {
if (flags & CLONE_VFORK) {
flags &= ~CLONE_VFORK;
flags &= ~CLONE_VM;
LogMan::Msg::D("clone: WARNING: CLONE_VFORK w/o CLONE_THREAD");
}
if (AnyFlagsSet(flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM)) {
LogMan::Msg::I("clone: Unsuported flags w/o CLONE_THREAD (Shared Resources), %X", flags);
return -EPERM;
}
// CLONE_PARENT is ignored (Implied by CLONE_THREAD)
return FEX::HLE::ForkGuest(Thread, Frame, flags, stack, parent_tid, child_tid, tls);
} else {
if (!AllFlagsSet(flags, CLONE_SYSVSEM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)) {
LogMan::Msg::I("clone: CLONE_THREAD: Unsuported flags w/ CLONE_THREAD (Shared Resources), %X", flags);
return -EPERM;
}
auto NewThread = FEX::HLE::CreateNewThread(Thread->CTX, Frame, flags, stack, parent_tid, child_tid, tls);
// Return the new threads TID
uint64_t Result = NewThread->ThreadManager.GetTID();
LogMan::Msg::D("Child [%d] starting at: 0x%lx. Parent was at 0x%lx", Result, NewThread->CurrentFrame->State.rip, Thread->CurrentFrame->State.rip);
if (flags & CLONE_VFORK) {
NewThread->DestroyedByParent = true;
}
// Actually start the thread
FEXCore::Context::RunThread(Thread->CTX, NewThread);
if (flags & CLONE_VFORK) {
// If VFORK is set then the calling process is suspended until the thread exits with execve or exit
NewThread->ExecutionThread->join(nullptr);
// Normally a thread cleans itself up on exit. But because we need to join, we are now responsible
FEXCore::Context::DestroyThread(Thread->CTX, NewThread);
}
SYSCALL_ERRNO();
}
});
REGISTER_SYSCALL_IMPL_X64(set_robust_list, [](FEXCore::Core::CpuStateFrame *Frame, struct robust_list_head *head, size_t len) -> uint64_t {
auto Thread = Frame->Thread;
Thread->ThreadManager.robust_list_head = reinterpret_cast<uint64_t>(head);
@@ -173,9 +95,33 @@ namespace FEX::HLE::x64 {
Envp.push_back(nullptr);
return FEX::HLE::ExecveHandler(pathname, Args, Envp);
return FEX::HLE::ExecveHandler(pathname, Args, Envp, nullptr);
});
REGISTER_SYSCALL_IMPL_X64(execveat, ([](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, char *const argv[], char *const envp[], int flags) -> uint64_t {
std::vector<const char*> Args;
std::vector<const char*> Envp;
for (int i = 0; argv[i]; i++) {
Args.push_back(argv[i]);
}
Args.push_back(nullptr);
for (int i = 0; envp[i]; i++) {
Envp.push_back(envp[i]);
}
Envp.push_back(nullptr);
FEX::HLE::ExecveAtArgs AtArgs {
.dirfd = dirfd,
.flags = flags,
};
return FEX::HLE::ExecveHandler(pathname, Args, Envp, &AtArgs);
}));
REGISTER_SYSCALL_IMPL_X64(wait4, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int *wstatus, int options, struct rusage *rusage) -> uint64_t {
uint64_t Result = ::wait4(pid, wstatus, options, rusage);
SYSCALL_ERRNO();