diff --git a/Source/Interface/Core/OpcodeDispatcher.cpp b/Source/Interface/Core/OpcodeDispatcher.cpp index 7cfd19921..4ed20fe35 100644 --- a/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/Source/Interface/Core/OpcodeDispatcher.cpp @@ -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), diff --git a/Source/Interface/HLE/FileManagement.cpp b/Source/Interface/HLE/FileManagement.cpp index 6ddee437f..2f89209d8 100644 --- a/Source/Interface/HLE/FileManagement.cpp +++ b/Source/Interface/HLE/FileManagement.cpp @@ -4,10 +4,12 @@ #include "Interface/HLE/FileManagement.h" #include #include +#include #include #include #include #include +#include #include 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(buf)); + if (Result != -1) + return Result; + } + return ::statfs(path, reinterpret_cast(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 Hostvec; + struct msghdr Hosthdr; + memcpy(&Hosthdr, msg, sizeof(struct msghdr)); + + if (Hosthdr.msg_name) + Hosthdr.msg_name = CTX->MemoryMapper.GetPointer(reinterpret_cast(Hosthdr.msg_name)); + + if (Hosthdr.msg_control) + Hosthdr.msg_control = CTX->MemoryMapper.GetPointer(reinterpret_cast(Hosthdr.msg_control)); + + Hostvec.resize(Hosthdr.msg_iovlen); + + struct iovec *Guestiov = CTX->MemoryMapper.GetPointer(reinterpret_cast(Hosthdr.msg_iov)); + for (int i = 0; i < Hosthdr.msg_iovlen; ++i) { + Hostvec[i].iov_base = CTX->MemoryMapper.GetPointer(reinterpret_cast(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; +} + } diff --git a/Source/Interface/HLE/FileManagement.h b/Source/Interface/HLE/FileManagement.h index 4ee25c274..7a909eac4 100644 --- a/Source/Interface/HLE/FileManagement.h +++ b/Source/Interface/HLE/FileManagement.h @@ -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; } diff --git a/Source/Interface/HLE/Syscalls.cpp b/Source/Interface/HLE/Syscalls.cpp index 4a242db73..d4ba0870f 100644 --- a/Source/Interface/HLE/Syscalls.cpp +++ b/Source/Interface/HLE/Syscalls.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -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(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(Args->Argument[1]), Args->Argument[2], Ret); break; + case SYSCALL_RMDIR: + LogMan::Msg::D("rmdir(\"%s\", 0x%lx) = %ld", CTX->MemoryMapper.GetPointer(Args->Argument[1]), Args->Argument[2], Ret); + break; case SYSCALL_UNLINK: LogMan::Msg::D("unlink(\"%s\", 0x%lx) = %ld", CTX->MemoryMapper.GetPointer(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(Args->Argument[1]), + Args->Argument[2], Args->Argument[3], + Ret); + break; + case SYSCALL_STATFS: + LogMan::Msg::D("statfs(\"%s\", {...}) = %ld", CTX->MemoryMapper.GetPointer(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(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(Args->Argument[5]), CTX->MemoryMapper.GetPointer(Args->Argument[6])); break; + case SYSCALL_SENDMSG: + Result = FM.Sendmsg(Args->Argument[1], + CTX->MemoryMapper.GetPointer(Args->Argument[2]), + Args->Argument[3]); + break; case SYSCALL_RECVMSG: Result = FM.Recvmsg(Args->Argument[1], CTX->MemoryMapper.GetPointer(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(Args->Argument[1]), + Args->Argument[2], Args->Argument[3]); + break; + case SYSCALL_STATFS: + Result = FM.Statfs(CTX->MemoryMapper.GetPointer(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*>(Args->Argument[1]); - futex->Val = Args->Argument[3]; - EmplaceFutex(Args->Argument[1], futex); - { - std::unique_lock 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*>(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 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*>(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(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(Args->Argument[3])); + break; + } case SYSCALL_NANOSLEEP: { timespec const* req = CTX->MemoryMapper.GetPointer(Args->Argument[1]); timespec *rem = CTX->MemoryMapper.GetPointer(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*>(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(Args->Argument[1]), Args->Argument[2]); break; + case SYSCALL_RMDIR: + Result = rmdir(CTX->MemoryMapper.GetPointer(Args->Argument[1])); + break; case SYSCALL_UNLINK: Result = unlink(CTX->MemoryMapper.GetPointer(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(Args->Argument[2]), + Args->Argument[3], Args->Argument[4], + CTX->MemoryMapper.GetPointer(Args->Argument[5])); + break; // Currently unhandled // Return fake result case SYSCALL_RT_SIGACTION: diff --git a/Source/Interface/HLE/Syscalls.h b/Source/Interface/HLE/Syscalls.h index 6f56c86a1..ea811e3fb 100644 --- a/Source/Interface/HLE/Syscalls.h +++ b/Source/Interface/HLE/Syscalls.h @@ -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 *Addr; + std::atomic Waiters{}; uint32_t Val; }; @@ -114,7 +126,13 @@ public: Futex *GetFutex(uint64_t Addr) { std::scoped_lock 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); diff --git a/include/FEXCore/HLE/Linux/ThreadManagement.h b/include/FEXCore/HLE/Linux/ThreadManagement.h index ec8464c9a..0dc512dfc 100644 --- a/include/FEXCore/HLE/Linux/ThreadManagement.h +++ b/include/FEXCore/HLE/Linux/ThreadManagement.h @@ -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}; }; }