mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 20:00:16 +02:00
Adds 11 new emulated syscalls
This commit is contained in:
1 parent
d2bfb39b54
commit
472ec5f5cf
6 files changed
+407
-62
No files matched your search
@@ -50,6 +50,9 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) {
|
||||
FEXCore::X86State::REG_R9,
|
||||
};
|
||||
|
||||
auto NewRIP = _Constant(Op->PC);
|
||||
_StoreContext(8, offsetof(FEXCore::Core::CPUState, rip), NewRIP);
|
||||
|
||||
auto SyscallOp = _Syscall(
|
||||
_LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs) + GPRIndexes[0] * 8),
|
||||
_LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs) + GPRIndexes[1] * 8),
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
#include "Interface/HLE/FileManagement.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEXCore {
|
||||
@@ -76,6 +78,15 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class EventFD final : public FD {
|
||||
public:
|
||||
EventFD(FEXCore::Context::Context *ctx, int32_t fd, uint32_t initval, uint32_t flags)
|
||||
: FD (ctx, fd, "Event", 0, 0) {
|
||||
HostFD = eventfd(initval, flags);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
uint64_t FD::read(int fd, void *buf, size_t count) {
|
||||
return ::read(HostFD, buf, count);
|
||||
}
|
||||
@@ -373,6 +384,36 @@ uint64_t FileManager::PRead64(int fd, void *buf, size_t count, off_t offset) {
|
||||
return pread(FD->second->GetHostFD(), buf, count, offset);
|
||||
}
|
||||
|
||||
uint64_t FileManager::Statx(int dirfd, const char *pathname, int flags, uint32_t mask, struct statx *statxbuf) {
|
||||
// Do we need the dirfd?
|
||||
if (pathname[0] == '/' ||
|
||||
((flags & AT_EMPTY_PATH) && pathname[0] == '\0')) {
|
||||
auto FD = FDMap.find(dirfd);
|
||||
if (FD == FDMap.end()) {
|
||||
return EBADF;
|
||||
}
|
||||
dirfd = FD->second->GetHostFD();
|
||||
}
|
||||
auto Path = GetEmulatedPath(pathname);
|
||||
if (!Path.empty()) {
|
||||
uint64_t Result = ::statx(dirfd, Path.c_str(), flags, mask, statxbuf);
|
||||
if (Result != -1)
|
||||
return Result;
|
||||
}
|
||||
return ::statx(dirfd, pathname, flags, mask, statxbuf);
|
||||
}
|
||||
|
||||
uint64_t FileManager::Mknod(const char *pathname, mode_t mode, dev_t dev) {
|
||||
auto Path = GetEmulatedPath(pathname);
|
||||
if (!Path.empty()) {
|
||||
uint64_t Result = ::mknod(Path.c_str(), mode, dev);
|
||||
if (Result != -1)
|
||||
return Result;
|
||||
}
|
||||
return ::mknod(pathname, mode, dev);
|
||||
}
|
||||
|
||||
|
||||
uint64_t FileManager::EPoll_Create1(int flags) {
|
||||
int HostFD = epoll_create1(flags);
|
||||
int32_t fd = CurrentFDOffset;
|
||||
@@ -382,6 +423,32 @@ uint64_t FileManager::EPoll_Create1(int flags) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
uint64_t FileManager::Statfs(const char *path, void *buf) {
|
||||
auto Path = GetEmulatedPath(path);
|
||||
if (!Path.empty()) {
|
||||
uint64_t Result = ::statfs(Path.c_str(), reinterpret_cast<struct statfs*>(buf));
|
||||
if (Result != -1)
|
||||
return Result;
|
||||
}
|
||||
return ::statfs(path, reinterpret_cast<struct statfs*>(buf));
|
||||
}
|
||||
|
||||
uint64_t FileManager::Eventfd(uint32_t initval, uint32_t flags) {
|
||||
int32_t fd = CurrentFDOffset;
|
||||
|
||||
auto fdPtr = new EventFD{CTX, fd, initval, flags};
|
||||
|
||||
auto Result = fdPtr->GetHostFD();
|
||||
if (Result == -1) {
|
||||
delete fdPtr;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
FDMap[CurrentFDOffset++] = fdPtr;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
uint64_t FileManager::Socket(int domain, int type, int protocol) {
|
||||
int32_t fd = CurrentFDOffset;
|
||||
|
||||
@@ -420,6 +487,42 @@ uint64_t FileManager::Recvfrom(int sockfd, void *buf, size_t len, int flags, str
|
||||
return recvfrom(FD->second->GetHostFD(), buf, len, flags, src_addr, addrlen);
|
||||
}
|
||||
|
||||
uint64_t FileManager::Sendmsg(int sockfd, const struct msghdr *msg, int flags) {
|
||||
auto FD = FDMap.find(sockfd);
|
||||
if (FD == FDMap.end()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<iovec> Hostvec;
|
||||
struct msghdr Hosthdr;
|
||||
memcpy(&Hosthdr, msg, sizeof(struct msghdr));
|
||||
|
||||
if (Hosthdr.msg_name)
|
||||
Hosthdr.msg_name = CTX->MemoryMapper.GetPointer(reinterpret_cast<uint64_t>(Hosthdr.msg_name));
|
||||
|
||||
if (Hosthdr.msg_control)
|
||||
Hosthdr.msg_control = CTX->MemoryMapper.GetPointer(reinterpret_cast<uint64_t>(Hosthdr.msg_control));
|
||||
|
||||
Hostvec.resize(Hosthdr.msg_iovlen);
|
||||
|
||||
struct iovec *Guestiov = CTX->MemoryMapper.GetPointer<struct iovec*>(reinterpret_cast<uint64_t>(Hosthdr.msg_iov));
|
||||
for (int i = 0; i < Hosthdr.msg_iovlen; ++i) {
|
||||
Hostvec[i].iov_base = CTX->MemoryMapper.GetPointer(reinterpret_cast<uint64_t>(Guestiov[i].iov_base));
|
||||
Hostvec[i].iov_len = Guestiov[i].iov_len;
|
||||
}
|
||||
|
||||
Hosthdr.msg_iov = &Hostvec.at(0);
|
||||
|
||||
int Result = sendmsg(FD->second->GetHostFD(), &Hosthdr, flags);
|
||||
if (Result == -1) {
|
||||
if (errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK) {
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
uint64_t FileManager::Recvmsg(int sockfd, struct msghdr *msg, int flags) {
|
||||
auto FD = FDMap.find(sockfd);
|
||||
if (FD == FDMap.end()) {
|
||||
@@ -638,4 +741,18 @@ FD const* FileManager::GetFDBacking(int fd) {
|
||||
return FD->second;
|
||||
}
|
||||
|
||||
int32_t FileManager::DupFD(int prevFD, int newFD) {
|
||||
auto prevFDClass = FDMap.find(prevFD);
|
||||
if (prevFDClass == FDMap.end()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t fd = CurrentFDOffset;
|
||||
|
||||
auto fdPtr = new FD{prevFDClass->second, fd};
|
||||
FDMap[CurrentFDOffset++] = fdPtr;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,14 @@ public:
|
||||
, Flags {flags}
|
||||
, Mode {mode} {
|
||||
}
|
||||
|
||||
FD(FD *Prev, int32_t fd)
|
||||
: CTX {Prev->CTX}
|
||||
, FDOffset {fd}
|
||||
, PathName {Prev->PathName}
|
||||
, Flags {Prev->Flags}
|
||||
, Mode {Prev->Mode} {
|
||||
}
|
||||
virtual ~FD() {}
|
||||
|
||||
uint64_t read(int fd, void *buf, size_t count);
|
||||
@@ -74,14 +82,23 @@ public:
|
||||
uint64_t Ioctl(int fd, uint64_t request, void *args);
|
||||
uint64_t GetDents(int fd, void *dirp, uint32_t count);
|
||||
uint64_t PRead64(int fd, void *buf, size_t count, off_t offset);
|
||||
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);
|
||||
|
||||
// EPoll
|
||||
uint64_t EPoll_Create1(int flags);
|
||||
|
||||
// vfs
|
||||
uint64_t Statfs(const char *path, void *buf);
|
||||
|
||||
// Eventfd
|
||||
uint64_t Eventfd(uint32_t initval, uint32_t flags);
|
||||
|
||||
// Sockets
|
||||
uint64_t Socket(int domain, int type, int protocol);
|
||||
uint64_t Connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
uint64_t Recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
uint64_t Sendmsg(int sockfd, const struct msghdr *msg, int flags);
|
||||
uint64_t Recvmsg(int sockfd, struct msghdr *msg, int flags);
|
||||
uint64_t Shutdown(int sockfd, int how);
|
||||
uint64_t GetSockName(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
@@ -95,6 +112,7 @@ public:
|
||||
int32_t FindHostFD(int fd);
|
||||
|
||||
FD const* GetFDBacking(int fd);
|
||||
int32_t DupFD(int prevFD, int newFD);
|
||||
|
||||
void SetFilename(std::string const &File) { Filename = File; }
|
||||
std::string const & GetFilename() const { return Filename; }
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
@@ -89,12 +90,28 @@ void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret)
|
||||
Args->Argument[5],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_SCHED_YIELD:
|
||||
LogMan::Msg::D("sched_yield() = %ld",
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_MINCORE:
|
||||
LogMan::Msg::D("mincore(0x%lx, 0x%lx, 0x%lx) = %ld",
|
||||
Args->Argument[1],
|
||||
Args->Argument[2],
|
||||
Args->Argument[3],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_NANOSLEEP:
|
||||
LogMan::Msg::D("nanosleep(0x%ld, 0x%lx) = %ld",
|
||||
Args->Argument[1],
|
||||
Args->Argument[2],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_ALARM:
|
||||
LogMan::Msg::D("alarm(%ld) = %ld",
|
||||
Args->Argument[1],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_OPENAT:
|
||||
LogMan::Msg::D("openat(%ld, \"%s\", %d) = %ld", Args->Argument[1], CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[2]), Args->Argument[3], Ret);
|
||||
break;
|
||||
@@ -119,6 +136,13 @@ void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret)
|
||||
case SYSCALL_READ:
|
||||
LogMan::Msg::D("read(%ld, {...}, %ld) = %ld", Args->Argument[1], Args->Argument[3], Ret);
|
||||
break;
|
||||
case SYSCALL_PRCTL:
|
||||
LogMan::Msg::D("arch_prctl(%ld, %p, %p, %p, %p) = %ld",
|
||||
Args->Argument[1], Args->Argument[2],
|
||||
Args->Argument[3], Args->Argument[4],
|
||||
Args->Argument[5],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_ARCH_PRCTL:
|
||||
LogMan::Msg::D("arch_prctl(%ld, %p) = %ld", Args->Argument[1], Args->Argument[2], Ret);
|
||||
break;
|
||||
@@ -152,6 +176,9 @@ void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret)
|
||||
case SYSCALL_MKDIR:
|
||||
LogMan::Msg::D("mkdir(\"%s\", 0x%lx) = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Args->Argument[2], Ret);
|
||||
break;
|
||||
case SYSCALL_RMDIR:
|
||||
LogMan::Msg::D("rmdir(\"%s\", 0x%lx) = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Args->Argument[2], Ret);
|
||||
break;
|
||||
case SYSCALL_UNLINK:
|
||||
LogMan::Msg::D("unlink(\"%s\", 0x%lx) = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Ret);
|
||||
break;
|
||||
@@ -176,6 +203,9 @@ void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret)
|
||||
case SYSCALL_SET_ROBUST_LIST:
|
||||
LogMan::Msg::D("set_robust_list(%p, %ld) = %ld", Args->Argument[1], Args->Argument[2], Ret);
|
||||
break;
|
||||
case SYSCALL_EVENTFD:
|
||||
LogMan::Msg::D("eventfd(%lx, %ld) = %ld", Args->Argument[1], Args->Argument[2], Ret);
|
||||
break;
|
||||
case SYSCALL_EPOLL_CREATE1:
|
||||
LogMan::Msg::D("epoll_create1(%ld) = %ld", Args->Argument[1], Ret);
|
||||
break;
|
||||
@@ -213,6 +243,13 @@ void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret)
|
||||
Args->Argument[6],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_SENDMSG:
|
||||
LogMan::Msg::D("sendmsg(%ld, 0x%lx, %ld) = %ld",
|
||||
Args->Argument[1],
|
||||
Args->Argument[2],
|
||||
Args->Argument[3],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_RECVMSG:
|
||||
LogMan::Msg::D("recvmsg(%ld, 0x%lx, %ld) = %ld",
|
||||
Args->Argument[1],
|
||||
@@ -277,6 +314,17 @@ void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret)
|
||||
case SYSCALL_SETRESUID:
|
||||
LogMan::Msg::D("setresuid(%ld, %ld, %ld) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret);
|
||||
break;
|
||||
case SYSCALL_SETRESGID:
|
||||
LogMan::Msg::D("setresgid(%ld, %ld, %ld) = %ld", Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret);
|
||||
break;
|
||||
case SYSCALL_MKNOD:
|
||||
LogMan::Msg::D("mknod(\"%s\", %ld, %ld) = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]),
|
||||
Args->Argument[2], Args->Argument[3],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_STATFS:
|
||||
LogMan::Msg::D("statfs(\"%s\", {...}) = %ld", CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Ret);
|
||||
break;
|
||||
case SYSCALL_GETTID:
|
||||
LogMan::Msg::D("gettid() = %ld", Ret);
|
||||
break;
|
||||
@@ -321,6 +369,13 @@ void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret)
|
||||
Args->Argument[3],
|
||||
Ret);
|
||||
break;
|
||||
case SYSCALL_STATX:
|
||||
LogMan::Msg::D("statx(%ld, \"%s\", 0x%lx, 0x%lx, {...}) = %ld",
|
||||
Args->Argument[1],
|
||||
CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[2]),
|
||||
Args->Argument[3], Args->Argument[4],
|
||||
Ret);
|
||||
break;
|
||||
default: LogMan::Msg::D("Unknown strace: %d", Args->Argument[0]);
|
||||
}
|
||||
}
|
||||
@@ -393,6 +448,10 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
uint64_t Size = AlignUp(Args->Argument[2], PAGE_SIZE);
|
||||
uint64_t FileSizeToUse = Args->Argument[2];
|
||||
uint64_t Prot = Args->Argument[3];
|
||||
if (Args->Argument[2] == 0) {
|
||||
Result = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Flags & MAP_FIXED) {
|
||||
Base = Args->Argument[1];
|
||||
@@ -441,6 +500,19 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
Result = mprotect(HostPtr, Args->Argument[2], Args->Argument[3]);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_PRCTL: {
|
||||
switch (Args->Argument[1]) {
|
||||
case 0xF: // PR_SET_NAME
|
||||
case 0x10: // PR_GET_NAME
|
||||
Result = 0;
|
||||
break;
|
||||
default:
|
||||
LogMan::Msg::E("Unknown prctl: 0x%x", Args->Argument[1]);
|
||||
CTX->ShouldStop = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ARCH_PRCTL: {
|
||||
switch (Args->Argument[1]) {
|
||||
case 0x1001: // ARCH_SET_GS
|
||||
@@ -485,6 +557,11 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
CTX->MemoryMapper.GetPointer<struct sockaddr *>(Args->Argument[5]),
|
||||
CTX->MemoryMapper.GetPointer<socklen_t*>(Args->Argument[6]));
|
||||
break;
|
||||
case SYSCALL_SENDMSG:
|
||||
Result = FM.Sendmsg(Args->Argument[1],
|
||||
CTX->MemoryMapper.GetPointer<const struct msghdr*>(Args->Argument[2]),
|
||||
Args->Argument[3]);
|
||||
break;
|
||||
case SYSCALL_RECVMSG:
|
||||
Result = FM.Recvmsg(Args->Argument[1],
|
||||
CTX->MemoryMapper.GetPointer<struct msghdr*>(Args->Argument[2]),
|
||||
@@ -529,8 +606,12 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
Result = Thread->State.ThreadManager.GetGID();
|
||||
break;
|
||||
case SYSCALL_SETUID:
|
||||
// XXX: Not a real result
|
||||
Result = -1;
|
||||
if (Thread->State.ThreadManager.GetUID() == Args->Argument[1]) {
|
||||
Result = 0;
|
||||
}
|
||||
else {
|
||||
Result = EINVAL;
|
||||
}
|
||||
break;
|
||||
case SYSCALL_GETEUID:
|
||||
Result = Thread->State.ThreadManager.GetEUID();
|
||||
@@ -539,13 +620,41 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
Result = Thread->State.ThreadManager.GetEGID();
|
||||
break;
|
||||
case SYSCALL_SETREGID:
|
||||
// XXX: Not a real result
|
||||
Result = 0;
|
||||
if (Thread->State.ThreadManager.GetEGID() == Args->Argument[1]) {
|
||||
Result = 0;
|
||||
}
|
||||
else {
|
||||
Result = EINVAL;
|
||||
}
|
||||
break;
|
||||
case SYSCALL_SETRESUID:
|
||||
// XXX: Not a real result
|
||||
Result = -1;
|
||||
break;
|
||||
case SYSCALL_SETRESGID:
|
||||
// rgid, egid, sgid
|
||||
Result = 0;
|
||||
if (Args->Argument[1] != -1 &&
|
||||
Args->Argument[1] != Thread->State.ThreadManager.GetGID()) {
|
||||
Result = EPERM;
|
||||
}
|
||||
if (Args->Argument[2] != -1 &&
|
||||
Args->Argument[2] != Thread->State.ThreadManager.GetEGID()) {
|
||||
Result = EPERM;
|
||||
}
|
||||
if (Args->Argument[3] != -1) {
|
||||
Result = EPERM;
|
||||
}
|
||||
|
||||
break;
|
||||
case SYSCALL_MKNOD:
|
||||
Result = FM.Mknod(CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]),
|
||||
Args->Argument[2], Args->Argument[3]);
|
||||
break;
|
||||
case SYSCALL_STATFS:
|
||||
Result = FM.Statfs(CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]),
|
||||
CTX->MemoryMapper.GetPointer(Args->Argument[2]));
|
||||
break;
|
||||
case SYSCALL_GETTID:
|
||||
Result = Thread->State.ThreadManager.GetTID();
|
||||
break;
|
||||
@@ -555,6 +664,11 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
case SYSCALL_EXIT:
|
||||
LogMan::Msg::D("Thread exit with: %zd\n", Args->Argument[1]);
|
||||
Thread->State.RunningEvents.ShouldStop = true;
|
||||
if (Thread->State.ThreadManager.clear_tid) {
|
||||
Futex *futex = GetFutex(Thread->State.ThreadManager.child_tid);
|
||||
futex->Addr->store(0);
|
||||
futex->cv.notify_all();
|
||||
}
|
||||
break;
|
||||
case SYSCALL_WAIT4:
|
||||
LogMan::Msg::I("wait4(%lx,\n\t%lx,\n\t%lx,\n\t%lx)",
|
||||
@@ -566,51 +680,70 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
|
||||
// Futexes
|
||||
case SYSCALL_FUTEX: {
|
||||
// 0 : uaddr
|
||||
// 1 : op
|
||||
// 2: val
|
||||
// 3: utime
|
||||
// 4: uaddr2
|
||||
// 5: val3
|
||||
LogMan::Msg::I("futex(%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx)",
|
||||
Args->Argument[1],
|
||||
Args->Argument[2],
|
||||
Args->Argument[3],
|
||||
Args->Argument[4],
|
||||
Args->Argument[5],
|
||||
Args->Argument[6]);
|
||||
|
||||
// 0 : uaddr
|
||||
// 1 : op
|
||||
// 2: val
|
||||
// 3: utime
|
||||
// 4: uaddr2
|
||||
// 5: val3
|
||||
LogMan::Msg::I("futex(%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx,\n\t%lx)",
|
||||
Args->Argument[1],
|
||||
Args->Argument[2],
|
||||
Args->Argument[3],
|
||||
Args->Argument[4],
|
||||
Args->Argument[5],
|
||||
Args->Argument[6]);
|
||||
uint8_t Command = Args->Argument[2] & 0xF;
|
||||
Result = 0;
|
||||
switch (Command) {
|
||||
case 0: { // WAIT
|
||||
LogMan::Throw::A(!Args->Argument[4], "Can't handle timed futexes");
|
||||
Futex *futex = GetFutex(Args->Argument[1]);
|
||||
|
||||
uint8_t Command = Args->Argument[2] & 0xF;
|
||||
Result = 0;
|
||||
switch (Command) {
|
||||
case 0: { // WAIT
|
||||
LogMan::Throw::A(!Args->Argument[4], "Can't handle timed futexes");
|
||||
Futex *futex = new Futex{}; // XXX: Definitely a memory leak. When should we free this?
|
||||
futex->Addr = CTX->MemoryMapper.GetPointer<std::atomic<uint32_t>*>(Args->Argument[1]);
|
||||
futex->Val = Args->Argument[3];
|
||||
EmplaceFutex(Args->Argument[1], futex);
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(futex->Mutex);
|
||||
futex->cv.wait(lk, [futex] { return futex->Addr->load() != futex->Val; });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: { // WAKE
|
||||
Futex *futex = GetFutex(Args->Argument[1]);
|
||||
if (!futex) {
|
||||
Result = 0;
|
||||
if (!futex) {
|
||||
futex = new Futex{}; // XXX: Definitely a memory leak. When should we free this?
|
||||
futex->Addr = CTX->MemoryMapper.GetPointer<std::atomic<uint32_t>*>(Args->Argument[1]);
|
||||
futex->Val = Args->Argument[3];
|
||||
EmplaceFutex(Args->Argument[1], futex);
|
||||
}
|
||||
if (futex->Addr->load() != futex->Val) {
|
||||
// Immediate check can return EAGAIN
|
||||
Result = EAGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(futex->Mutex);
|
||||
futex->Waiters++;
|
||||
futex->cv.wait(lk, [futex] { return futex->Addr->load() != futex->Val; });
|
||||
futex->Waiters--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: { // WAKE
|
||||
Futex *futex = GetFutex(Args->Argument[1]);
|
||||
if (!futex) {
|
||||
// Tried to wake up an unknown futex?
|
||||
Result = 0;
|
||||
break;
|
||||
}
|
||||
if (Args->Argument[3] == INT_MAX) {
|
||||
Result = futex->Waiters;
|
||||
futex->cv.notify_all();
|
||||
}
|
||||
else {
|
||||
uint32_t PrevWaiters = futex->Waiters;
|
||||
for (uint64_t i = 0; i < Args->Argument[3]; ++i)
|
||||
futex->cv.notify_one();
|
||||
Result = std::min(PrevWaiters, (uint32_t)Args->Argument[3]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogMan::Msg::A("Unknown futex command");
|
||||
break;
|
||||
}
|
||||
for (uint64_t i = 0; i < Args->Argument[3]; ++i)
|
||||
futex->cv.notify_one();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogMan::Msg::A("Unknown futex command");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case SYSCALL_CLONE: {
|
||||
// 0: clone_flags
|
||||
@@ -657,7 +790,10 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
NewThreadState.gregs[FEXCore::X86State::REG_RBX] = 0;
|
||||
NewThreadState.gregs[FEXCore::X86State::REG_RBP] = 0;
|
||||
NewThreadState.gregs[FEXCore::X86State::REG_RSP] = NewSP;
|
||||
NewThreadState.fs = NewTLS;
|
||||
|
||||
if (Flags & CLONE_SETTLS) {
|
||||
NewThreadState.fs = NewTLS;
|
||||
}
|
||||
|
||||
// Set us to start just after the syscall instruction
|
||||
NewThreadState.rip += 2;
|
||||
@@ -681,6 +817,11 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
// Additionally wakeup a futex at that address
|
||||
// Address /may/ be changed with SET_TID_ADDRESS syscall
|
||||
if (Flags & CLONE_CHILD_CLEARTID) {
|
||||
Futex *futex = new Futex{}; // XXX: Definitely a memory leak. When should we free this?
|
||||
futex->Addr = CTX->MemoryMapper.GetPointer<std::atomic<uint32_t>*>(ChildTID);
|
||||
futex->Val = NewThread->State.ThreadManager.GetTID();
|
||||
EmplaceFutex(ChildTID, futex);
|
||||
NewThread->State.ThreadManager.clear_tid = true;
|
||||
}
|
||||
|
||||
CTX->InitializeThread(NewThread);
|
||||
@@ -777,6 +918,9 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
readfds, writefds, exceptfds, timeout);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_SCHED_YIELD:
|
||||
Result = sched_yield();
|
||||
break;
|
||||
case SYSCALL_READLINK:
|
||||
Result = FM.Readlink(
|
||||
CTX->MemoryMapper.GetPointer<const char*>(Args->Argument[1]),
|
||||
@@ -839,12 +983,23 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
Result = clock_getres(Args->Argument[1], res);
|
||||
}
|
||||
break;
|
||||
case SYSCALL_MINCORE: {
|
||||
Result = mincore(CTX->MemoryMapper.GetPointer(Args->Argument[1]),
|
||||
Args->Argument[2],
|
||||
CTX->MemoryMapper.GetPointer<unsigned char*>(Args->Argument[3]));
|
||||
break;
|
||||
}
|
||||
case SYSCALL_NANOSLEEP: {
|
||||
timespec const* req = CTX->MemoryMapper.GetPointer<timespec const*>(Args->Argument[1]);
|
||||
timespec *rem = CTX->MemoryMapper.GetPointer<timespec*>(Args->Argument[2]);
|
||||
Result = nanosleep(req, rem);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_ALARM: {
|
||||
// XXX: Not a real result
|
||||
Result = 0;
|
||||
break;
|
||||
}
|
||||
case SYSCALL_GETDENTS64: {
|
||||
Result = FM.GetDents(Args->Argument[1],
|
||||
CTX->MemoryMapper.GetPointer(Args->Argument[2]),
|
||||
@@ -852,6 +1007,14 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
break;
|
||||
}
|
||||
case SYSCALL_SET_TID_ADDRESS: {
|
||||
Futex *futex = GetFutex(Thread->State.ThreadManager.child_tid);
|
||||
// If a futex for this address changes then the futex location needs to change...
|
||||
if (futex) {
|
||||
RemoveFutex(Thread->State.ThreadManager.child_tid);
|
||||
futex->Addr = CTX->MemoryMapper.GetPointer<std::atomic<uint32_t>*>(Args->Argument[1]);
|
||||
EmplaceFutex(Args->Argument[1], futex);
|
||||
}
|
||||
|
||||
Thread->State.ThreadManager.child_tid = Args->Argument[1];
|
||||
Result = Thread->State.ThreadManager.GetTID();
|
||||
break;
|
||||
@@ -861,6 +1024,10 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
Result = 0;
|
||||
break;
|
||||
}
|
||||
case SYSCALL_EVENTFD: {
|
||||
Result = FM.Eventfd(Args->Argument[1], Args->Argument[2]);
|
||||
break;
|
||||
}
|
||||
case SYSCALL_EPOLL_CREATE1: {
|
||||
Result = FM.EPoll_Create1(Args->Argument[1]);
|
||||
break;
|
||||
@@ -925,27 +1092,41 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
case SYSCALL_MKDIR:
|
||||
Result = mkdir(CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]), Args->Argument[2]);
|
||||
break;
|
||||
case SYSCALL_RMDIR:
|
||||
Result = rmdir(CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]));
|
||||
break;
|
||||
case SYSCALL_UNLINK:
|
||||
Result = unlink(CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[1]));
|
||||
break;
|
||||
case SYSCALL_FCNTL: {
|
||||
int Cmd = Args->Argument[2];
|
||||
auto FD = FM.GetFDBacking(Args->Argument[1]);
|
||||
auto HostFD = FD->GetHostFD();
|
||||
switch (Cmd) {
|
||||
case 1: // F_GETFD
|
||||
Result = fcntl(HostFD, Cmd);
|
||||
break;
|
||||
case 2: // F_SETFD
|
||||
Result = fcntl(HostFD, Cmd, Args->Argument[3]);
|
||||
break;
|
||||
case 3: // F_GETFL
|
||||
Result = fcntl(HostFD, Cmd);
|
||||
break;
|
||||
case 4: // F_SETFL
|
||||
Result = fcntl(HostFD, Cmd, Args->Argument[3]);
|
||||
break;
|
||||
default: LogMan::Msg::A("FCNTL: Unknown Command: %ld", Cmd); break;
|
||||
if (!FD) {
|
||||
Result = EBADF;
|
||||
}
|
||||
else {
|
||||
auto HostFD = FD->GetHostFD();
|
||||
switch (Cmd) {
|
||||
case 0: // F_DUPFD
|
||||
case 1030:{ // F_DUPFD_CLOEXEC
|
||||
int NewFD = fcntl(HostFD, Cmd);
|
||||
Result = FM.DupFD(Args->Argument[1], NewFD);
|
||||
break;
|
||||
}
|
||||
case 1: // F_GETFD
|
||||
Result = fcntl(HostFD, Cmd);
|
||||
break;
|
||||
case 2: // F_SETFD
|
||||
Result = fcntl(HostFD, Cmd, Args->Argument[3]);
|
||||
break;
|
||||
case 3: // F_GETFL
|
||||
Result = fcntl(HostFD, Cmd);
|
||||
break;
|
||||
case 4: // F_SETFL
|
||||
Result = fcntl(HostFD, Cmd, Args->Argument[3]);
|
||||
break;
|
||||
default: LogMan::Msg::A("FCNTL: Unknown Command: %ld", Cmd); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -954,6 +1135,13 @@ uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Threa
|
||||
Args->Argument[2],
|
||||
Args->Argument[3]);
|
||||
break;
|
||||
case SYSCALL_STATX:
|
||||
Result = FM.Statx(
|
||||
Args->Argument[1],
|
||||
CTX->MemoryMapper.GetPointer<char const*>(Args->Argument[2]),
|
||||
Args->Argument[3], Args->Argument[4],
|
||||
CTX->MemoryMapper.GetPointer<struct statx*>(Args->Argument[5]));
|
||||
break;
|
||||
// Currently unhandled
|
||||
// Return fake result
|
||||
case SYSCALL_RT_SIGACTION:
|
||||
|
||||
@@ -42,11 +42,15 @@ enum Syscalls {
|
||||
SYSCALL_ACCESS = 21, ///< __NR_access
|
||||
SYSCALL_PIPE = 22, ///< __NR_pipe
|
||||
SYSCALL_SELECT = 23, ///< __NR_select
|
||||
SYSCALL_SCHED_YIELD = 24, ///< __NR_sched_yield
|
||||
SYSCALL_MINCORE = 27, ///< __NR_mincore
|
||||
SYSCALL_NANOSLEEP = 35, ///< __NR_nanosleep
|
||||
SYSCALL_ALARM = 37, ///< __NR_alarm
|
||||
SYSCALL_GETPID = 39, ///< __NR_getpid
|
||||
SYSCALL_SOCKET = 41, ///< __NR_socket
|
||||
SYSCALL_CONNECT = 42, ///< __NR_connect
|
||||
SYSCALL_RECVFROM = 45, ///< __NR_recvfrom
|
||||
SYSCALL_SENDMSG = 46, ///< __NR_sendmsg
|
||||
SYSCALL_RECVMSG = 47, ///< __NR_recvmsg
|
||||
SYSCALL_SHUTDOWN = 48, ///< __NR_shutdown
|
||||
SYSCALL_GETSOCKNAME = 51, ///< __NR_getsockname
|
||||
@@ -61,6 +65,7 @@ enum Syscalls {
|
||||
SYSCALL_GETCWD = 79, ///< __NR_getcwd
|
||||
SYSCALL_CHDIR = 80, ///< __NR_chdir
|
||||
SYSCALL_MKDIR = 83, ///< __NR_mkdir
|
||||
SYSCALL_RMDIR = 84, ///< __NR_rmdir
|
||||
SYSCALL_UNLINK = 87, ///< __NR_unlink
|
||||
SYSCALL_READLINK = 89, ///< __NR_readlink
|
||||
SYSCALL_UMASK = 95, ///< __NR_umask
|
||||
@@ -73,6 +78,10 @@ enum Syscalls {
|
||||
SYSCALL_GETEGID = 108, ///< __NR_getegid
|
||||
SYSCALL_SETREGID = 114, ///< __NR_setregid
|
||||
SYSCALL_SETRESUID = 117, ///< __NR_setresuid
|
||||
SYSCALL_SETRESGID = 119, ///< __NR_setresgid
|
||||
SYSCALL_MKNOD = 133, ///< __NR_mknod
|
||||
SYSCALL_STATFS = 137, ///< __NR_statfs
|
||||
SYSCALL_PRCTL = 157, ///< __NR_prctl
|
||||
SYSCALL_ARCH_PRCTL = 158, ///< __NR_arch_prctl
|
||||
SYSCALL_GETTID = 186, ///< __NR_gettid
|
||||
SYSCALL_TIME = 201, ///< __NR_time
|
||||
@@ -85,17 +94,20 @@ enum Syscalls {
|
||||
SYSCALL_TGKILL = 234, ///< __NR_tgkill
|
||||
SYSCALL_OPENAT = 257, ///< __NR_openat
|
||||
SYSCALL_SET_ROBUST_LIST = 273, ///< __NR_set_robust_list
|
||||
SYSCALL_EVENTFD = 290, ///< __NR_eventfd
|
||||
SYSCALL_EPOLL_CREATE1 = 291, ///< __NR_epoll_create1
|
||||
SYSCALL_PIPE2 = 293, ///< __NR_pipe2
|
||||
SYSCALL_PRLIMIT64 = 302, ///< __NR_prlimit64
|
||||
SYSCALL_SENDMMSG = 307, ///< __NR_sendmmsg
|
||||
SYSCALL_GETRANDOM = 318, ///< __NR_getrandom
|
||||
SYSCALL_STATX = 332, ///< __NR_statx
|
||||
};
|
||||
|
||||
struct Futex {
|
||||
std::mutex Mutex;
|
||||
std::condition_variable cv;
|
||||
std::atomic<uint32_t> *Addr;
|
||||
std::atomic<uint32_t> Waiters{};
|
||||
uint32_t Val;
|
||||
};
|
||||
|
||||
@@ -114,7 +126,13 @@ public:
|
||||
|
||||
Futex *GetFutex(uint64_t Addr) {
|
||||
std::scoped_lock<std::mutex> lk (FutexMutex);
|
||||
return Futexes[Addr];
|
||||
auto it = Futexes.find(Addr);
|
||||
if (it == Futexes.end()) return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void RemoveFutex(uint64_t Addr) {
|
||||
Futexes.erase(Addr);
|
||||
}
|
||||
|
||||
void DefaultProgramBreak(FEXCore::Core::InternalThreadState *Thread, uint64_t Addr);
|
||||
|
||||
@@ -22,5 +22,6 @@ public:
|
||||
uint64_t child_tid{0};
|
||||
uint64_t parent_tid{0};
|
||||
uint64_t robust_list_head{0};
|
||||
bool clear_tid{false};
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user