diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/EPoll.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/EPoll.cpp index 690c1f0862..32058b25ec 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/EPoll.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/EPoll.cpp @@ -29,80 +29,80 @@ struct CpuStateFrame; } namespace FEX::HLE::x32 { +auto epoll_wait(FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, int maxevents, int timeout) + -> uint64_t { + fextl::vector Events(std::max(0, maxevents)); + uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), epfd, Events.data(), maxevents, timeout, nullptr, 8); + + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(events, sizeof(FEX::HLE::x32::epoll_event32) * Result); + for (size_t i = 0; i < Result; ++i) { + events[i] = Events[i]; + } + } + SYSCALL_ERRNO(); +} + +auto epoll_ctl(FEXCore::Core::CpuStateFrame* Frame, int epfd, int op, int fd, compat_ptr event) -> uint64_t { + struct epoll_event Event; + struct epoll_event* EventPtr {}; + if (event) { + FaultSafeUserMemAccess::VerifyIsReadable(event, sizeof(FEX::HLE::x32::epoll_event32)); + Event = *event; + EventPtr = &Event; + } + uint64_t Result = ::syscall(SYSCALL_DEF(epoll_ctl), epfd, op, fd, EventPtr); + + if (Result != -1 && event) { + FaultSafeUserMemAccess::VerifyIsWritable(event, sizeof(FEX::HLE::x32::epoll_event32)); + *event = Event; + } + SYSCALL_ERRNO(); +} + +auto epoll_pwait(FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, int maxevent, int timeout, + const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { + fextl::vector Events(std::max(0, maxevent)); + + uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), epfd, Events.data(), maxevent, timeout, sigmask, sigsetsize); + + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(events, sizeof(FEX::HLE::x32::epoll_event32) * Result); + for (size_t i = 0; i < Result; ++i) { + events[i] = Events[i]; + } + } + + SYSCALL_ERRNO(); +} + +auto epoll_pwait2(FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, int maxevent, + compat_ptr timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { + fextl::vector Events(std::max(0, maxevent)); + + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (timeout) { + tp64 = *timeout; + timed_ptr = &tp64; + } + + uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait2), epfd, Events.data(), maxevent, timed_ptr, sigmask, sigsetsize); + + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(events, sizeof(FEX::HLE::x32::epoll_event32) * Result); + for (size_t i = 0; i < Result; ++i) { + events[i] = Events[i]; + } + } + + SYSCALL_ERRNO(); +} + void RegisterEpoll(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32( - epoll_wait, - [](FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, int maxevents, int timeout) -> uint64_t { - fextl::vector Events(std::max(0, maxevents)); - uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), epfd, Events.data(), maxevents, timeout, nullptr, 8); - - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(events, sizeof(FEX::HLE::x32::epoll_event32) * Result); - for (size_t i = 0; i < Result; ++i) { - events[i] = Events[i]; - } - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - epoll_ctl, [](FEXCore::Core::CpuStateFrame* Frame, int epfd, int op, int fd, compat_ptr event) -> uint64_t { - struct epoll_event Event; - struct epoll_event* EventPtr {}; - if (event) { - FaultSafeUserMemAccess::VerifyIsReadable(event, sizeof(FEX::HLE::x32::epoll_event32)); - Event = *event; - EventPtr = &Event; - } - uint64_t Result = ::syscall(SYSCALL_DEF(epoll_ctl), epfd, op, fd, EventPtr); - - if (Result != -1 && event) { - FaultSafeUserMemAccess::VerifyIsWritable(event, sizeof(FEX::HLE::x32::epoll_event32)); - *event = Event; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(epoll_pwait, - [](FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, int maxevent, - int timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { - fextl::vector Events(std::max(0, maxevent)); - - uint64_t Result = ::syscall(SYSCALL_DEF(epoll_pwait), epfd, Events.data(), maxevent, timeout, sigmask, sigsetsize); - - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(events, sizeof(FEX::HLE::x32::epoll_event32) * Result); - for (size_t i = 0; i < Result; ++i) { - events[i] = Events[i]; - } - } - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(epoll_pwait2, - [](FEXCore::Core::CpuStateFrame* Frame, int epfd, compat_ptr events, int maxevent, - compat_ptr timeout, const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { - fextl::vector Events(std::max(0, maxevent)); - - struct timespec tp64 {}; - struct timespec* timed_ptr {}; - if (timeout) { - tp64 = *timeout; - timed_ptr = &tp64; - } - - uint64_t Result = - ::syscall(SYSCALL_DEF(epoll_pwait2), epfd, Events.data(), maxevent, timed_ptr, sigmask, sigsetsize); - - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(events, sizeof(FEX::HLE::x32::epoll_event32) * Result); - for (size_t i = 0; i < Result; ++i) { - events[i] = Events[i]; - } - } - - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(epoll_wait, epoll_wait); + REGISTER_SYSCALL_IMPL_X32(epoll_ctl, epoll_ctl); + REGISTER_SYSCALL_IMPL_X32(epoll_pwait, epoll_pwait); + REGISTER_SYSCALL_IMPL_X32(epoll_pwait2, epoll_pwait2); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp index 610a024380..78ba9de790 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FD.cpp @@ -262,233 +262,715 @@ auto selectHandler = [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* SYSCALL_ERRNO(); }; -void RegisterFD(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(ppoll, - [](FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, timespec32* timeout_ts, - const uint64_t* sigmask, size_t sigsetsize) -> uint64_t { - // sigsetsize is unused here since it is currently a constant and not exposed through glibc - struct timespec tp64 {}; - struct timespec* timed_ptr {}; - if (timeout_ts) { - struct timespec32 timeout {}; - if (FaultSafeUserMemAccess::CopyFromUser(&timeout, timeout_ts, sizeof(timeout)) == EFAULT) { - return -EFAULT; - } - - tp64 = timeout; - timed_ptr = &tp64; - } - - uint64_t Result = ::syscall(SYSCALL_DEF(ppoll), fds, nfds, timed_ptr, sigmask, sigsetsize); - - if (timeout_ts) { - struct timespec32 timeout {}; - timeout = tp64; - - if (FaultSafeUserMemAccess::CopyToUser(timeout_ts, &timeout, sizeof(timeout)) == EFAULT) { - // Write to user memory failed, this can occur if the timeout is defined in read-only memory. - // This is okay to happen, kernel continues happily. - } - } - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - _llseek, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t fd, uint32_t offset_high, uint32_t offset_low, loff_t* result, uint32_t whence) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - uint64_t Result = lseek(fd, Offset, whence); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(result, sizeof(*result)); - *result = Result; - // On non-error result, llseek returns zero (As the result is returned in pointer). - return 0; +auto ppoll(FEXCore::Core::CpuStateFrame* Frame, struct pollfd* fds, nfds_t nfds, timespec32* timeout_ts, const uint64_t* sigmask, + size_t sigsetsize) -> uint64_t { + // sigsetsize is unused here since it is currently a constant and not exposed through glibc + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (timeout_ts) { + struct timespec32 timeout {}; + if (FaultSafeUserMemAccess::CopyFromUser(&timeout, timeout_ts, sizeof(timeout)) == EFAULT) { + return -EFAULT; + } + + tp64 = timeout; + timed_ptr = &tp64; + } + + uint64_t Result = ::syscall(SYSCALL_DEF(ppoll), fds, nfds, timed_ptr, sigmask, sigsetsize); + + if (timeout_ts) { + struct timespec32 timeout {}; + timeout = tp64; + + if (FaultSafeUserMemAccess::CopyToUser(timeout_ts, &timeout, sizeof(timeout)) == EFAULT) { + // Write to user memory failed, this can occur if the timeout is defined in read-only memory. + // This is okay to happen, kernel continues happily. + } + } + + SYSCALL_ERRNO(); +} + +auto _llseek(FEXCore::Core::CpuStateFrame* Frame, uint32_t fd, uint32_t offset_high, uint32_t offset_low, loff_t* result, uint32_t whence) + -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + uint64_t Result = lseek(fd, Offset, whence); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(result, sizeof(*result)); + *result = Result; + // On non-error result, llseek returns zero (As the result is returned in pointer). + return 0; + } + SYSCALL_ERRNO(); +} + +auto readv(FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, int iovcnt) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + uint64_t Result = ::readv(fd, Host_iovec.data(), iovcnt); + SYSCALL_ERRNO(); +} + +auto writev(FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, int iovcnt) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + uint64_t Result = ::writev(fd, Host_iovec.data(), iovcnt); + SYSCALL_ERRNO(); +} + +auto chown32(FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uid_t owner, gid_t group) -> uint64_t { + uint64_t Result = ::chown(pathname, owner, group); + SYSCALL_ERRNO(); +} + +auto lchown32(FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uid_t owner, gid_t group) -> uint64_t { + uint64_t Result = ::lchown(pathname, owner, group); + SYSCALL_ERRNO(); +} + +auto oldstat(FEXCore::Core::CpuStateFrame* Frame, const char* pathname, oldstat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); + if (Result != -1) { + if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { + return -EOVERFLOW; + } + if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { + return -EOVERFLOW; + } + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto oldfstat(FEXCore::Core::CpuStateFrame* Frame, int fd, oldstat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = ::fstat(fd, &host_stat); + if (Result != -1) { + if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { + return -EOVERFLOW; + } + if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { + return -EOVERFLOW; + } + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto oldlstat(FEXCore::Core::CpuStateFrame* Frame, const char* path, oldstat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); + if (Result != -1) { + if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { + return -EOVERFLOW; + } + if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { + return -EOVERFLOW; + } + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto stat(FEXCore::Core::CpuStateFrame* Frame, const char* pathname, stat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto fstat(FEXCore::Core::CpuStateFrame* Frame, int fd, stat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = ::fstat(fd, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto lstat(FEXCore::Core::CpuStateFrame* Frame, const char* path, stat32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto stat64(FEXCore::Core::CpuStateFrame* Frame, const char* pathname, stat64_32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto lstat64(FEXCore::Core::CpuStateFrame* Frame, const char* path, stat64_32* buf) -> uint64_t { + struct stat host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); + + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto fstat64(FEXCore::Core::CpuStateFrame* Frame, int fd, stat64_32* buf) -> uint64_t { + struct stat64 host_stat; + uint64_t Result = ::fstat64(fd, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto statfs(FEXCore::Core::CpuStateFrame* Frame, const char* path, statfs32_32* buf) -> uint64_t { + struct statfs host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto fstatfs(FEXCore::Core::CpuStateFrame* Frame, int fd, statfs32_32* buf) -> uint64_t { + struct statfs host_stat; + uint64_t Result = ::fstatfs(fd, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto fstatfs64(FEXCore::Core::CpuStateFrame* Frame, int fd, size_t sz, struct statfs64_32* buf) -> uint64_t { + LOGMAN_THROW_A_FMT(sz == sizeof(struct statfs64_32), "This needs to match"); + + struct statfs64 host_stat; + uint64_t Result = ::fstatfs64(fd, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto statfs64(FEXCore::Core::CpuStateFrame* Frame, const char* path, size_t sz, struct statfs64_32* buf) -> uint64_t { + LOGMAN_THROW_A_FMT(sz == sizeof(struct statfs64_32), "This needs to match"); + + struct statfs host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, &host_stat); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + + SYSCALL_ERRNO(); +} + +auto dup(FEXCore::Core::CpuStateFrame* Frame, int oldfd) -> uint64_t { + uint64_t Result = ::dup(oldfd); + if (Result != -1) { + CheckAndAddFDDuplication(oldfd, Result); + } + SYSCALL_ERRNO(); +} + +auto dup2(FEXCore::Core::CpuStateFrame* Frame, int oldfd, int newfd) -> uint64_t { + uint64_t Result = ::dup2(oldfd, newfd); + if (Result != -1) { + CheckAndAddFDDuplication(oldfd, newfd); + } + SYSCALL_ERRNO(); +} + +auto preadv(FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, uint32_t pos_high) + -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + + uint64_t Result = ::syscall(SYSCALL_DEF(preadv), fd, Host_iovec.data(), iovcnt, pos_low, pos_high); + SYSCALL_ERRNO(); +} + +auto pwritev(FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, uint32_t pos_high) + -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + + uint64_t Result = ::syscall(SYSCALL_DEF(pwritev), fd, Host_iovec.data(), iovcnt, pos_low, pos_high); + SYSCALL_ERRNO(); +} + +auto process_vm_readv(FEXCore::Core::CpuStateFrame* Frame, pid_t pid, const struct iovec32* local_iov, unsigned long liovcnt, + const struct iovec32* remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(local_iov, sizeof(struct iovec32) * SanitizeIOCount(liovcnt)); + FaultSafeUserMemAccess::VerifyIsReadable(remote_iov, sizeof(struct iovec32) * SanitizeIOCount(riovcnt)); + + fextl::vector Host_local_iovec(local_iov, local_iov + SanitizeIOCount(liovcnt)); + fextl::vector Host_remote_iovec(remote_iov, remote_iov + SanitizeIOCount(riovcnt)); + + uint64_t Result = ::process_vm_readv(pid, Host_local_iovec.data(), liovcnt, Host_remote_iovec.data(), riovcnt, flags); + SYSCALL_ERRNO(); +} + +auto process_vm_writev(FEXCore::Core::CpuStateFrame* Frame, pid_t pid, const struct iovec32* local_iov, unsigned long liovcnt, + const struct iovec32* remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(local_iov, sizeof(struct iovec32) * SanitizeIOCount(liovcnt)); + FaultSafeUserMemAccess::VerifyIsReadable(remote_iov, sizeof(struct iovec32) * SanitizeIOCount(riovcnt)); + + fextl::vector Host_local_iovec(local_iov, local_iov + SanitizeIOCount(liovcnt)); + fextl::vector Host_remote_iovec(remote_iov, remote_iov + SanitizeIOCount(riovcnt)); + + uint64_t Result = ::process_vm_writev(pid, Host_local_iovec.data(), liovcnt, Host_remote_iovec.data(), riovcnt, flags); + SYSCALL_ERRNO(); +} + +auto preadv2(FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, uint32_t pos_high, + int flags) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + + uint64_t Result = ::syscall(SYSCALL_DEF(preadv2), fd, Host_iovec.data(), iovcnt, pos_low, pos_high, flags); + SYSCALL_ERRNO(); +} + +auto pwritev2(FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, uint32_t pos_high, + int flags) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); + fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); + + uint64_t Result = ::syscall(SYSCALL_DEF(pwritev2), fd, Host_iovec.data(), iovcnt, pos_low, pos_high, flags); + SYSCALL_ERRNO(); +} + +auto fstatat_64(FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, stat64_32* buf, int flag) -> uint64_t { + struct stat64 host_stat; + uint64_t Result = FEX::HLE::_SyscallHandler->FM.NewFSStatAt64(dirfd, pathname, &host_stat, flag); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = host_stat; + } + SYSCALL_ERRNO(); +} + +auto getdents(FEXCore::Core::CpuStateFrame* Frame, int fd, void* dirp, uint32_t count) -> uint64_t { + return GetDentsEmulation(fd, reinterpret_cast(dirp), count); +} + +auto getdents64(FEXCore::Core::CpuStateFrame* Frame, int fd, void* dirp, uint32_t count) -> uint64_t { + uint64_t Result = ::syscall(SYSCALL_DEF(getdents64), static_cast(fd), dirp, static_cast(count)); + if (Result != -1) { + // Walk each offset + // if we are passing the full d_off to the 32bit application then it seems to break things? + for (size_t i = 0, num = 0; i < Result; ++num) { + linux_dirent_64* Incoming = (linux_dirent_64*)(reinterpret_cast(dirp) + i); + Incoming->d_off = num; + if (FEX::HLE::_SyscallHandler->FM.IsProtectedFile(fd, Incoming->d_ino)) { + Result -= Incoming->d_reclen; + memmove(Incoming, (linux_dirent_64*)(reinterpret_cast(Incoming) + Incoming->d_reclen), Result - i); + continue; + } + i += Incoming->d_reclen; + } + } + SYSCALL_ERRNO(); +} + +auto select(FEXCore::Core::CpuStateFrame* Frame, compat_select_args* arg) -> uint64_t { + return selectHandler(Frame, arg->nfds, arg->readfds, arg->writefds, arg->exceptfds, arg->timeout); +} + +auto pselect6(FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* readfds, fd_set32* writefds, fd_set32* exceptfds, + timespec32* timeout, compat_ptr sigmaskpack) -> uint64_t { + struct timespec tp64 {}; + if (timeout) { + FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); + tp64 = *timeout; + } + + fd_set Host_readfds; + fd_set Host_writefds; + fd_set Host_exceptfds; + sigset_t HostSet {}; + + FD_ZERO(&Host_readfds); + FD_ZERO(&Host_writefds); + FD_ZERO(&Host_exceptfds); + sigemptyset(&HostSet); + + // Round up to the full 32bit word + uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; + + if (readfds) { + FaultSafeUserMemAccess::VerifyIsReadable(readfds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = readfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_readfds); + } + } + } + } + + if (writefds) { + FaultSafeUserMemAccess::VerifyIsReadable(writefds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = writefds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_writefds); + } + } + } + } + + if (exceptfds) { + FaultSafeUserMemAccess::VerifyIsReadable(exceptfds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = exceptfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_exceptfds); + } + } + } + } + + FaultSafeUserMemAccess::VerifyIsReadableOrNull(sigmaskpack, sizeof(*sigmaskpack)); + if (sigmaskpack && sigmaskpack->sigset) { + FaultSafeUserMemAccess::VerifyIsReadable(sigmaskpack->sigset, sizeof(*sigmaskpack->sigset)); + uint64_t* sigmask = sigmaskpack->sigset; + size_t sigsetsize = sigmaskpack->size; + for (int32_t i = 0; i < (sigsetsize * 8); ++i) { + if (*sigmask & (1ULL << i)) { + sigaddset(&HostSet, i + 1); + } + } + } + + uint64_t Result = ::pselect(nfds, readfds ? &Host_readfds : nullptr, writefds ? &Host_writefds : nullptr, + exceptfds ? &Host_exceptfds : nullptr, timeout ? &tp64 : nullptr, &HostSet); + + if (readfds) { + FaultSafeUserMemAccess::VerifyIsWritable(readfds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_readfds)) { + readfds[i / 32] |= 1 << (i & 31); + } else { + readfds[i / 32] &= ~(1 << (i & 31)); } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(readv, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, int iovcnt) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - uint64_t Result = ::readv(fd, Host_iovec.data(), iovcnt); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(writev, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, int iovcnt) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - uint64_t Result = ::writev(fd, Host_iovec.data(), iovcnt); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(chown32, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uid_t owner, gid_t group) -> uint64_t { - uint64_t Result = ::chown(pathname, owner, group); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(lchown32, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uid_t owner, gid_t group) -> uint64_t { - uint64_t Result = ::lchown(pathname, owner, group); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(oldstat, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, oldstat32* buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); - if (Result != -1) { - if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { - return -EOVERFLOW; + } + } + + if (writefds) { + FaultSafeUserMemAccess::VerifyIsWritable(writefds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_writefds)) { + writefds[i / 32] |= 1 << (i & 31); + } else { + writefds[i / 32] &= ~(1 << (i & 31)); } - if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { - return -EOVERFLOW; + } + } + + if (exceptfds) { + FaultSafeUserMemAccess::VerifyIsWritable(exceptfds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_exceptfds)) { + exceptfds[i / 32] |= 1 << (i & 31); + } else { + exceptfds[i / 32] &= ~(1 << (i & 31)); + } + } + } + + if (timeout) { + FaultSafeUserMemAccess::VerifyIsWritable(timeout, sizeof(*timeout)); + *timeout = tp64; + } + SYSCALL_ERRNO(); +} + +auto fadvise64(FEXCore::Core::CpuStateFrame* Frame, int32_t fd, uint32_t offset_low, uint32_t offset_high, uint32_t len, int advice) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + uint64_t Result = ::posix_fadvise64(fd, Offset, len, advice); + SYSCALL_ERRNO(); +} + +auto fadvise64_64(FEXCore::Core::CpuStateFrame* Frame, int32_t fd, uint32_t offset_low, uint32_t offset_high, uint32_t len_low, + uint32_t len_high, int advice) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + uint64_t Len = len_high; + Len <<= 32; + Len |= len_low; + uint64_t Result = ::posix_fadvise64(fd, Offset, Len, advice); + SYSCALL_ERRNO(); +} + +auto timerfd_settime(FEXCore::Core::CpuStateFrame* Frame, int fd, int flags, const FEX::HLE::x32::old_itimerspec32* new_value, + FEX::HLE::x32::old_itimerspec32* old_value) -> uint64_t { + struct itimerspec new_value_host {}; + struct itimerspec old_value_host {}; + struct itimerspec* old_value_host_p {}; + + new_value_host = *new_value; + if (old_value) { + FaultSafeUserMemAccess::VerifyIsReadable(old_value, sizeof(*old_value)); + old_value_host_p = &old_value_host; + } + + // Flags don't need remapped + uint64_t Result = ::timerfd_settime(fd, flags, &new_value_host, old_value_host_p); + + if (Result != -1 && old_value) { + FaultSafeUserMemAccess::VerifyIsWritable(old_value, sizeof(*old_value)); + *old_value = old_value_host; + } + SYSCALL_ERRNO(); +} + +auto timerfd_gettime(FEXCore::Core::CpuStateFrame* Frame, int fd, FEX::HLE::x32::old_itimerspec32* curr_value) -> uint64_t { + struct itimerspec Host {}; + + uint64_t Result = ::timerfd_gettime(fd, &Host); + + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(curr_value, sizeof(*curr_value)); + *curr_value = Host; + } + + SYSCALL_ERRNO(); +} + +auto pselect6_time64(FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* readfds, fd_set32* writefds, fd_set32* exceptfds, + struct timespec* timeout, compat_ptr sigmaskpack) -> uint64_t { + fd_set Host_readfds; + fd_set Host_writefds; + fd_set Host_exceptfds; + sigset_t HostSet {}; + + FD_ZERO(&Host_readfds); + FD_ZERO(&Host_writefds); + FD_ZERO(&Host_exceptfds); + sigemptyset(&HostSet); + + // Round up to the full 32bit word + uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; + + if (readfds) { + FaultSafeUserMemAccess::VerifyIsReadable(readfds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = readfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_readfds); + } } - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + } + } - *buf = host_stat; + if (writefds) { + FaultSafeUserMemAccess::VerifyIsReadable(writefds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = writefds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_writefds); + } + } } - SYSCALL_ERRNO(); - }); + } - REGISTER_SYSCALL_IMPL_X32(oldfstat, [](FEXCore::Core::CpuStateFrame* Frame, int fd, oldstat32* buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = ::fstat(fd, &host_stat); - if (Result != -1) { - if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { - return -EOVERFLOW; + if (exceptfds) { + FaultSafeUserMemAccess::VerifyIsReadable(exceptfds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < NumWords; ++i) { + uint32_t FD = exceptfds[i]; + int32_t Rem = nfds - (i * 32); + for (int j = 0; j < 32 && j < Rem; ++j) { + if ((FD >> j) & 1) { + FD_SET(i * 32 + j, &Host_exceptfds); + } } - if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { - return -EOVERFLOW; + } + } + + FaultSafeUserMemAccess::VerifyIsReadableOrNull(sigmaskpack, sizeof(*sigmaskpack)); + if (sigmaskpack && sigmaskpack->sigset) { + FaultSafeUserMemAccess::VerifyIsReadable(sigmaskpack->sigset, sizeof(*sigmaskpack->sigset)); + uint64_t* sigmask = sigmaskpack->sigset; + size_t sigsetsize = sigmaskpack->size; + for (int32_t i = 0; i < (sigsetsize * 8); ++i) { + if (*sigmask & (1ULL << i)) { + sigaddset(&HostSet, i + 1); } - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + } + } - *buf = host_stat; + uint64_t Result = ::pselect(nfds, readfds ? &Host_readfds : nullptr, writefds ? &Host_writefds : nullptr, + exceptfds ? &Host_exceptfds : nullptr, timeout, &HostSet); + + if (readfds) { + FaultSafeUserMemAccess::VerifyIsWritable(readfds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_readfds)) { + readfds[i / 32] |= 1 << (i & 31); + } else { + readfds[i / 32] &= ~(1 << (i & 31)); + } } - SYSCALL_ERRNO(); - }); + } - REGISTER_SYSCALL_IMPL_X32(oldlstat, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, oldstat32* buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); - if (Result != -1) { - if (host_stat.st_ino > std::numeric_limitsst_ino)>::max()) { - return -EOVERFLOW; + if (writefds) { + FaultSafeUserMemAccess::VerifyIsWritable(writefds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_writefds)) { + writefds[i / 32] |= 1 << (i & 31); + } else { + writefds[i / 32] &= ~(1 << (i & 31)); } - if (host_stat.st_nlink > std::numeric_limitsst_nlink)>::max()) { - return -EOVERFLOW; + } + } + + if (exceptfds) { + FaultSafeUserMemAccess::VerifyIsWritable(exceptfds, sizeof(fd_set32) * NumWords); + for (int i = 0; i < nfds; ++i) { + if (FD_ISSET(i, &Host_exceptfds)) { + exceptfds[i / 32] |= 1 << (i & 31); + } else { + exceptfds[i / 32] &= ~(1 << (i & 31)); } - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(stat, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, stat32* buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstat, [](FEXCore::Core::CpuStateFrame* Frame, int fd, stat32* buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = ::fstat(fd, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(lstat, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, stat32* buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(stat64, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, stat64_32* buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(lstat64, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, stat64_32* buf) -> uint64_t { - struct stat host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Lstat(path, &host_stat); - - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstat64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, stat64_32* buf) -> uint64_t { - struct stat64 host_stat; - uint64_t Result = ::fstat64(fd, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(statfs, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, statfs32_32* buf) -> uint64_t { - struct statfs host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstatfs, [](FEXCore::Core::CpuStateFrame* Frame, int fd, statfs32_32* buf) -> uint64_t { - struct statfs host_stat; - uint64_t Result = ::fstatfs(fd, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstatfs64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, size_t sz, struct statfs64_32* buf) -> uint64_t { - LOGMAN_THROW_A_FMT(sz == sizeof(struct statfs64_32), "This needs to match"); - - struct statfs64 host_stat; - uint64_t Result = ::fstatfs64(fd, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(statfs64, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, size_t sz, struct statfs64_32* buf) -> uint64_t { - LOGMAN_THROW_A_FMT(sz == sizeof(struct statfs64_32), "This needs to match"); - - struct statfs host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, &host_stat); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - - SYSCALL_ERRNO(); - }); + } + } + + SYSCALL_ERRNO(); +} + +auto sendfile(FEXCore::Core::CpuStateFrame* Frame, int out_fd, int in_fd, compat_off_t* offset, size_t count) -> uint64_t { + off_t Local {}; + off_t* Local_p {}; + if (offset) { + Local_p = &Local; + Local = *offset; + } + uint64_t Result = ::sendfile(out_fd, in_fd, Local_p, count); + SYSCALL_ERRNO(); +} + +auto pread_64(FEXCore::Core::CpuStateFrame* Frame, int fd, void* buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + + uint64_t Result = ::pread64(fd, buf, count, Offset); + SYSCALL_ERRNO(); +} + +auto pwrite_64(FEXCore::Core::CpuStateFrame* Frame, int fd, void* buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + + uint64_t Result = ::pwrite64(fd, buf, count, Offset); + SYSCALL_ERRNO(); +} + +auto readahead(FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint64_t offset_high, size_t count) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + + uint64_t Result = ::readahead(fd, Offset, count); + SYSCALL_ERRNO(); +} + +auto sync_file_range(FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint32_t offset_high, uint32_t len_low, + uint32_t len_high, unsigned int flags) -> uint64_t { + // Flags don't need remapped + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + + uint64_t Len = len_high; + Len <<= 32; + Len |= len_low; + + uint64_t Result = ::syscall(SYSCALL_DEF(sync_file_range), fd, Offset, Len, flags); + SYSCALL_ERRNO(); +} + +auto fallocate(FEXCore::Core::CpuStateFrame* Frame, int fd, int mode, uint32_t offset_low, uint32_t offset_high, uint32_t len_low, + uint32_t len_high) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + + uint64_t Len = len_high; + Len <<= 32; + Len |= len_low; + + uint64_t Result = ::fallocate(fd, mode, Offset, Len); + SYSCALL_ERRNO(); +} + +auto vmsplice(FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, unsigned long nr_segs, unsigned int flags) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(nr_segs)); + fextl::vector Host_iovec(iov, iov + nr_segs); + uint64_t Result = ::vmsplice(fd, Host_iovec.data(), nr_segs, flags); + SYSCALL_ERRNO(); +} + + +void RegisterFD(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(ppoll, ppoll); + REGISTER_SYSCALL_IMPL_X32(_llseek, _llseek); + REGISTER_SYSCALL_IMPL_X32(readv, readv); + REGISTER_SYSCALL_IMPL_X32(writev, writev); + REGISTER_SYSCALL_IMPL_X32(chown32, chown32); + REGISTER_SYSCALL_IMPL_X32(lchown32, lchown32); + REGISTER_SYSCALL_IMPL_X32(oldstat, oldstat); + REGISTER_SYSCALL_IMPL_X32(oldfstat, oldfstat); + REGISTER_SYSCALL_IMPL_X32(oldlstat, oldlstat); + REGISTER_SYSCALL_IMPL_X32(stat, stat); + REGISTER_SYSCALL_IMPL_X32(fstat, fstat); + REGISTER_SYSCALL_IMPL_X32(lstat, lstat); + REGISTER_SYSCALL_IMPL_X32(stat64, stat64); + REGISTER_SYSCALL_IMPL_X32(lstat64, lstat64); + REGISTER_SYSCALL_IMPL_X32(fstat64, fstat64); + REGISTER_SYSCALL_IMPL_X32(statfs, statfs); + REGISTER_SYSCALL_IMPL_X32(fstatfs, fstatfs); + REGISTER_SYSCALL_IMPL_X32(fstatfs64, fstatfs64); + REGISTER_SYSCALL_IMPL_X32(statfs64, statfs64); // x86 32-bit fcntl syscall has a historical quirk that it uses the same handler as fcntl64 // This is in direct opposition to all other 32-bit architectures that use the compat_fcntl handler @@ -505,488 +987,32 @@ void RegisterFD(FEX::HLE::SyscallHandler* Handler) { REGISTER_SYSCALL_IMPL_X32(fcntl, fcntl32Handler); REGISTER_SYSCALL_IMPL_X32(fcntl64, fcntlHandler); - - REGISTER_SYSCALL_IMPL_X32(dup, [](FEXCore::Core::CpuStateFrame* Frame, int oldfd) -> uint64_t { - uint64_t Result = ::dup(oldfd); - if (Result != -1) { - CheckAndAddFDDuplication(oldfd, Result); - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(dup2, [](FEXCore::Core::CpuStateFrame* Frame, int oldfd, int newfd) -> uint64_t { - uint64_t Result = ::dup2(oldfd, newfd); - if (Result != -1) { - CheckAndAddFDDuplication(oldfd, newfd); - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - preadv, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, uint32_t pos_high) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - - uint64_t Result = ::syscall(SYSCALL_DEF(preadv), fd, Host_iovec.data(), iovcnt, pos_low, pos_high); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - pwritev, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, uint32_t pos_high) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - - uint64_t Result = ::syscall(SYSCALL_DEF(pwritev), fd, Host_iovec.data(), iovcnt, pos_low, pos_high); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(process_vm_readv, - [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, const struct iovec32* local_iov, unsigned long liovcnt, - const struct iovec32* remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(local_iov, sizeof(struct iovec32) * SanitizeIOCount(liovcnt)); - FaultSafeUserMemAccess::VerifyIsReadable(remote_iov, sizeof(struct iovec32) * SanitizeIOCount(riovcnt)); - - fextl::vector Host_local_iovec(local_iov, local_iov + SanitizeIOCount(liovcnt)); - fextl::vector Host_remote_iovec(remote_iov, remote_iov + SanitizeIOCount(riovcnt)); - - uint64_t Result = - ::process_vm_readv(pid, Host_local_iovec.data(), liovcnt, Host_remote_iovec.data(), riovcnt, flags); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(process_vm_writev, - [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, const struct iovec32* local_iov, unsigned long liovcnt, - const struct iovec32* remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(local_iov, sizeof(struct iovec32) * SanitizeIOCount(liovcnt)); - FaultSafeUserMemAccess::VerifyIsReadable(remote_iov, sizeof(struct iovec32) * SanitizeIOCount(riovcnt)); - - fextl::vector Host_local_iovec(local_iov, local_iov + SanitizeIOCount(liovcnt)); - fextl::vector Host_remote_iovec(remote_iov, remote_iov + SanitizeIOCount(riovcnt)); - - uint64_t Result = - ::process_vm_writev(pid, Host_local_iovec.data(), liovcnt, Host_remote_iovec.data(), riovcnt, flags); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(preadv2, - [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, - uint32_t pos_high, int flags) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - - uint64_t Result = ::syscall(SYSCALL_DEF(preadv2), fd, Host_iovec.data(), iovcnt, pos_low, pos_high, flags); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(pwritev2, - [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, uint32_t iovcnt, uint32_t pos_low, - uint32_t pos_high, int flags) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(iovcnt)); - fextl::vector Host_iovec(iov, iov + SanitizeIOCount(iovcnt)); - - uint64_t Result = ::syscall(SYSCALL_DEF(pwritev2), fd, Host_iovec.data(), iovcnt, pos_low, pos_high, flags); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fstatat_64, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, stat64_32* buf, int flag) -> uint64_t { - struct stat64 host_stat; - uint64_t Result = FEX::HLE::_SyscallHandler->FM.NewFSStatAt64(dirfd, pathname, &host_stat, flag); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = host_stat; - } - SYSCALL_ERRNO(); - }); - + REGISTER_SYSCALL_IMPL_X32(dup, dup); + REGISTER_SYSCALL_IMPL_X32(dup2, dup2); + REGISTER_SYSCALL_IMPL_X32(preadv, preadv); + REGISTER_SYSCALL_IMPL_X32(pwritev, pwritev); + REGISTER_SYSCALL_IMPL_X32(process_vm_readv, process_vm_readv); + REGISTER_SYSCALL_IMPL_X32(process_vm_writev, process_vm_writev); + REGISTER_SYSCALL_IMPL_X32(preadv2, preadv2); + REGISTER_SYSCALL_IMPL_X32(pwritev2, pwritev2); + REGISTER_SYSCALL_IMPL_X32(fstatat_64, fstatat_64); REGISTER_SYSCALL_IMPL_X32(ioctl, ioctl32); - - REGISTER_SYSCALL_IMPL_X32(getdents, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* dirp, uint32_t count) -> uint64_t { - return GetDentsEmulation(fd, reinterpret_cast(dirp), count); - }); - - REGISTER_SYSCALL_IMPL_X32(getdents64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* dirp, uint32_t count) -> uint64_t { - uint64_t Result = ::syscall(SYSCALL_DEF(getdents64), static_cast(fd), dirp, static_cast(count)); - if (Result != -1) { - // Walk each offset - // if we are passing the full d_off to the 32bit application then it seems to break things? - for (size_t i = 0, num = 0; i < Result; ++num) { - linux_dirent_64* Incoming = (linux_dirent_64*)(reinterpret_cast(dirp) + i); - Incoming->d_off = num; - if (FEX::HLE::_SyscallHandler->FM.IsProtectedFile(fd, Incoming->d_ino)) { - Result -= Incoming->d_reclen; - memmove(Incoming, (linux_dirent_64*)(reinterpret_cast(Incoming) + Incoming->d_reclen), Result - i); - continue; - } - i += Incoming->d_reclen; - } - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(select, [](FEXCore::Core::CpuStateFrame* Frame, compat_select_args* arg) -> uint64_t { - return selectHandler(Frame, arg->nfds, arg->readfds, arg->writefds, arg->exceptfds, arg->timeout); - }); - + REGISTER_SYSCALL_IMPL_X32(getdents, getdents); + REGISTER_SYSCALL_IMPL_X32(getdents64, getdents64); + REGISTER_SYSCALL_IMPL_X32(select, select); REGISTER_SYSCALL_IMPL_X32(_newselect, selectHandler); - - REGISTER_SYSCALL_IMPL_X32(pselect6, - [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* readfds, fd_set32* writefds, fd_set32* exceptfds, - timespec32* timeout, compat_ptr sigmaskpack) -> uint64_t { - struct timespec tp64 {}; - if (timeout) { - FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); - tp64 = *timeout; - } - - fd_set Host_readfds; - fd_set Host_writefds; - fd_set Host_exceptfds; - sigset_t HostSet {}; - - FD_ZERO(&Host_readfds); - FD_ZERO(&Host_writefds); - FD_ZERO(&Host_exceptfds); - sigemptyset(&HostSet); - - // Round up to the full 32bit word - uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; - - if (readfds) { - FaultSafeUserMemAccess::VerifyIsReadable(readfds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = readfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_readfds); - } - } - } - } - - if (writefds) { - FaultSafeUserMemAccess::VerifyIsReadable(writefds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = writefds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_writefds); - } - } - } - } - - if (exceptfds) { - FaultSafeUserMemAccess::VerifyIsReadable(exceptfds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = exceptfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_exceptfds); - } - } - } - } - - FaultSafeUserMemAccess::VerifyIsReadableOrNull(sigmaskpack, sizeof(*sigmaskpack)); - if (sigmaskpack && sigmaskpack->sigset) { - FaultSafeUserMemAccess::VerifyIsReadable(sigmaskpack->sigset, sizeof(*sigmaskpack->sigset)); - uint64_t* sigmask = sigmaskpack->sigset; - size_t sigsetsize = sigmaskpack->size; - for (int32_t i = 0; i < (sigsetsize * 8); ++i) { - if (*sigmask & (1ULL << i)) { - sigaddset(&HostSet, i + 1); - } - } - } - - uint64_t Result = ::pselect(nfds, readfds ? &Host_readfds : nullptr, writefds ? &Host_writefds : nullptr, - exceptfds ? &Host_exceptfds : nullptr, timeout ? &tp64 : nullptr, &HostSet); - - if (readfds) { - FaultSafeUserMemAccess::VerifyIsWritable(readfds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_readfds)) { - readfds[i / 32] |= 1 << (i & 31); - } else { - readfds[i / 32] &= ~(1 << (i & 31)); - } - } - } - - if (writefds) { - FaultSafeUserMemAccess::VerifyIsWritable(writefds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_writefds)) { - writefds[i / 32] |= 1 << (i & 31); - } else { - writefds[i / 32] &= ~(1 << (i & 31)); - } - } - } - - if (exceptfds) { - FaultSafeUserMemAccess::VerifyIsWritable(exceptfds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_exceptfds)) { - exceptfds[i / 32] |= 1 << (i & 31); - } else { - exceptfds[i / 32] &= ~(1 << (i & 31)); - } - } - } - - if (timeout) { - FaultSafeUserMemAccess::VerifyIsWritable(timeout, sizeof(*timeout)); - *timeout = tp64; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - fadvise64, [](FEXCore::Core::CpuStateFrame* Frame, int32_t fd, uint32_t offset_low, uint32_t offset_high, uint32_t len, int advice) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - uint64_t Result = ::posix_fadvise64(fd, Offset, len, advice); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fadvise64_64, - [](FEXCore::Core::CpuStateFrame* Frame, int32_t fd, uint32_t offset_low, uint32_t offset_high, uint32_t len_low, - uint32_t len_high, int advice) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - uint64_t Len = len_high; - Len <<= 32; - Len |= len_low; - uint64_t Result = ::posix_fadvise64(fd, Offset, Len, advice); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(timerfd_settime, - [](FEXCore::Core::CpuStateFrame* Frame, int fd, int flags, const FEX::HLE::x32::old_itimerspec32* new_value, - FEX::HLE::x32::old_itimerspec32* old_value) -> uint64_t { - struct itimerspec new_value_host {}; - struct itimerspec old_value_host {}; - struct itimerspec* old_value_host_p {}; - - new_value_host = *new_value; - if (old_value) { - FaultSafeUserMemAccess::VerifyIsReadable(old_value, sizeof(*old_value)); - old_value_host_p = &old_value_host; - } - - // Flags don't need remapped - uint64_t Result = ::timerfd_settime(fd, flags, &new_value_host, old_value_host_p); - - if (Result != -1 && old_value) { - FaultSafeUserMemAccess::VerifyIsWritable(old_value, sizeof(*old_value)); - *old_value = old_value_host; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(timerfd_gettime, [](FEXCore::Core::CpuStateFrame* Frame, int fd, FEX::HLE::x32::old_itimerspec32* curr_value) -> uint64_t { - struct itimerspec Host {}; - - uint64_t Result = ::timerfd_gettime(fd, &Host); - - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(curr_value, sizeof(*curr_value)); - *curr_value = Host; - } - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(pselect6_time64, - [](FEXCore::Core::CpuStateFrame* Frame, int nfds, fd_set32* readfds, fd_set32* writefds, fd_set32* exceptfds, - struct timespec* timeout, compat_ptr sigmaskpack) -> uint64_t { - fd_set Host_readfds; - fd_set Host_writefds; - fd_set Host_exceptfds; - sigset_t HostSet {}; - - FD_ZERO(&Host_readfds); - FD_ZERO(&Host_writefds); - FD_ZERO(&Host_exceptfds); - sigemptyset(&HostSet); - - // Round up to the full 32bit word - uint32_t NumWords = FEXCore::AlignUp(nfds, 32) / 4; - - if (readfds) { - FaultSafeUserMemAccess::VerifyIsReadable(readfds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = readfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_readfds); - } - } - } - } - - if (writefds) { - FaultSafeUserMemAccess::VerifyIsReadable(writefds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = writefds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_writefds); - } - } - } - } - - if (exceptfds) { - FaultSafeUserMemAccess::VerifyIsReadable(exceptfds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < NumWords; ++i) { - uint32_t FD = exceptfds[i]; - int32_t Rem = nfds - (i * 32); - for (int j = 0; j < 32 && j < Rem; ++j) { - if ((FD >> j) & 1) { - FD_SET(i * 32 + j, &Host_exceptfds); - } - } - } - } - - FaultSafeUserMemAccess::VerifyIsReadableOrNull(sigmaskpack, sizeof(*sigmaskpack)); - if (sigmaskpack && sigmaskpack->sigset) { - FaultSafeUserMemAccess::VerifyIsReadable(sigmaskpack->sigset, sizeof(*sigmaskpack->sigset)); - uint64_t* sigmask = sigmaskpack->sigset; - size_t sigsetsize = sigmaskpack->size; - for (int32_t i = 0; i < (sigsetsize * 8); ++i) { - if (*sigmask & (1ULL << i)) { - sigaddset(&HostSet, i + 1); - } - } - } - - uint64_t Result = ::pselect(nfds, readfds ? &Host_readfds : nullptr, writefds ? &Host_writefds : nullptr, - exceptfds ? &Host_exceptfds : nullptr, timeout, &HostSet); - - if (readfds) { - FaultSafeUserMemAccess::VerifyIsWritable(readfds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_readfds)) { - readfds[i / 32] |= 1 << (i & 31); - } else { - readfds[i / 32] &= ~(1 << (i & 31)); - } - } - } - - if (writefds) { - FaultSafeUserMemAccess::VerifyIsWritable(writefds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_writefds)) { - writefds[i / 32] |= 1 << (i & 31); - } else { - writefds[i / 32] &= ~(1 << (i & 31)); - } - } - } - - if (exceptfds) { - FaultSafeUserMemAccess::VerifyIsWritable(exceptfds, sizeof(fd_set32) * NumWords); - for (int i = 0; i < nfds; ++i) { - if (FD_ISSET(i, &Host_exceptfds)) { - exceptfds[i / 32] |= 1 << (i & 31); - } else { - exceptfds[i / 32] &= ~(1 << (i & 31)); - } - } - } - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(sendfile, [](FEXCore::Core::CpuStateFrame* Frame, int out_fd, int in_fd, compat_off_t* offset, size_t count) -> uint64_t { - off_t Local {}; - off_t* Local_p {}; - if (offset) { - Local_p = &Local; - Local = *offset; - } - uint64_t Result = ::sendfile(out_fd, in_fd, Local_p, count); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - pread_64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - - uint64_t Result = ::pread64(fd, buf, count, Offset); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - pwrite_64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, void* buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - - uint64_t Result = ::pwrite64(fd, buf, count, Offset); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - readahead, [](FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint64_t offset_high, size_t count) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - - uint64_t Result = ::readahead(fd, Offset, count); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(sync_file_range, - [](FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint32_t offset_high, uint32_t len_low, - uint32_t len_high, unsigned int flags) -> uint64_t { - // Flags don't need remapped - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - - uint64_t Len = len_high; - Len <<= 32; - Len |= len_low; - - uint64_t Result = ::syscall(SYSCALL_DEF(sync_file_range), fd, Offset, Len, flags); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(fallocate, - [](FEXCore::Core::CpuStateFrame* Frame, int fd, int mode, uint32_t offset_low, uint32_t offset_high, - uint32_t len_low, uint32_t len_high) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - - uint64_t Len = len_high; - Len <<= 32; - Len |= len_low; - - uint64_t Result = ::fallocate(fd, mode, Offset, Len); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - vmsplice, [](FEXCore::Core::CpuStateFrame* Frame, int fd, const struct iovec32* iov, unsigned long nr_segs, unsigned int flags) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(iov, sizeof(struct iovec32) * SanitizeIOCount(nr_segs)); - fextl::vector Host_iovec(iov, iov + nr_segs); - uint64_t Result = ::vmsplice(fd, Host_iovec.data(), nr_segs, flags); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(pselect6, pselect6); + REGISTER_SYSCALL_IMPL_X32(fadvise64, fadvise64); + REGISTER_SYSCALL_IMPL_X32(fadvise64_64, fadvise64_64); + REGISTER_SYSCALL_IMPL_X32(timerfd_settime, timerfd_settime); + REGISTER_SYSCALL_IMPL_X32(timerfd_gettime, timerfd_gettime); + REGISTER_SYSCALL_IMPL_X32(pselect6_time64, pselect6_time64); + REGISTER_SYSCALL_IMPL_X32(sendfile, sendfile); + REGISTER_SYSCALL_IMPL_X32(pread_64, pread_64); + REGISTER_SYSCALL_IMPL_X32(pwrite_64, pwrite_64); + REGISTER_SYSCALL_IMPL_X32(readahead, readahead); + REGISTER_SYSCALL_IMPL_X32(sync_file_range, sync_file_range); + REGISTER_SYSCALL_IMPL_X32(fallocate, fallocate); + REGISTER_SYSCALL_IMPL_X32(vmsplice, vmsplice); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp index fd29cf589c..7e61587164 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/FS.cpp @@ -15,33 +15,37 @@ tags: LinuxSyscalls|syscalls-x86-32 #include namespace FEX::HLE::x32 { + +auto umount(FEXCore::Core::CpuStateFrame* Frame, const char* target) -> uint64_t { + uint64_t Result = ::umount(target); + SYSCALL_ERRNO(); +} + +auto truncate64(FEXCore::Core::CpuStateFrame* Frame, const char* path, uint32_t offset_low, uint32_t offset_high) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + uint64_t Result = ::truncate(path, Offset); + SYSCALL_ERRNO(); +} + +auto ftruncate64(FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint32_t offset_high) -> uint64_t { + uint64_t Offset = offset_high; + Offset <<= 32; + Offset |= offset_low; + uint64_t Result = ::ftruncate(fd, Offset); + SYSCALL_ERRNO(); +} + +auto sigprocmask(FEXCore::Core::CpuStateFrame* Frame, int how, const uint64_t* set, uint64_t* oldset, size_t sigsetsize) -> uint64_t { + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), how, + set, oldset); +} + void RegisterFS(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(umount, [](FEXCore::Core::CpuStateFrame* Frame, const char* target) -> uint64_t { - uint64_t Result = ::umount(target); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - truncate64, [](FEXCore::Core::CpuStateFrame* Frame, const char* path, uint32_t offset_low, uint32_t offset_high) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - uint64_t Result = ::truncate(path, Offset); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(ftruncate64, [](FEXCore::Core::CpuStateFrame* Frame, int fd, uint32_t offset_low, uint32_t offset_high) -> uint64_t { - uint64_t Offset = offset_high; - Offset <<= 32; - Offset |= offset_low; - uint64_t Result = ::ftruncate(fd, Offset); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - sigprocmask, [](FEXCore::Core::CpuStateFrame* Frame, int how, const uint64_t* set, uint64_t* oldset, size_t sigsetsize) -> uint64_t { - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), - how, set, oldset); - }); + REGISTER_SYSCALL_IMPL_X32(umount, umount); + REGISTER_SYSCALL_IMPL_X32(truncate64, truncate64); + REGISTER_SYSCALL_IMPL_X32(ftruncate64, ftruncate64); + REGISTER_SYSCALL_IMPL_X32(sigprocmask, sigprocmask); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IO.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IO.cpp index be5d8fe9f2..41dc18d2a2 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IO.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/IO.cpp @@ -16,35 +16,35 @@ tags: LinuxSyscalls|syscalls-x86-32 #include namespace FEX::HLE::x32 { -void RegisterIO(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(io_getevents, - [](FEXCore::Core::CpuStateFrame* Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event* events, - struct timespec32* timeout) -> uint64_t { - struct timespec* timeout_ptr {}; - struct timespec tp64 {}; - if (timeout) { - FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); - tp64 = *timeout; - timeout_ptr = &tp64; - } +auto io_getevents(FEXCore::Core::CpuStateFrame* Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event* events, + struct timespec32* timeout) -> uint64_t { + struct timespec* timeout_ptr {}; + struct timespec tp64 {}; + if (timeout) { + FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); + tp64 = *timeout; + timeout_ptr = &tp64; + } - uint64_t Result = ::syscall(SYSCALL_DEF(io_getevents), ctx_id, min_nr, nr, events, timeout_ptr); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::syscall(SYSCALL_DEF(io_getevents), ctx_id, min_nr, nr, events, timeout_ptr); + SYSCALL_ERRNO(); +} - REGISTER_SYSCALL_IMPL_X32(io_pgetevents, - [](FEXCore::Core::CpuStateFrame* Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event* events, - struct timespec32* timeout, const struct io_sigset* usig) -> uint64_t { - struct timespec* timeout_ptr {}; - struct timespec tp64 {}; - if (timeout) { - FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); - tp64 = *timeout; - timeout_ptr = &tp64; - } +auto io_pgetevents(FEXCore::Core::CpuStateFrame* Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event* events, + struct timespec32* timeout, const struct io_sigset* usig) -> uint64_t { + struct timespec* timeout_ptr {}; + struct timespec tp64 {}; + if (timeout) { + FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); + tp64 = *timeout; + timeout_ptr = &tp64; + } - uint64_t Result = ::syscall(SYSCALL_DEF(io_pgetevents), ctx_id, min_nr, nr, events, timeout_ptr, usig); - SYSCALL_ERRNO(); - }); + uint64_t Result = ::syscall(SYSCALL_DEF(io_pgetevents), ctx_id, min_nr, nr, events, timeout_ptr, usig); + SYSCALL_ERRNO(); +} +void RegisterIO(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(io_getevents, io_getevents); + REGISTER_SYSCALL_IMPL_X32(io_pgetevents, io_pgetevents); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp index 525de86405..4d11f658c5 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp @@ -46,136 +46,142 @@ struct sysinfo32 { static_assert(sizeof(sysinfo32) == 64, "Needs to be 64bytes"); -void RegisterInfo(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(oldolduname, [](FEXCore::Core::CpuStateFrame* Frame, struct oldold_utsname* buf) -> uint64_t { - struct utsname Local {}; +auto oldolduname(FEXCore::Core::CpuStateFrame* Frame, struct oldold_utsname* buf) -> uint64_t { + struct utsname Local {}; - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - memset(buf, 0, sizeof(*buf)); - if (::uname(&Local) == 0) { - memcpy(buf->nodename, Local.nodename, __OLD_UTS_LEN); - } else { - strncpy(buf->nodename, "FEXCore", __OLD_UTS_LEN); - LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); - } - strncpy(buf->sysname, "Linux", __OLD_UTS_LEN); - uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - snprintf(buf->release, __OLD_UTS_LEN, "%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__; - strncpy(buf->version, version, __OLD_UTS_LEN); - // Tell the guest that we are a 64bit kernel - strncpy(buf->machine, "x86_64", __OLD_UTS_LEN); - return 0; - }); - - REGISTER_SYSCALL_IMPL_X32(olduname, [](FEXCore::Core::CpuStateFrame* Frame, struct old_utsname* buf) -> uint64_t { - struct utsname Local {}; - - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - - memset(buf, 0, sizeof(*buf)); - if (::uname(&Local) == 0) { - memcpy(buf->nodename, Local.nodename, __NEW_UTS_LEN); - } else { - strncpy(buf->nodename, "FEXCore", __NEW_UTS_LEN); - LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); - } - strncpy(buf->sysname, "Linux", __NEW_UTS_LEN); - uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - snprintf(buf->release, __NEW_UTS_LEN, "%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__; - strncpy(buf->version, version, __NEW_UTS_LEN); - // Tell the guest that we are a 64bit kernel - strncpy(buf->machine, "x86_64", __NEW_UTS_LEN); - return 0; - }); - - REGISTER_SYSCALL_IMPL_X32( - getrlimit, [](FEXCore::Core::CpuStateFrame* Frame, int resource, compat_ptr> rlim) -> uint64_t { - struct rlimit rlim64 {}; - uint64_t Result = ::getrlimit(resource, &rlim64); - FaultSafeUserMemAccess::VerifyIsWritable(rlim, sizeof(*rlim)); - *rlim = rlim64; - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - ugetrlimit, [](FEXCore::Core::CpuStateFrame* Frame, int resource, compat_ptr> rlim) -> uint64_t { - struct rlimit rlim64 {}; - uint64_t Result = ::getrlimit(resource, &rlim64); - FaultSafeUserMemAccess::VerifyIsWritable(rlim, sizeof(*rlim)); - *rlim = rlim64; - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - setrlimit, [](FEXCore::Core::CpuStateFrame* Frame, int resource, const compat_ptr> rlim) -> uint64_t { - struct rlimit rlim64 {}; - FaultSafeUserMemAccess::VerifyIsReadable(rlim, sizeof(*rlim)); - rlim64 = *rlim; - uint64_t Result = ::setrlimit(resource, &rlim64); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(sysinfo, [](FEXCore::Core::CpuStateFrame* Frame, struct sysinfo32* info) -> uint64_t { - struct sysinfo Host {}; - uint64_t Result = ::sysinfo(&Host); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); + memset(buf, 0, sizeof(*buf)); + if (::uname(&Local) == 0) { + memcpy(buf->nodename, Local.nodename, __OLD_UTS_LEN); + } else { + strncpy(buf->nodename, "FEXCore", __OLD_UTS_LEN); + LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); + } + strncpy(buf->sysname, "Linux", __OLD_UTS_LEN); + uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); + snprintf(buf->release, __OLD_UTS_LEN, "%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__; + strncpy(buf->version, version, __OLD_UTS_LEN); + // Tell the guest that we are a 64bit kernel + strncpy(buf->machine, "x86_64", __OLD_UTS_LEN); + return 0; +} + +auto olduname(FEXCore::Core::CpuStateFrame* Frame, struct old_utsname* buf) -> uint64_t { + struct utsname Local {}; + + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + + memset(buf, 0, sizeof(*buf)); + if (::uname(&Local) == 0) { + memcpy(buf->nodename, Local.nodename, __NEW_UTS_LEN); + } else { + strncpy(buf->nodename, "FEXCore", __NEW_UTS_LEN); + LogMan::Msg::EFmt("Couldn't determine host nodename. Defaulting to '{}'", buf->nodename); + } + strncpy(buf->sysname, "Linux", __NEW_UTS_LEN); + uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); + snprintf(buf->release, __NEW_UTS_LEN, "%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__; + strncpy(buf->version, version, __NEW_UTS_LEN); + // Tell the guest that we are a 64bit kernel + strncpy(buf->machine, "x86_64", __NEW_UTS_LEN); + return 0; +} + +auto getrlimit(FEXCore::Core::CpuStateFrame* Frame, int resource, compat_ptr> rlim) -> uint64_t { + struct rlimit rlim64 {}; + uint64_t Result = ::getrlimit(resource, &rlim64); + FaultSafeUserMemAccess::VerifyIsWritable(rlim, sizeof(*rlim)); + *rlim = rlim64; + SYSCALL_ERRNO(); +} + +auto ugetrlimit(FEXCore::Core::CpuStateFrame* Frame, int resource, compat_ptr> rlim) -> uint64_t { + struct rlimit rlim64 {}; + uint64_t Result = ::getrlimit(resource, &rlim64); + FaultSafeUserMemAccess::VerifyIsWritable(rlim, sizeof(*rlim)); + *rlim = rlim64; + SYSCALL_ERRNO(); +} + +auto setrlimit(FEXCore::Core::CpuStateFrame* Frame, int resource, const compat_ptr> rlim) -> uint64_t { + struct rlimit rlim64 {}; + FaultSafeUserMemAccess::VerifyIsReadable(rlim, sizeof(*rlim)); + rlim64 = *rlim; + uint64_t Result = ::setrlimit(resource, &rlim64); + SYSCALL_ERRNO(); +} + +auto sysinfo(FEXCore::Core::CpuStateFrame* Frame, struct sysinfo32* info) -> uint64_t { + struct sysinfo Host {}; + uint64_t Result = ::sysinfo(&Host); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); #define Copy(x) \ info->x = static_castx)>(std::min(Host.x, static_cast(std::numeric_limitsx)>::max()))); - Copy(uptime); - Copy(procs); + Copy(uptime); + Copy(procs); #define CopyShift(x) info->x = static_castx)>(Host.x >> ShiftAmount); - info->loads[0] = std::min(Host.loads[0], static_cast(std::numeric_limits::max())); - info->loads[1] = std::min(Host.loads[1], static_cast(std::numeric_limits::max())); - info->loads[2] = std::min(Host.loads[2], static_cast(std::numeric_limits::max())); + info->loads[0] = std::min(Host.loads[0], static_cast(std::numeric_limits::max())); + info->loads[1] = std::min(Host.loads[1], static_cast(std::numeric_limits::max())); + info->loads[2] = std::min(Host.loads[2], static_cast(std::numeric_limits::max())); - // If any result can't fit in to a uint32_t then we need to shift the mem_unit and all the members - // Set the mem_unit to the pagesize - uint32_t ShiftAmount {}; - if ((Host.totalram >> 32) != 0 || (Host.totalswap >> 32) != 0) { + // If any result can't fit in to a uint32_t then we need to shift the mem_unit and all the members + // Set the mem_unit to the pagesize + uint32_t ShiftAmount {}; + if ((Host.totalram >> 32) != 0 || (Host.totalswap >> 32) != 0) { - while (Host.mem_unit < FEXCore::Utils::FEX_PAGE_SIZE) { - Host.mem_unit <<= 1; - ++ShiftAmount; - } + while (Host.mem_unit < FEXCore::Utils::FEX_PAGE_SIZE) { + Host.mem_unit <<= 1; + ++ShiftAmount; } - - CopyShift(totalram); - CopyShift(freeram); - CopyShift(sharedram); - CopyShift(bufferram); - CopyShift(totalswap); - CopyShift(freeswap); - CopyShift(totalhigh); - CopyShift(freehigh); - Copy(mem_unit); } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(getrusage, [](FEXCore::Core::CpuStateFrame* Frame, int who, rusage_32* usage) -> uint64_t { - struct rusage usage64 = *usage; - uint64_t Result = ::getrusage(who, &usage64); - FaultSafeUserMemAccess::VerifyIsWritable(usage, sizeof(*usage)); - *usage = usage64; - SYSCALL_ERRNO(); - }); - - if (Handler->IsHostKernelVersionAtLeast(6, 8, 0)) { - REGISTER_SYSCALL_IMPL_X32(map_shadow_stack, [](FEXCore::Core::CpuStateFrame* Frame, uint64_t addr, uint64_t size, uint32_t flags) -> uint64_t { - // Claim that shadow stack isn't supported. - return -EOPNOTSUPP; - }); + + CopyShift(totalram); + CopyShift(freeram); + CopyShift(sharedram); + CopyShift(bufferram); + CopyShift(totalswap); + CopyShift(freeswap); + CopyShift(totalhigh); + CopyShift(freehigh); + Copy(mem_unit); + } + SYSCALL_ERRNO(); +} + +auto getrusage(FEXCore::Core::CpuStateFrame* Frame, int who, rusage_32* usage) -> uint64_t { + struct rusage usage64 = *usage; + uint64_t Result = ::getrusage(who, &usage64); + FaultSafeUserMemAccess::VerifyIsWritable(usage, sizeof(*usage)); + *usage = usage64; + SYSCALL_ERRNO(); +} + +auto map_shadow_stack(FEXCore::Core::CpuStateFrame* Frame, uint64_t addr, uint64_t size, uint32_t flags) -> uint64_t { + if (FEX::HLE::_SyscallHandler->IsHostKernelVersionAtLeast(6, 8, 0)) { + // Claim that shadow stack isn't supported. + return -EOPNOTSUPP; } else { - REGISTER_SYSCALL_IMPL_X32(map_shadow_stack, UnimplementedSyscallSafe); + return -ENOSYS; } } + +void RegisterInfo(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(oldolduname, oldolduname); + REGISTER_SYSCALL_IMPL_X32(olduname, olduname); + REGISTER_SYSCALL_IMPL_X32(getrlimit, getrlimit); + REGISTER_SYSCALL_IMPL_X32(ugetrlimit, ugetrlimit); + REGISTER_SYSCALL_IMPL_X32(setrlimit, setrlimit); + REGISTER_SYSCALL_IMPL_X32(sysinfo, sysinfo); + REGISTER_SYSCALL_IMPL_X32(getrusage, getrusage); + REGISTER_SYSCALL_IMPL_X32(map_shadow_stack, map_shadow_stack); +} } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Memory.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Memory.cpp index 5ffde0afae..70dadfa532 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Memory.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Memory.cpp @@ -18,61 +18,68 @@ tags: LinuxSyscalls|syscalls-x86-32 #include #include #include -#include -#include namespace FEX::HLE::x32 { -void RegisterMemory(FEX::HLE::SyscallHandler* Handler) { - struct old_mmap_struct { - uint32_t addr; - uint32_t len; - uint32_t prot; - uint32_t flags; - uint32_t fd; - uint32_t offset; - }; - REGISTER_SYSCALL_IMPL_X32(mmap, [](FEXCore::Core::CpuStateFrame* Frame, const old_mmap_struct* arg) -> uint64_t { - return reinterpret_cast(FEX::HLE::_SyscallHandler->GuestMmap(false, Frame->Thread, reinterpret_cast(arg->addr), - arg->len, arg->prot, arg->flags, arg->fd, arg->offset)); - }); +struct old_mmap_struct { + uint32_t addr; + uint32_t len; + uint32_t prot; + uint32_t flags; + uint32_t fd; + uint32_t offset; +}; - REGISTER_SYSCALL_IMPL_X32( - mmap2, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t addr, uint32_t length, int prot, int flags, int fd, uint32_t pgoffset) -> uint64_t { - return reinterpret_cast(FEX::HLE::_SyscallHandler->GuestMmap(false, Frame->Thread, reinterpret_cast(addr), length, - prot, flags, fd, (uint64_t)pgoffset * 0x1000)); - }); +auto mmap(FEXCore::Core::CpuStateFrame* Frame, const old_mmap_struct* arg) -> uint64_t { + return reinterpret_cast(FEX::HLE::_SyscallHandler->GuestMmap(false, Frame->Thread, reinterpret_cast(arg->addr), arg->len, + arg->prot, arg->flags, arg->fd, arg->offset)); +} - REGISTER_SYSCALL_IMPL_X32(munmap, [](FEXCore::Core::CpuStateFrame* Frame, void* addr, size_t length) -> uint64_t { - return FEX::HLE::_SyscallHandler->GuestMunmap(Frame->Thread, addr, length); - }); +auto mmap2(FEXCore::Core::CpuStateFrame* Frame, uint32_t addr, uint32_t length, int prot, int flags, int fd, uint32_t pgoffset) -> uint64_t { + return reinterpret_cast(FEX::HLE::_SyscallHandler->GuestMmap(false, Frame->Thread, reinterpret_cast(addr), length, prot, + flags, fd, (uint64_t)pgoffset * 0x1000)); +} - REGISTER_SYSCALL_IMPL_X32(mprotect, [](FEXCore::Core::CpuStateFrame* Frame, void* addr, uint32_t len, int prot) -> uint64_t { - return FEX::HLE::_SyscallHandler->GuestMprotect(Frame->Thread, addr, len, prot); - }); +auto munmap(FEXCore::Core::CpuStateFrame* Frame, void* addr, size_t length) -> uint64_t { + return FEX::HLE::_SyscallHandler->GuestMunmap(Frame->Thread, addr, length); +} - REGISTER_SYSCALL_IMPL_X32( - mremap, [](FEXCore::Core::CpuStateFrame* Frame, void* old_address, size_t old_size, size_t new_size, int flags, void* new_address) -> uint64_t { - return FEX::HLE::_SyscallHandler->GuestMremap(false, Frame->Thread, old_address, old_size, new_size, flags, new_address); - }); +auto mprotect(FEXCore::Core::CpuStateFrame* Frame, void* addr, uint32_t len, int prot) -> uint64_t { + return FEX::HLE::_SyscallHandler->GuestMprotect(Frame->Thread, addr, len, prot); +} - REGISTER_SYSCALL_IMPL_X32(mlockall, [](FEXCore::Core::CpuStateFrame* Frame, int flags) -> uint64_t { - uint64_t Result = ::syscall(SYSCALL_DEF(mlock2), reinterpret_cast(0x1'0000), 0x1'0000'0000ULL - 0x1'0000, flags); - SYSCALL_ERRNO(); - }); +auto mremap(FEXCore::Core::CpuStateFrame* Frame, void* old_address, size_t old_size, size_t new_size, int flags, void* new_address) -> uint64_t { + return FEX::HLE::_SyscallHandler->GuestMremap(false, Frame->Thread, old_address, old_size, new_size, flags, new_address); +} - REGISTER_SYSCALL_IMPL_X32(munlockall, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { - uint64_t Result = ::munlock(reinterpret_cast(0x1'0000), 0x1'0000'0000ULL - 0x1'0000); - SYSCALL_ERRNO(); - }); +auto mlockall(FEXCore::Core::CpuStateFrame* Frame, int flags) -> uint64_t { + uint64_t Result = ::syscall(SYSCALL_DEF(mlock2), reinterpret_cast(0x1'0000), 0x1'0000'0000ULL - 0x1'0000, flags); + SYSCALL_ERRNO(); +} - REGISTER_SYSCALL_IMPL_X32(shmat, [](FEXCore::Core::CpuStateFrame* Frame, int shmid, const void* shmaddr, int shmflg) -> uint64_t { - return FEX::HLE::_SyscallHandler->GuestShmat(false, Frame->Thread, shmid, shmaddr, shmflg); - }); +auto munlockall(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + uint64_t Result = ::munlock(reinterpret_cast(0x1'0000), 0x1'0000'0000ULL - 0x1'0000); + SYSCALL_ERRNO(); +} + +auto shmat(FEXCore::Core::CpuStateFrame* Frame, int shmid, const void* shmaddr, int shmflg) -> uint64_t { + return FEX::HLE::_SyscallHandler->GuestShmat(false, Frame->Thread, shmid, shmaddr, shmflg); +} - REGISTER_SYSCALL_IMPL_X32(shmdt, [](FEXCore::Core::CpuStateFrame* Frame, const void* shmaddr) -> uint64_t { - return FEX::HLE::_SyscallHandler->GuestShmdt(false, Frame->Thread, shmaddr); - }); +auto shmdt(FEXCore::Core::CpuStateFrame* Frame, const void* shmaddr) -> uint64_t { + return FEX::HLE::_SyscallHandler->GuestShmdt(false, Frame->Thread, shmaddr); +} + +void RegisterMemory(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(mmap, mmap); + REGISTER_SYSCALL_IMPL_X32(mmap2, mmap2); + REGISTER_SYSCALL_IMPL_X32(munmap, munmap); + REGISTER_SYSCALL_IMPL_X32(mprotect, mprotect); + REGISTER_SYSCALL_IMPL_X32(mremap, mremap); + REGISTER_SYSCALL_IMPL_X32(mlockall, mlockall); + REGISTER_SYSCALL_IMPL_X32(munlockall, munlockall); + REGISTER_SYSCALL_IMPL_X32(shmat, shmat); + REGISTER_SYSCALL_IMPL_X32(shmdt, shmdt); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/NotImplemented.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/NotImplemented.cpp index d3f1739d03..ac36c83bb0 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/NotImplemented.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/NotImplemented.cpp @@ -24,20 +24,43 @@ namespace FEX::HLE::x32 { #define REGISTER_SYSCALL_NO_PERM_X32(name) \ REGISTER_SYSCALL_IMPL_X32(name, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -EPERM; }); +#define SYSCALL_NOT_IMPL_X32(name) \ + auto name(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { \ + LogMan::Msg::DFmt("Using deprecated/removed syscall: " #name); \ + return -ENOSYS; \ + }; +#define SYSCALL_NO_PERM_X32(name) \ + auto name(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { \ + return -EPERM; \ + }; + +SYSCALL_NOT_IMPL_X32(_break); +SYSCALL_NOT_IMPL_X32(stty); +SYSCALL_NOT_IMPL_X32(gtty); +SYSCALL_NOT_IMPL_X32(prof); +SYSCALL_NOT_IMPL_X32(ftime); +SYSCALL_NOT_IMPL_X32(mpx); +SYSCALL_NOT_IMPL_X32(lock); +SYSCALL_NOT_IMPL_X32(ulimit); +SYSCALL_NOT_IMPL_X32(profil); +SYSCALL_NOT_IMPL_X32(idle); + +SYSCALL_NO_PERM_X32(stime); +SYSCALL_NO_PERM_X32(bdflush); // these are removed/not implemented in the linux kernel we present void RegisterNotImplemented(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_NOT_IMPL_X32(break); - REGISTER_SYSCALL_NOT_IMPL_X32(stty); - REGISTER_SYSCALL_NOT_IMPL_X32(gtty); - REGISTER_SYSCALL_NOT_IMPL_X32(prof); - REGISTER_SYSCALL_NOT_IMPL_X32(ftime); - REGISTER_SYSCALL_NOT_IMPL_X32(mpx); - REGISTER_SYSCALL_NOT_IMPL_X32(lock); - REGISTER_SYSCALL_NOT_IMPL_X32(ulimit); - REGISTER_SYSCALL_NOT_IMPL_X32(profil); - REGISTER_SYSCALL_NOT_IMPL_X32(idle); - - REGISTER_SYSCALL_NO_PERM_X32(stime); - REGISTER_SYSCALL_NO_PERM_X32(bdflush); + REGISTER_SYSCALL_IMPL_X32(break, _break); + REGISTER_SYSCALL_IMPL_X32(stty, stty); + REGISTER_SYSCALL_IMPL_X32(gtty, gtty); + REGISTER_SYSCALL_IMPL_X32(prof, prof); + REGISTER_SYSCALL_IMPL_X32(ftime, ftime); + REGISTER_SYSCALL_IMPL_X32(mpx, mpx); + REGISTER_SYSCALL_IMPL_X32(lock, lock); + REGISTER_SYSCALL_IMPL_X32(ulimit, ulimit); + REGISTER_SYSCALL_IMPL_X32(profil, profil); + REGISTER_SYSCALL_IMPL_X32(idle, idle); + + REGISTER_SYSCALL_IMPL_X32(stime, stime); + REGISTER_SYSCALL_IMPL_X32(bdflush, bdflush); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Sched.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Sched.cpp index 82638db8ca..24722c2794 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Sched.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Sched.cpp @@ -20,15 +20,17 @@ struct CpuStateFrame; } namespace FEX::HLE::x32 { +auto sched_rr_get_interval(FEXCore::Core::CpuStateFrame* Frame, pid_t pid, struct timespec32* tp) -> uint64_t { + struct timespec tp64 {}; + uint64_t Result = ::sched_rr_get_interval(pid, tp ? &tp64 : nullptr); + if (tp) { + FaultSafeUserMemAccess::VerifyIsWritable(tp, sizeof(*tp)); + *tp = tp64; + } + SYSCALL_ERRNO(); +} + void RegisterSched(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(sched_rr_get_interval, [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, struct timespec32* tp) -> uint64_t { - struct timespec tp64 {}; - uint64_t Result = ::sched_rr_get_interval(pid, tp ? &tp64 : nullptr); - if (tp) { - FaultSafeUserMemAccess::VerifyIsWritable(tp, sizeof(*tp)); - *tp = tp64; - } - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(sched_rr_get_interval, sched_rr_get_interval); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Semaphore.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Semaphore.cpp index a0f1d2d802..c735bdd907 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Semaphore.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Semaphore.cpp @@ -86,7 +86,7 @@ union semun { void* __pad; }; -uint64_t _ipc(FEXCore::Core::CpuStateFrame* Frame, uint32_t call, uint32_t first, uint32_t second, uint32_t third, uint32_t ptr, uint32_t fifth) { +uint64_t ipc(FEXCore::Core::CpuStateFrame* Frame, uint32_t call, uint32_t first, uint32_t second, uint32_t third, uint32_t ptr, uint32_t fifth) { uint64_t Result {}; const int Version = call >> 16; @@ -382,80 +382,82 @@ uint64_t _ipc(FEXCore::Core::CpuStateFrame* Frame, uint32_t call, uint32_t first } SYSCALL_ERRNO(); } -void RegisterSemaphore(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(ipc, _ipc); - REGISTER_SYSCALL_IMPL_X32(semctl, [](FEXCore::Core::CpuStateFrame* Frame, int semid, int semnum, int cmd, semun_32* semun) -> uint64_t { - uint64_t Result {}; - bool IPC64 = cmd & 0x100; +auto semctl(FEXCore::Core::CpuStateFrame* Frame, int semid, int semnum, int cmd, semun_32* semun) -> uint64_t { + uint64_t Result {}; + bool IPC64 = cmd & 0x100; - switch (cmd) { - case IPC_SET: { - struct semid64_ds buf {}; + switch (cmd) { + case IPC_SET: { + struct semid64_ds buf {}; + if (IPC64) { + FaultSafeUserMemAccess::VerifyIsReadable(semun->buf64, sizeof(*semun->buf64)); + buf = *semun->buf64; + } else { + FaultSafeUserMemAccess::VerifyIsReadable(semun->buf32, sizeof(*semun->buf32)); + buf = *semun->buf32; + } + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); + if (Result != -1) { if (IPC64) { - FaultSafeUserMemAccess::VerifyIsReadable(semun->buf64, sizeof(*semun->buf64)); - buf = *semun->buf64; + FaultSafeUserMemAccess::VerifyIsWritable(semun->buf64, sizeof(*semun->buf64)); + *semun->buf64 = buf; } else { - FaultSafeUserMemAccess::VerifyIsReadable(semun->buf32, sizeof(*semun->buf32)); - buf = *semun->buf32; - } - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); - if (Result != -1) { - if (IPC64) { - FaultSafeUserMemAccess::VerifyIsWritable(semun->buf64, sizeof(*semun->buf64)); - *semun->buf64 = buf; - } else { - FaultSafeUserMemAccess::VerifyIsWritable(semun->buf32, sizeof(*semun->buf32)); - *semun->buf32 = buf; - } - } - break; - } - case SEM_STAT: - case SEM_STAT_ANY: - case IPC_STAT: { - struct semid64_ds buf {}; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); - if (Result != -1) { - if (IPC64) { - FaultSafeUserMemAccess::VerifyIsWritable(semun->buf64, sizeof(*semun->buf64)); - *semun->buf64 = buf; - } else { - FaultSafeUserMemAccess::VerifyIsWritable(semun->buf32, sizeof(*semun->buf32)); - *semun->buf32 = buf; - } + FaultSafeUserMemAccess::VerifyIsWritable(semun->buf32, sizeof(*semun->buf32)); + *semun->buf32 = buf; } - break; } - case SEM_INFO: - case IPC_INFO: { - struct fex_seminfo si {}; - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &si); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(semun->__buf, sizeof(*semun->__buf)); - memcpy(semun->__buf, &si, sizeof(si)); + break; + } + case SEM_STAT: + case SEM_STAT_ANY: + case IPC_STAT: { + struct semid64_ds buf {}; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &buf); + if (Result != -1) { + if (IPC64) { + FaultSafeUserMemAccess::VerifyIsWritable(semun->buf64, sizeof(*semun->buf64)); + *semun->buf64 = buf; + } else { + FaultSafeUserMemAccess::VerifyIsWritable(semun->buf32, sizeof(*semun->buf32)); + *semun->buf32 = buf; } - break; } - case GETALL: - case SETALL: { - // ptr is just a int32_t* in this case - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->array); - break; - } - case SETVAL: { - // ptr is just a int32_t in this case - Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->val); - break; - } - case IPC_RMID: - case GETPID: - case GETNCNT: - case GETZCNT: - case GETVAL: Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun); break; - default: LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); return -EINVAL; + break; + } + case SEM_INFO: + case IPC_INFO: { + struct fex_seminfo si {}; + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, &si); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(semun->__buf, sizeof(*semun->__buf)); + memcpy(semun->__buf, &si, sizeof(si)); } - SYSCALL_ERRNO(); - }); + break; + } + case GETALL: + case SETALL: { + // ptr is just a int32_t* in this case + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->array); + break; + } + case SETVAL: { + // ptr is just a int32_t in this case + Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun->val); + break; + } + case IPC_RMID: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETVAL: Result = ::syscall(SYSCALL_DEF(semctl), semid, semnum, cmd, semun); break; + default: LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); return -EINVAL; + } + SYSCALL_ERRNO(); +} + +void RegisterSemaphore(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(ipc, ipc); + REGISTER_SYSCALL_IMPL_X32(semctl, semctl); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp index 64d5768d84..a10a067b8e 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Signals.cpp @@ -72,189 +72,191 @@ void CopySigInfo(FEXCore::x86::siginfo_t* Info, const siginfo_t& Host) { } } -void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { +// Only gets the lower 32-bits of the signal mask +auto sgetmask(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + uint64_t Set {}; + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), 0, nullptr, &Set); + return Set & ~0U; +} - // Only gets the lower 32-bits of the signal mask - REGISTER_SYSCALL_IMPL_X32(sgetmask, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { - uint64_t Set {}; - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), 0, nullptr, &Set); - return Set & ~0U; - }); - - // Only controls the lower 32-bits of the signal mask - // Blocks the upper 32-bits - REGISTER_SYSCALL_IMPL_X32(ssetmask, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t New) -> uint64_t { - uint64_t Set {}; - uint64_t NewSet = (~0ULL << 32) | New; - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), - SIG_SETMASK, &NewSet, &Set); - return Set & ~0U; - }); - - // Only masks the lower 32-bits of the signal mask - // The upper 32-bits are still active (unmasked) and can signal the program - REGISTER_SYSCALL_IMPL_X32(sigsuspend, [](FEXCore::Core::CpuStateFrame* Frame, uint32_t Mask) -> uint64_t { - uint64_t Mask64 = Mask; - return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), &Mask64, 8); - }); - - REGISTER_SYSCALL_IMPL_X32(sigpending, [](FEXCore::Core::CpuStateFrame* Frame, compat_old_sigset_t* set) -> uint64_t { - uint64_t HostSet {}; - uint64_t Result = - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), &HostSet, 8); - if (Result == 0) { - // This old interface only returns the lower signals - FaultSafeUserMemAccess::VerifyIsWritable(set, sizeof(*set)); - *set = HostSet & ~0U; - } - return Result; - }); - - REGISTER_SYSCALL_IMPL_X32(signal, [](FEXCore::Core::CpuStateFrame* Frame, int signum, uint32_t handler) -> uint64_t { - GuestSigAction newact {}; - GuestSigAction oldact {}; - newact.sigaction_handler.handler = reinterpret_cast(handler); - FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, &newact, &oldact); - return static_cast(reinterpret_cast(oldact.sigaction_handler.handler)); - }); - - REGISTER_SYSCALL_IMPL_X32( - sigaction, [](FEXCore::Core::CpuStateFrame* Frame, int signum, const OldGuestSigAction_32* act, OldGuestSigAction_32* oldact) -> uint64_t { - GuestSigAction* act64_p {}; - GuestSigAction* old64_p {}; - - GuestSigAction act64 {}; - if (act) { - FaultSafeUserMemAccess::VerifyIsReadable(act, sizeof(*act)); - act64 = *act; - act64_p = &act64; - } - GuestSigAction old64 {}; - - if (oldact) { - old64_p = &old64; - } - - uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, act64_p, old64_p); - if (Result == 0 && oldact) { - FaultSafeUserMemAccess::VerifyIsWritable(oldact, sizeof(*oldact)); - *oldact = old64; - } - - return Result; - }); - - REGISTER_SYSCALL_IMPL_X32( - rt_sigaction, - [](FEXCore::Core::CpuStateFrame* Frame, int signum, const GuestSigAction_32* act, GuestSigAction_32* oldact, size_t sigsetsize) -> uint64_t { - if (sigsetsize != 8) { - return -EINVAL; - } - - GuestSigAction* act64_p {}; - GuestSigAction* old64_p {}; - - GuestSigAction act64 {}; - if (act) { - FaultSafeUserMemAccess::VerifyIsReadable(act, sizeof(*act)); - act64 = *act; - act64_p = &act64; - } - GuestSigAction old64 {}; - - if (oldact) { - old64_p = &old64; - } - - uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, act64_p, old64_p); - if (Result == 0 && oldact) { - FaultSafeUserMemAccess::VerifyIsWritable(oldact, sizeof(*oldact)); - *oldact = old64; - } - - return Result; - }); - - REGISTER_SYSCALL_IMPL_X32(rt_sigtimedwait, - [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, compat_ptr info, - const struct timespec32* timeout, size_t sigsetsize) -> uint64_t { - struct timespec* timeout_ptr {}; - struct timespec tp64 {}; - if (timeout) { - FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); - tp64 = *timeout; - timeout_ptr = &tp64; - } - - siginfo_t HostInfo {}; - uint64_t Result = - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, &HostInfo, timeout_ptr, sigsetsize); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); - // We need to translate the 64-bit siginfo_t to 32-bit siginfo_t - CopySigInfo(info, HostInfo); - } - return Result; - }); - - - REGISTER_SYSCALL_IMPL_X32(rt_sigtimedwait_time64, - [](FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, compat_ptr info, - const struct timespec* timeout, size_t sigsetsize) -> uint64_t { - siginfo_t HostInfo {}; - uint64_t Result = - FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, &HostInfo, timeout, sigsetsize); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); - // We need to translate the 64-bit siginfo_t to 32-bit siginfo_t - CopySigInfo(info, HostInfo); - } - return Result; - }); - - REGISTER_SYSCALL_IMPL_X32( - pidfd_send_signal, - [](FEXCore::Core::CpuStateFrame* Frame, int pidfd, int sig, compat_ptr info, unsigned int flags) -> uint64_t { - siginfo_t* InfoHost_ptr {}; - siginfo_t InfoHost {}; - if (info) { - FaultSafeUserMemAccess::VerifyIsReadable(info, sizeof(*info)); - InfoHost = *info; - InfoHost_ptr = &InfoHost; - } - - uint64_t Result = ::syscall(SYSCALL_DEF(pidfd_send_signal), pidfd, sig, InfoHost_ptr, flags); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - rt_sigqueueinfo, [](FEXCore::Core::CpuStateFrame* Frame, pid_t pid, int sig, compat_ptr info) -> uint64_t { - siginfo_t info64 {}; - siginfo_t* info64_p {}; - - if (info) { - FaultSafeUserMemAccess::VerifyIsReadable(info, sizeof(*info)); - info64 = *info; - info64_p = &info64; - } - - uint64_t Result = ::syscall(SYSCALL_DEF(rt_sigqueueinfo), pid, sig, info64_p); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - rt_tgsigqueueinfo, [](FEXCore::Core::CpuStateFrame* Frame, pid_t tgid, pid_t tid, int sig, compat_ptr info) -> uint64_t { - siginfo_t info64 {}; - siginfo_t* info64_p {}; - - if (info) { - FaultSafeUserMemAccess::VerifyIsReadable(info, sizeof(*info)); - info64 = *info; - info64_p = &info64; - } - - uint64_t Result = ::syscall(SYSCALL_DEF(rt_tgsigqueueinfo), tgid, tid, sig, info64_p); - SYSCALL_ERRNO(); - }); +// Only controls the lower 32-bits of the signal mask +// Blocks the upper 32-bits +auto ssetmask(FEXCore::Core::CpuStateFrame* Frame, uint32_t New) -> uint64_t { + uint64_t Set {}; + uint64_t NewSet = (~0ULL << 32) | New; + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigProcMask(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), SIG_SETMASK, + &NewSet, &Set); + return Set & ~0U; +} + +// Only masks the lower 32-bits of the signal mask +// The upper 32-bits are still active (unmasked) and can signal the program +auto sigsuspend(FEXCore::Core::CpuStateFrame* Frame, uint32_t Mask) -> uint64_t { + uint64_t Mask64 = Mask; + return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigSuspend(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), &Mask64, 8); +} + +auto sigpending(FEXCore::Core::CpuStateFrame* Frame, compat_old_sigset_t* set) -> uint64_t { + uint64_t HostSet {}; + uint64_t Result = + FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigPending(FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), &HostSet, 8); + if (Result == 0) { + // This old interface only returns the lower signals + FaultSafeUserMemAccess::VerifyIsWritable(set, sizeof(*set)); + *set = HostSet & ~0U; + } + return Result; +} + +auto signal(FEXCore::Core::CpuStateFrame* Frame, int signum, uint32_t handler) -> uint64_t { + GuestSigAction newact {}; + GuestSigAction oldact {}; + newact.sigaction_handler.handler = reinterpret_cast(handler); + FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, &newact, &oldact); + return static_cast(reinterpret_cast(oldact.sigaction_handler.handler)); +} + +auto sigaction(FEXCore::Core::CpuStateFrame* Frame, int signum, const OldGuestSigAction_32* act, OldGuestSigAction_32* oldact) -> uint64_t { + GuestSigAction* act64_p {}; + GuestSigAction* old64_p {}; + + GuestSigAction act64 {}; + if (act) { + FaultSafeUserMemAccess::VerifyIsReadable(act, sizeof(*act)); + act64 = *act; + act64_p = &act64; + } + GuestSigAction old64 {}; + + if (oldact) { + old64_p = &old64; + } + + uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, act64_p, old64_p); + if (Result == 0 && oldact) { + FaultSafeUserMemAccess::VerifyIsWritable(oldact, sizeof(*oldact)); + *oldact = old64; + } + + return Result; +} + +auto rt_sigaction(FEXCore::Core::CpuStateFrame* Frame, int signum, const GuestSigAction_32* act, GuestSigAction_32* oldact, size_t sigsetsize) + -> uint64_t { + if (sigsetsize != 8) { + return -EINVAL; + } + + GuestSigAction* act64_p {}; + GuestSigAction* old64_p {}; + + GuestSigAction act64 {}; + if (act) { + FaultSafeUserMemAccess::VerifyIsReadable(act, sizeof(*act)); + act64 = *act; + act64_p = &act64; + } + GuestSigAction old64 {}; + + if (oldact) { + old64_p = &old64; + } + + uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSignalHandler(signum, act64_p, old64_p); + if (Result == 0 && oldact) { + FaultSafeUserMemAccess::VerifyIsWritable(oldact, sizeof(*oldact)); + *oldact = old64; + } + + return Result; +} + +auto rt_sigtimedwait(FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, compat_ptr info, + const struct timespec32* timeout, size_t sigsetsize) -> uint64_t { + struct timespec* timeout_ptr {}; + struct timespec tp64 {}; + if (timeout) { + FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); + tp64 = *timeout; + timeout_ptr = &tp64; + } + + siginfo_t HostInfo {}; + uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, &HostInfo, timeout_ptr, sigsetsize); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); + // We need to translate the 64-bit siginfo_t to 32-bit siginfo_t + CopySigInfo(info, HostInfo); + } + return Result; +} + +auto rt_sigtimedwait_time64(FEXCore::Core::CpuStateFrame* Frame, uint64_t* set, compat_ptr info, + const struct timespec* timeout, size_t sigsetsize) -> uint64_t { + siginfo_t HostInfo {}; + uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, &HostInfo, timeout, sigsetsize); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); + // We need to translate the 64-bit siginfo_t to 32-bit siginfo_t + CopySigInfo(info, HostInfo); + } + return Result; +} + +auto pidfd_send_signal(FEXCore::Core::CpuStateFrame* Frame, int pidfd, int sig, compat_ptr info, unsigned int flags) + -> uint64_t { + siginfo_t* InfoHost_ptr {}; + siginfo_t InfoHost {}; + if (info) { + FaultSafeUserMemAccess::VerifyIsReadable(info, sizeof(*info)); + InfoHost = *info; + InfoHost_ptr = &InfoHost; + } + + uint64_t Result = ::syscall(SYSCALL_DEF(pidfd_send_signal), pidfd, sig, InfoHost_ptr, flags); + SYSCALL_ERRNO(); +} + +auto rt_sigqueueinfo(FEXCore::Core::CpuStateFrame* Frame, pid_t pid, int sig, compat_ptr info) -> uint64_t { + siginfo_t info64 {}; + siginfo_t* info64_p {}; + + if (info) { + FaultSafeUserMemAccess::VerifyIsReadable(info, sizeof(*info)); + info64 = *info; + info64_p = &info64; + } + + uint64_t Result = ::syscall(SYSCALL_DEF(rt_sigqueueinfo), pid, sig, info64_p); + SYSCALL_ERRNO(); +} + +auto rt_tgsigqueueinfo(FEXCore::Core::CpuStateFrame* Frame, pid_t tgid, pid_t tid, int sig, compat_ptr info) -> uint64_t { + siginfo_t info64 {}; + siginfo_t* info64_p {}; + + if (info) { + FaultSafeUserMemAccess::VerifyIsReadable(info, sizeof(*info)); + info64 = *info; + info64_p = &info64; + } + + uint64_t Result = ::syscall(SYSCALL_DEF(rt_tgsigqueueinfo), tgid, tid, sig, info64_p); + SYSCALL_ERRNO(); +} + +void RegisterSignals(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(sgetmask, sgetmask); + REGISTER_SYSCALL_IMPL_X32(ssetmask, ssetmask); + REGISTER_SYSCALL_IMPL_X32(sigsuspend, sigsuspend); + REGISTER_SYSCALL_IMPL_X32(sigpending, sigpending); + REGISTER_SYSCALL_IMPL_X32(signal, signal); + REGISTER_SYSCALL_IMPL_X32(sigaction, sigaction); + REGISTER_SYSCALL_IMPL_X32(rt_sigaction, rt_sigaction); + REGISTER_SYSCALL_IMPL_X32(rt_sigtimedwait, rt_sigtimedwait); + REGISTER_SYSCALL_IMPL_X32(rt_sigtimedwait_time64, rt_sigtimedwait_time64); + REGISTER_SYSCALL_IMPL_X32(pidfd_send_signal, pidfd_send_signal); + REGISTER_SYSCALL_IMPL_X32(rt_sigqueueinfo, rt_sigqueueinfo); + REGISTER_SYSCALL_IMPL_X32(rt_tgsigqueueinfo, rt_tgsigqueueinfo); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Socket.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Socket.cpp index 3a7e6815fa..c4a33327ed 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Socket.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Socket.cpp @@ -647,154 +647,163 @@ static uint64_t GetSockOpt(int sockfd, int level, int optname, auto_compat_ptr uint64_t { - uint64_t Result {}; +auto socketcall(FEXCore::Core::CpuStateFrame* Frame, uint32_t call, uint32_t* Arguments) -> uint64_t { + uint64_t Result {}; - switch (call) { - case OP_SOCKET: { - Result = ::socket(Arguments[0], Arguments[1], Arguments[2]); - break; - } - case OP_BIND: { - Result = ::bind(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); - break; - } - case OP_CONNECT: { - Result = ::connect(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); - break; - } - case OP_LISTEN: { - Result = ::listen(Arguments[0], Arguments[1]); - break; - } - case OP_ACCEPT: { - Result = ::accept(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); - break; - } - case OP_GETSOCKNAME: { - Result = ::getsockname(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); - break; - } - case OP_GETPEERNAME: { - Result = ::getpeername(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); - break; - } - case OP_SOCKETPAIR: { - Result = ::socketpair(Arguments[0], Arguments[1], Arguments[2], reinterpret_cast(Arguments[3])); - break; - } - case OP_SEND: { - Result = ::send(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); - break; - } - case OP_RECV: { - Result = ::recv(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); - break; - } - case OP_SENDTO: { - Result = ::sendto(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3], - reinterpret_cast(Arguments[4]), reinterpret_cast(Arguments[5])); - break; - } - case OP_RECVFROM: { - Result = ::recvfrom(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3], - reinterpret_cast(Arguments[4]), reinterpret_cast(Arguments[5])); - break; - } - case OP_SHUTDOWN: { - Result = ::shutdown(Arguments[0], Arguments[1]); - break; - } - case OP_SETSOCKOPT: { - return SetSockOpt(Arguments[0], Arguments[1], Arguments[2], Arguments[3], reinterpret_cast(Arguments[4])); - break; - } - case OP_GETSOCKOPT: { - return GetSockOpt(Arguments[0], Arguments[1], Arguments[2], reinterpret_cast(Arguments[3]), - reinterpret_cast(Arguments[4])); - break; - } - case OP_SENDMSG: { - return SendMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); - break; - } - case OP_RECVMSG: { - return RecvMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); - break; + switch (call) { + case OP_SOCKET: { + Result = ::socket(Arguments[0], Arguments[1], Arguments[2]); + break; + } + case OP_BIND: { + Result = ::bind(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); + break; + } + case OP_CONNECT: { + Result = ::connect(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); + break; + } + case OP_LISTEN: { + Result = ::listen(Arguments[0], Arguments[1]); + break; + } + case OP_ACCEPT: { + Result = ::accept(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); + break; + } + case OP_GETSOCKNAME: { + Result = ::getsockname(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); + break; + } + case OP_GETPEERNAME: { + Result = ::getpeername(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2])); + break; + } + case OP_SOCKETPAIR: { + Result = ::socketpair(Arguments[0], Arguments[1], Arguments[2], reinterpret_cast(Arguments[3])); + break; + } + case OP_SEND: { + Result = ::send(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); + break; + } + case OP_RECV: { + Result = ::recv(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); + break; + } + case OP_SENDTO: { + Result = ::sendto(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3], + reinterpret_cast(Arguments[4]), reinterpret_cast(Arguments[5])); + break; + } + case OP_RECVFROM: { + Result = ::recvfrom(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3], + reinterpret_cast(Arguments[4]), reinterpret_cast(Arguments[5])); + break; + } + case OP_SHUTDOWN: { + Result = ::shutdown(Arguments[0], Arguments[1]); + break; + } + case OP_SETSOCKOPT: { + return SetSockOpt(Arguments[0], Arguments[1], Arguments[2], Arguments[3], reinterpret_cast(Arguments[4])); + break; + } + case OP_GETSOCKOPT: { + return GetSockOpt(Arguments[0], Arguments[1], Arguments[2], reinterpret_cast(Arguments[3]), reinterpret_cast(Arguments[4])); + break; + } + case OP_SENDMSG: { + return SendMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); + break; + } + case OP_RECVMSG: { + return RecvMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2]); + break; + } + case OP_ACCEPT4: { + return ::accept4(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2]), Arguments[3]); + break; + } + case OP_RECVMMSG: { + timespec32* timeout_ts = reinterpret_cast(Arguments[4]); + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (timeout_ts) { + tp64 = *timeout_ts; + timed_ptr = &tp64; } - case OP_ACCEPT4: { - return ::accept4(Arguments[0], reinterpret_cast(Arguments[1]), reinterpret_cast(Arguments[2]), Arguments[3]); - break; + + uint64_t Result = RecvMMsg(Arguments[0], Arguments[1], Arguments[2], Arguments[3], timed_ptr); + + if (timeout_ts) { + *timeout_ts = tp64; } - case OP_RECVMMSG: { - timespec32* timeout_ts = reinterpret_cast(Arguments[4]); - struct timespec tp64 {}; - struct timespec* timed_ptr {}; - if (timeout_ts) { - tp64 = *timeout_ts; - timed_ptr = &tp64; - } - uint64_t Result = RecvMMsg(Arguments[0], Arguments[1], Arguments[2], Arguments[3], timed_ptr); + return Result; + break; + } + case OP_SENDMMSG: { + return SendMMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); + break; + } + default: LOGMAN_MSG_A_FMT("Unsupported socketcall op: {}", call); break; + } + SYSCALL_ERRNO(); +} - if (timeout_ts) { - *timeout_ts = tp64; - } +auto sendmsg(FEXCore::Core::CpuStateFrame* Frame, int sockfd, const struct msghdr32* msg, int flags) -> uint64_t { + return SendMsg(sockfd, msg, flags); +} - return Result; - break; - } - case OP_SENDMMSG: { - return SendMMsg(Arguments[0], reinterpret_cast(Arguments[1]), Arguments[2], Arguments[3]); - break; - } - default: LOGMAN_MSG_A_FMT("Unsupported socketcall op: {}", call); break; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(sendmsg, [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, const struct msghdr32* msg, int flags) -> uint64_t { - return SendMsg(sockfd, msg, flags); - }); - - REGISTER_SYSCALL_IMPL_X32(sendmmsg, - [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, auto_compat_ptr msgvec, uint32_t vlen, - int flags) -> uint64_t { return SendMMsg(sockfd, msgvec, vlen, flags); }); - - REGISTER_SYSCALL_IMPL_X32(recvmmsg, - [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, auto_compat_ptr msgvec, uint32_t vlen, - int flags, timespec32* timeout_ts) -> uint64_t { - struct timespec tp64 {}; - struct timespec* timed_ptr {}; - if (timeout_ts) { - tp64 = *timeout_ts; - timed_ptr = &tp64; - } - - uint64_t Result = RecvMMsg(sockfd, msgvec, vlen, flags, timed_ptr); - - if (timeout_ts) { - *timeout_ts = tp64; - } - - return Result; - }); - - REGISTER_SYSCALL_IMPL_X32(recvmmsg_time64, - [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, auto_compat_ptr msgvec, uint32_t vlen, int flags, - struct timespec* timeout_ts) -> uint64_t { return RecvMMsg(sockfd, msgvec, vlen, flags, timeout_ts); }); - - REGISTER_SYSCALL_IMPL_X32(recvmsg, [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, struct msghdr32* msg, int flags) -> uint64_t { - return RecvMsg(sockfd, msg, flags); - }); - - REGISTER_SYSCALL_IMPL_X32(setsockopt, - [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, int level, int optname, auto_compat_ptr optval, - socklen_t optlen) -> uint64_t { return SetSockOpt(sockfd, level, optname, optval, optlen); }); - - REGISTER_SYSCALL_IMPL_X32(getsockopt, - [](FEXCore::Core::CpuStateFrame* Frame, int sockfd, int level, int optname, auto_compat_ptr optval, - auto_compat_ptr optlen) -> uint64_t { return GetSockOpt(sockfd, level, optname, optval, optlen); }); +auto sendmmsg(FEXCore::Core::CpuStateFrame* Frame, int sockfd, auto_compat_ptr msgvec, uint32_t vlen, int flags) -> uint64_t { + return SendMMsg(sockfd, msgvec, vlen, flags); +} + +auto recvmmsg(FEXCore::Core::CpuStateFrame* Frame, int sockfd, auto_compat_ptr msgvec, uint32_t vlen, int flags, + timespec32* timeout_ts) -> uint64_t { + struct timespec tp64 {}; + struct timespec* timed_ptr {}; + if (timeout_ts) { + tp64 = *timeout_ts; + timed_ptr = &tp64; + } + + uint64_t Result = RecvMMsg(sockfd, msgvec, vlen, flags, timed_ptr); + + if (timeout_ts) { + *timeout_ts = tp64; + } + + return Result; +} + +auto recvmmsg_time64(FEXCore::Core::CpuStateFrame* Frame, int sockfd, auto_compat_ptr msgvec, uint32_t vlen, int flags, + struct timespec* timeout_ts) -> uint64_t { + return RecvMMsg(sockfd, msgvec, vlen, flags, timeout_ts); +} + +auto recvmsg(FEXCore::Core::CpuStateFrame* Frame, int sockfd, struct msghdr32* msg, int flags) -> uint64_t { + return RecvMsg(sockfd, msg, flags); +} + +auto setsockopt(FEXCore::Core::CpuStateFrame* Frame, int sockfd, int level, int optname, auto_compat_ptr optval, socklen_t optlen) -> uint64_t { + return SetSockOpt(sockfd, level, optname, optval, optlen); +} + +auto getsockopt(FEXCore::Core::CpuStateFrame* Frame, int sockfd, int level, int optname, auto_compat_ptr optval, + auto_compat_ptr optlen) -> uint64_t { + return GetSockOpt(sockfd, level, optname, optval, optlen); +} + +void RegisterSocket(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(socketcall, socketcall); + REGISTER_SYSCALL_IMPL_X32(sendmsg, sendmsg); + REGISTER_SYSCALL_IMPL_X32(sendmmsg, sendmmsg); + REGISTER_SYSCALL_IMPL_X32(recvmmsg, recvmmsg); + REGISTER_SYSCALL_IMPL_X32(recvmmsg_time64, recvmmsg_time64); + REGISTER_SYSCALL_IMPL_X32(recvmsg, recvmsg); + REGISTER_SYSCALL_IMPL_X32(setsockopt, setsockopt); + REGISTER_SYSCALL_IMPL_X32(getsockopt, getsockopt); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Stubs.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Stubs.cpp index c35c2ba40c..575cbca1ec 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Stubs.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Stubs.cpp @@ -25,13 +25,26 @@ struct CpuStateFrame; } namespace FEX::HLE::x32 { -void RegisterStubs(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(modify_ldt, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { SYSCALL_STUB(readdir); }); +auto modify_ldt(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + SYSCALL_STUB(readdir); +} - REGISTER_SYSCALL_IMPL_X32(readdir, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { SYSCALL_STUB(readdir); }); +auto readdir(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + SYSCALL_STUB(readdir); +} - REGISTER_SYSCALL_IMPL_X32(vm86old, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -ENOSYS; }); +auto vm86old(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + return -ENOSYS; +} - REGISTER_SYSCALL_IMPL_X32(vm86, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { return -ENOSYS; }); +auto vm86(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + return -ENOSYS; +} + +void RegisterStubs(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(modify_ldt, modify_ldt); + REGISTER_SYSCALL_IMPL_X32(readdir, readdir); + REGISTER_SYSCALL_IMPL_X32(vm86old, vm86old); + REGISTER_SYSCALL_IMPL_X32(vm86, vm86); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp index 476ded336c..47700c71b3 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Thread.cpp @@ -101,267 +101,278 @@ void AdjustRipForNewThread(FEXCore::Core::CpuStateFrame* Frame) { Frame->State.rip += 2; } -void RegisterThread(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(sigreturn, [](FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { - FEX::HLE::_SyscallHandler->GetSignalDelegator()->HandleSignalHandlerReturn(false); - FEX_UNREACHABLE; - }); - - 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 { - // This is slightly different EFAULT behaviour, if child_tid or parent_tid is invalid then the kernel just doesn't write to the - // pointer. Still need to be EFAULT safe although. - if ((flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && child_tid) { - FaultSafeUserMemAccess::VerifyIsWritable(child_tid, sizeof(*child_tid)); - } +auto sigreturn(FEXCore::Core::CpuStateFrame* Frame) -> uint64_t { + FEX::HLE::_SyscallHandler->GetSignalDelegator()->HandleSignalHandlerReturn(false); + FEX_UNREACHABLE; +} - if ((flags & CLONE_PARENT_SETTID) && parent_tid) { - FaultSafeUserMemAccess::VerifyIsWritable(parent_tid, sizeof(*parent_tid)); - } +auto clone(FEXCore::Core::CpuStateFrame* Frame, uint32_t flags, void* stack, pid_t* parent_tid, void* tls, pid_t* child_tid) -> uint64_t { + // This is slightly different EFAULT behaviour, if child_tid or parent_tid is invalid then the kernel just doesn't write to the + // pointer. Still need to be EFAULT safe although. + if ((flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && child_tid) { + FaultSafeUserMemAccess::VerifyIsWritable(child_tid, sizeof(*child_tid)); + } + if ((flags & CLONE_PARENT_SETTID) && parent_tid) { + FaultSafeUserMemAccess::VerifyIsWritable(parent_tid, sizeof(*parent_tid)); + } - FEX::HLE::clone3_args args {.Type = TypeOfClone::TYPE_CLONE2, - .args = { - .flags = flags & ~CSIGNAL, // This no longer contains CSIGNAL - .pidfd = reinterpret_cast(parent_tid), // For clone, pidfd is duplicated here - .child_tid = reinterpret_cast(child_tid), - .parent_tid = reinterpret_cast(parent_tid), - .exit_signal = flags & CSIGNAL, - .stack = reinterpret_cast(stack), - .stack_size = 0, // This syscall isn't able to see the stack size - .tls = reinterpret_cast(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); - FaultSafeUserMemAccess::VerifyIsWritableOrNull(status, sizeof(*status)); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(nice, [](FEXCore::Core::CpuStateFrame* Frame, int inc) -> uint64_t { - uint64_t Result = ::nice(inc); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - set_thread_area, [](FEXCore::Core::CpuStateFrame* Frame, struct user_desc* u_info) -> uint64_t { return SetThreadArea(Frame, u_info); }); - - REGISTER_SYSCALL_IMPL_X32(get_thread_area, [](FEXCore::Core::CpuStateFrame* Frame, struct user_desc* u_info) -> uint64_t { - // Index to fetch comes from the user_desc - uint32_t Entry = u_info->entry_number; - if (Entry < TLS_NextEntry || Entry > TLS_MaxEntry) { - return -EINVAL; - } - FaultSafeUserMemAccess::VerifyIsWritable(u_info, sizeof(*u_info)); + FEX::HLE::clone3_args args {.Type = TypeOfClone::TYPE_CLONE2, + .args = { + .flags = flags & ~CSIGNAL, // This no longer contains CSIGNAL + .pidfd = reinterpret_cast(parent_tid), // For clone, pidfd is duplicated here + .child_tid = reinterpret_cast(child_tid), + .parent_tid = reinterpret_cast(parent_tid), + .exit_signal = flags & CSIGNAL, + .stack = reinterpret_cast(stack), + .stack_size = 0, // This syscall isn't able to see the stack size + .tls = reinterpret_cast(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); +} - const auto& GDT = &Frame->State.segment_arrays[FEXCore::Core::CPUState::SEGMENT_ARRAY_INDEX_GDT][Entry]; +auto waitpid(FEXCore::Core::CpuStateFrame* Frame, pid_t pid, int32_t* status, int32_t options) -> uint64_t { + uint64_t Result = ::waitpid(pid, status, options); + FaultSafeUserMemAccess::VerifyIsWritableOrNull(status, sizeof(*status)); + SYSCALL_ERRNO(); +} - memset(u_info, 0, sizeof(*u_info)); +auto nice(FEXCore::Core::CpuStateFrame* Frame, int inc) -> uint64_t { + uint64_t Result = ::nice(inc); + SYSCALL_ERRNO(); +} - // FEX only stores base instead of the full GDT - u_info->base_addr = Frame->State.CalculateGDTBase(*GDT); +auto set_thread_area(FEXCore::Core::CpuStateFrame* Frame, struct user_desc* u_info) -> uint64_t { + return SetThreadArea(Frame, u_info); +} - // Fill the rest of the structure with expected data (even if wrong at the moment) - if (u_info->base_addr) { - u_info->limit = 0xF'FFFF; - u_info->seg_32bit = 1; - u_info->limit_in_pages = 1; - u_info->useable = 1; - } else { - u_info->read_exec_only = 1; - u_info->seg_not_present = 1; - } - return 0; - }); +auto get_thread_area(FEXCore::Core::CpuStateFrame* Frame, struct user_desc* u_info) -> uint64_t { + // Index to fetch comes from the user_desc + uint32_t Entry = u_info->entry_number; + if (Entry < TLS_NextEntry || Entry > TLS_MaxEntry) { + return -EINVAL; + } - REGISTER_SYSCALL_IMPL_X32(set_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, struct robust_list_head* head, size_t len) -> uint64_t { - if (len != 12) { - // Return invalid if the passed in length doesn't match what's expected. - return -EINVAL; - } + FaultSafeUserMemAccess::VerifyIsWritable(u_info, sizeof(*u_info)); - auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame); - // Retain the robust list head but don't give it to the kernel - // The kernel would break if it tried parsing a 32bit robust list from a 64bit process - ThreadObject->ThreadInfo.robust_list_head = reinterpret_cast(head); - return 0; - }); - - REGISTER_SYSCALL_IMPL_X32( - get_robust_list, [](FEXCore::Core::CpuStateFrame* Frame, int pid, struct robust_list_head** head, uint32_t* len_ptr) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsWritable(head, sizeof(uint32_t)); - FaultSafeUserMemAccess::VerifyIsWritable(len_ptr, sizeof(*len_ptr)); - - auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame); - // Give the robust list back to the application - // Steam specifically checks to make sure the robust list is set - *(uint32_t*)head = (uint32_t)ThreadObject->ThreadInfo.robust_list_head; - *len_ptr = 12; - return 0; - }); - - REGISTER_SYSCALL_IMPL_X32( - futex, [](FEXCore::Core::CpuStateFrame* Frame, int* uaddr, int futex_op, int val, const timespec32* timeout, int* uaddr2, uint32_t val3) -> uint64_t { - void* timeout_ptr = (void*)timeout; - struct timespec tp64 {}; - int cmd = futex_op & FUTEX_CMD_MASK; - if (timeout && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || cmd == FUTEX_WAIT_BITSET || cmd == FUTEX_WAIT_REQUEUE_PI)) { - FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); - // timeout argument is only handled as timespec in these cases - // Otherwise just an integer - tp64 = *timeout; - timeout_ptr = &tp64; - } + const auto& GDT = &Frame->State.segment_arrays[FEXCore::Core::CPUState::SEGMENT_ARRAY_INDEX_GDT][Entry]; - uint64_t Result = syscall(SYSCALL_DEF(futex), uaddr, futex_op, val, timeout_ptr, uaddr2, val3); - SYSCALL_ERRNO(); - }); + memset(u_info, 0, sizeof(*u_info)); - REGISTER_SYSCALL_IMPL_X32( - sigaltstack, [](FEXCore::Core::CpuStateFrame* Frame, const compat_ptr ss, compat_ptr old_ss) -> uint64_t { - stack_t ss64 {}; - stack_t old64 {}; + // FEX only stores base instead of the full GDT + u_info->base_addr = Frame->State.CalculateGDTBase(*GDT); - stack_t* ss64_ptr {}; - stack_t* old64_ptr {}; + // Fill the rest of the structure with expected data (even if wrong at the moment) + if (u_info->base_addr) { + u_info->limit = 0xF'FFFF; + u_info->seg_32bit = 1; + u_info->limit_in_pages = 1; + u_info->useable = 1; + } else { + u_info->read_exec_only = 1; + u_info->seg_not_present = 1; + } + return 0; +} - if (ss) { - FaultSafeUserMemAccess::VerifyIsReadable(ss, sizeof(*ss)); - ss64 = *ss; - ss64_ptr = &ss64; - } +auto set_robust_list(FEXCore::Core::CpuStateFrame* Frame, struct robust_list_head* head, size_t len) -> uint64_t { + if (len != 12) { + // Return invalid if the passed in length doesn't match what's expected. + return -EINVAL; + } - if (old_ss) { - FaultSafeUserMemAccess::VerifyIsReadable(old_ss, sizeof(*old_ss)); - old64 = *old_ss; - old64_ptr = &old64; - } - uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack( - FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), ss64_ptr, old64_ptr); + auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame); + // Retain the robust list head but don't give it to the kernel + // The kernel would break if it tried parsing a 32bit robust list from a 64bit process + ThreadObject->ThreadInfo.robust_list_head = reinterpret_cast(head); + return 0; +} - if (Result == 0 && old_ss) { - FaultSafeUserMemAccess::VerifyIsWritable(old_ss, sizeof(*old_ss)); - *old_ss = old64; - } - return Result; - }); - - // launch a new process under fex - // currently does not propagate argv[0] correctly - REGISTER_SYSCALL_IMPL_X32(execve, [](FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uint32_t* argv, uint32_t* envp) -> uint64_t { - fextl::vector Args; - fextl::vector Envp; - - if (argv) { - for (int i = 0; argv[i]; i++) { - Args.push_back(reinterpret_cast(static_cast(argv[i]))); - } +auto get_robust_list(FEXCore::Core::CpuStateFrame* Frame, int pid, struct robust_list_head** head, uint32_t* len_ptr) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsWritable(head, sizeof(uint32_t)); + FaultSafeUserMemAccess::VerifyIsWritable(len_ptr, sizeof(*len_ptr)); + + auto ThreadObject = FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame); + // Give the robust list back to the application + // Steam specifically checks to make sure the robust list is set + *(uint32_t*)head = (uint32_t)ThreadObject->ThreadInfo.robust_list_head; + *len_ptr = 12; + return 0; +} + +auto futex(FEXCore::Core::CpuStateFrame* Frame, int* uaddr, int futex_op, int val, const timespec32* timeout, int* uaddr2, uint32_t val3) + -> uint64_t { + void* timeout_ptr = (void*)timeout; + struct timespec tp64 {}; + int cmd = futex_op & FUTEX_CMD_MASK; + if (timeout && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || cmd == FUTEX_WAIT_BITSET || cmd == FUTEX_WAIT_REQUEUE_PI)) { + FaultSafeUserMemAccess::VerifyIsReadable(timeout, sizeof(*timeout)); + // timeout argument is only handled as timespec in these cases + // Otherwise just an integer + tp64 = *timeout; + timeout_ptr = &tp64; + } + + uint64_t Result = syscall(SYSCALL_DEF(futex), uaddr, futex_op, val, timeout_ptr, uaddr2, val3); + SYSCALL_ERRNO(); +} + +auto sigaltstack(FEXCore::Core::CpuStateFrame* Frame, const compat_ptr ss, compat_ptr old_ss) -> uint64_t { + stack_t ss64 {}; + stack_t old64 {}; + + stack_t* ss64_ptr {}; + stack_t* old64_ptr {}; + + if (ss) { + FaultSafeUserMemAccess::VerifyIsReadable(ss, sizeof(*ss)); + ss64 = *ss; + ss64_ptr = &ss64; + } + + if (old_ss) { + FaultSafeUserMemAccess::VerifyIsReadable(old_ss, sizeof(*old_ss)); + old64 = *old_ss; + old64_ptr = &old64; + } + uint64_t Result = FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack( + FEX::HLE::ThreadManager::GetStateObjectFromCPUState(Frame), ss64_ptr, old64_ptr); - Args.push_back(nullptr); + if (Result == 0 && old_ss) { + FaultSafeUserMemAccess::VerifyIsWritable(old_ss, sizeof(*old_ss)); + *old_ss = old64; + } + return Result; +} + +// launch a new process under fex +// currently does not propagate argv[0] correctly +auto execve(FEXCore::Core::CpuStateFrame* Frame, const char* pathname, uint32_t* argv, uint32_t* envp) -> uint64_t { + fextl::vector Args; + fextl::vector Envp; + + if (argv) { + for (int i = 0; argv[i]; i++) { + Args.push_back(reinterpret_cast(static_cast(argv[i]))); } - if (envp) { - for (int i = 0; envp[i]; i++) { - Envp.push_back(reinterpret_cast(static_cast(envp[i]))); - } - Envp.push_back(nullptr); + Args.push_back(nullptr); + } + + if (envp) { + for (int i = 0; envp[i]; i++) { + Envp.push_back(reinterpret_cast(static_cast(envp[i]))); } + Envp.push_back(nullptr); + } - auto* const* ArgsPtr = argv ? const_cast(Args.data()) : nullptr; - auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; + auto* const* ArgsPtr = argv ? const_cast(Args.data()) : nullptr; + auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; - FEX::HLE::ExecveAtArgs AtArgs = FEX::HLE::ExecveAtArgs::Empty(); + FEX::HLE::ExecveAtArgs AtArgs = FEX::HLE::ExecveAtArgs::Empty(); - return FEX::HLE::ExecveHandler(Frame, pathname, ArgsPtr, EnvpPtr, AtArgs); - }); + return FEX::HLE::ExecveHandler(Frame, pathname, ArgsPtr, EnvpPtr, AtArgs); +} - REGISTER_SYSCALL_IMPL_X32( - execveat, ([](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, uint32_t* argv, uint32_t* envp, int flags) -> uint64_t { - fextl::vector Args; - fextl::vector Envp; +auto execveat(FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, uint32_t* argv, uint32_t* envp, int flags) -> uint64_t { + fextl::vector Args; + fextl::vector Envp; - if (argv) { - for (int i = 0; argv[i]; i++) { - Args.push_back(reinterpret_cast(static_cast(argv[i]))); - } + if (argv) { + for (int i = 0; argv[i]; i++) { + Args.push_back(reinterpret_cast(static_cast(argv[i]))); + } - Args.push_back(nullptr); - } + Args.push_back(nullptr); + } - if (envp) { - for (int i = 0; envp[i]; i++) { - Envp.push_back(reinterpret_cast(static_cast(envp[i]))); - } - Envp.push_back(nullptr); - } + if (envp) { + for (int i = 0; envp[i]; i++) { + Envp.push_back(reinterpret_cast(static_cast(envp[i]))); + } + Envp.push_back(nullptr); + } - FEX::HLE::ExecveAtArgs AtArgs { - .dirfd = dirfd, - .flags = flags, - }; + FEX::HLE::ExecveAtArgs AtArgs { + .dirfd = dirfd, + .flags = flags, + }; - auto* const* ArgsPtr = argv ? const_cast(Args.data()) : nullptr; - auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; - return FEX::HLE::ExecveHandler(Frame, pathname, ArgsPtr, EnvpPtr, AtArgs); - })); + auto* const* ArgsPtr = argv ? const_cast(Args.data()) : nullptr; + auto* const* EnvpPtr = envp ? const_cast(Envp.data()) : nullptr; + return FEX::HLE::ExecveHandler(Frame, pathname, ArgsPtr, EnvpPtr, 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 {}; +auto 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 {}; - if (rusage) { - FaultSafeUserMemAccess::VerifyIsReadable(rusage, sizeof(*rusage)); - usage64 = *rusage; - usage64_p = &usage64; - } - uint64_t Result = ::wait4(pid, wstatus, options, usage64_p); + if (rusage) { + FaultSafeUserMemAccess::VerifyIsReadable(rusage, sizeof(*rusage)); + usage64 = *rusage; + usage64_p = &usage64; + } + uint64_t Result = ::wait4(pid, wstatus, options, usage64_p); + if (rusage) { + FaultSafeUserMemAccess::VerifyIsWritable(rusage, sizeof(*rusage)); + *rusage = usage64; + } + SYSCALL_ERRNO(); +} + +auto waitid(FEXCore::Core::CpuStateFrame* Frame, int which, pid_t upid, compat_ptr info, int options, + struct rusage_32* rusage) -> uint64_t { + struct rusage usage64 {}; + struct rusage* usage64_p {}; + + siginfo_t info64 {}; + siginfo_t* info64_p {}; + + if (rusage) { + FaultSafeUserMemAccess::VerifyIsReadable(rusage, sizeof(*rusage)); + usage64 = *rusage; + usage64_p = &usage64; + } + + if (info) { + info64_p = &info64; + } + + uint64_t Result = ::syscall(SYSCALL_DEF(waitid), which, upid, info64_p, options, usage64_p); + + if (Result != -1) { if (rusage) { FaultSafeUserMemAccess::VerifyIsWritable(rusage, sizeof(*rusage)); *rusage = usage64; } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(waitid, - [](FEXCore::Core::CpuStateFrame* Frame, int which, pid_t upid, compat_ptr info, - int options, struct rusage_32* rusage) -> uint64_t { - struct rusage usage64 {}; - struct rusage* usage64_p {}; - - siginfo_t info64 {}; - siginfo_t* info64_p {}; - - if (rusage) { - FaultSafeUserMemAccess::VerifyIsReadable(rusage, sizeof(*rusage)); - usage64 = *rusage; - usage64_p = &usage64; - } - - if (info) { - info64_p = &info64; - } - - uint64_t Result = ::syscall(SYSCALL_DEF(waitid), which, upid, info64_p, options, usage64_p); - - if (Result != -1) { - if (rusage) { - FaultSafeUserMemAccess::VerifyIsWritable(rusage, sizeof(*rusage)); - *rusage = usage64; - } - - if (info) { - FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); - *info = info64; - } - } - - SYSCALL_ERRNO(); - }); + + if (info) { + FaultSafeUserMemAccess::VerifyIsWritable(info, sizeof(*info)); + *info = info64; + } + } + + SYSCALL_ERRNO(); +} + +void RegisterThread(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(sigreturn, sigreturn); + REGISTER_SYSCALL_IMPL_X32(clone, clone); + REGISTER_SYSCALL_IMPL_X32(waitpid, waitpid); + REGISTER_SYSCALL_IMPL_X32(nice, nice); + REGISTER_SYSCALL_IMPL_X32(set_thread_area, set_thread_area); + REGISTER_SYSCALL_IMPL_X32(get_thread_area, get_thread_area); + REGISTER_SYSCALL_IMPL_X32(set_robust_list, set_robust_list); + REGISTER_SYSCALL_IMPL_X32(get_robust_list, get_robust_list); + REGISTER_SYSCALL_IMPL_X32(futex, futex); + REGISTER_SYSCALL_IMPL_X32(sigaltstack, sigaltstack); + REGISTER_SYSCALL_IMPL_X32(execve, execve); + REGISTER_SYSCALL_IMPL_X32(execveat, execveat); + REGISTER_SYSCALL_IMPL_X32(wait4, wait4); + REGISTER_SYSCALL_IMPL_X32(waitid, waitid); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp index 31109b8964..db10e56385 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Time.cpp @@ -29,218 +29,230 @@ struct CpuStateFrame; } namespace FEX::HLE::x32 { -void RegisterTime(FEX::HLE::SyscallHandler* Handler) { +auto time(FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::x32::old_time32_t* tloc) -> uint64_t { + time_t Host {}; + uint64_t Result = ::time(&Host); + + if (tloc) { + FaultSafeUserMemAccess::VerifyIsWritable(tloc, sizeof(*tloc)); + // On 32-bit this truncates + *tloc = (FEX::HLE::x32::old_time32_t)Host; + } + + SYSCALL_ERRNO(); +} + +auto times(FEXCore::Core::CpuStateFrame* Frame, struct FEX::HLE::x32::compat_tms* buf) -> uint64_t { + struct tms Host {}; + uint64_t Result = ::times(&Host); + if (buf) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = Host; + } + SYSCALL_ERRNO(); +} + +auto utime(FEXCore::Core::CpuStateFrame* Frame, char* filename, const FEX::HLE::x32::old_utimbuf32* times) -> uint64_t { + struct utimbuf Host {}; + struct utimbuf* Host_p {}; + if (times) { + FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(*times)); + Host = *times; + Host_p = &Host; + } + uint64_t Result = ::utime(filename, Host_p); + SYSCALL_ERRNO(); +} + +auto gettimeofday(FEXCore::Core::CpuStateFrame* Frame, timeval32* tv, struct timezone* tz) -> uint64_t { + struct timeval tv64 {}; + struct timeval* tv_ptr {}; + if (tv) { + tv_ptr = &tv64; + } + + uint64_t Result = ::gettimeofday(tv_ptr, tz); + + if (tv) { + FaultSafeUserMemAccess::VerifyIsWritable(tv, sizeof(*tv)); + *tv = tv64; + } + SYSCALL_ERRNO(); +} + +auto settimeofday(FEXCore::Core::CpuStateFrame* Frame, const timeval32* tv, const struct timezone* tz) -> uint64_t { + struct timeval tv64 {}; + struct timeval* tv_ptr {}; + if (tv) { + FaultSafeUserMemAccess::VerifyIsReadable(tv, sizeof(*tv)); + tv64 = *tv; + tv_ptr = &tv64; + } + + const uint64_t Result = ::settimeofday(tv_ptr, tz); + SYSCALL_ERRNO(); +} + +auto nanosleep(FEXCore::Core::CpuStateFrame* Frame, const timespec32* req, timespec32* rem) -> uint64_t { + struct timespec rem64 {}; + struct timespec* rem64_ptr {}; + + if (rem) { + FaultSafeUserMemAccess::VerifyIsReadable(rem, sizeof(*rem)); + rem64 = *rem; + rem64_ptr = &rem64; + } + + uint64_t Result = 0; + if (req) { + FaultSafeUserMemAccess::VerifyIsReadable(req, sizeof(*req)); + const struct timespec req64 = *req; + Result = ::nanosleep(&req64, rem64_ptr); + } else { + Result = ::nanosleep(nullptr, rem64_ptr); + } + + if (rem) { + FaultSafeUserMemAccess::VerifyIsWritable(rem, sizeof(*rem)); + *rem = rem64; + } + SYSCALL_ERRNO(); +} + +auto clock_gettime(FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, timespec32* tp) -> uint64_t { + struct timespec tp64 {}; + uint64_t Result = ::clock_gettime(clk_id, &tp64); + if (tp) { + FaultSafeUserMemAccess::VerifyIsWritable(tp, sizeof(*tp)); + *tp = tp64; + } + SYSCALL_ERRNO(); +} - REGISTER_SYSCALL_IMPL_X32(time, [](FEXCore::Core::CpuStateFrame* Frame, FEX::HLE::x32::old_time32_t* tloc) -> uint64_t { - time_t Host {}; - uint64_t Result = ::time(&Host); - - if (tloc) { - FaultSafeUserMemAccess::VerifyIsWritable(tloc, sizeof(*tloc)); - // On 32-bit this truncates - *tloc = (FEX::HLE::x32::old_time32_t)Host; - } - - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(times, [](FEXCore::Core::CpuStateFrame* Frame, struct FEX::HLE::x32::compat_tms* buf) -> uint64_t { - struct tms Host {}; - uint64_t Result = ::times(&Host); - if (buf) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = Host; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(utime, [](FEXCore::Core::CpuStateFrame* Frame, char* filename, const FEX::HLE::x32::old_utimbuf32* times) -> uint64_t { - struct utimbuf Host {}; - struct utimbuf* Host_p {}; - if (times) { - FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(*times)); - Host = *times; - Host_p = &Host; - } - uint64_t Result = ::utime(filename, Host_p); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(gettimeofday, [](FEXCore::Core::CpuStateFrame* Frame, timeval32* tv, struct timezone* tz) -> uint64_t { - struct timeval tv64 {}; - struct timeval* tv_ptr {}; - if (tv) { - tv_ptr = &tv64; - } - - uint64_t Result = ::gettimeofday(tv_ptr, tz); - - if (tv) { - FaultSafeUserMemAccess::VerifyIsWritable(tv, sizeof(*tv)); - *tv = tv64; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(settimeofday, [](FEXCore::Core::CpuStateFrame* Frame, const timeval32* tv, const struct timezone* tz) -> uint64_t { - struct timeval tv64 {}; - struct timeval* tv_ptr {}; - if (tv) { - FaultSafeUserMemAccess::VerifyIsReadable(tv, sizeof(*tv)); - tv64 = *tv; - tv_ptr = &tv64; - } - - const uint64_t Result = ::settimeofday(tv_ptr, tz); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(nanosleep, [](FEXCore::Core::CpuStateFrame* Frame, const timespec32* req, timespec32* rem) -> uint64_t { - struct timespec rem64 {}; - struct timespec* rem64_ptr {}; - - if (rem) { - FaultSafeUserMemAccess::VerifyIsReadable(rem, sizeof(*rem)); - rem64 = *rem; - rem64_ptr = &rem64; - } - - uint64_t Result = 0; - if (req) { - FaultSafeUserMemAccess::VerifyIsReadable(req, sizeof(*req)); - const struct timespec req64 = *req; - Result = ::nanosleep(&req64, rem64_ptr); - } else { - Result = ::nanosleep(nullptr, rem64_ptr); - } - - if (rem) { - FaultSafeUserMemAccess::VerifyIsWritable(rem, sizeof(*rem)); - *rem = rem64; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(clock_gettime, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, timespec32* tp) -> uint64_t { - struct timespec tp64 {}; - uint64_t Result = ::clock_gettime(clk_id, &tp64); - if (tp) { - FaultSafeUserMemAccess::VerifyIsWritable(tp, sizeof(*tp)); - *tp = tp64; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(clock_getres, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, timespec32* tp) -> uint64_t { - struct timespec tp64 {}; - uint64_t Result = ::clock_getres(clk_id, &tp64); - if (tp) { - FaultSafeUserMemAccess::VerifyIsWritable(tp, sizeof(*tp)); - *tp = tp64; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - clock_nanosleep, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, int flags, const timespec32* request, timespec32* remain) -> uint64_t { - struct timespec req64 {}; - struct timespec* req64_ptr {}; - - struct timespec rem64 {}; - struct timespec* rem64_ptr {}; - - if (request) { - FaultSafeUserMemAccess::VerifyIsReadable(request, sizeof(*request)); - req64 = *request; - req64_ptr = &req64; - } - - if (remain) { - FaultSafeUserMemAccess::VerifyIsReadable(remain, sizeof(*remain)); - rem64 = *remain; - rem64_ptr = &rem64; - } - - // Can't use glibc helper here since it does additional validation and data munging that breaks games. - uint64_t Result = ::syscall(SYSCALL_DEF(clock_nanosleep), clockid, flags, req64_ptr, rem64_ptr); - - if (remain && (flags & TIMER_ABSTIME) == 0) { - FaultSafeUserMemAccess::VerifyIsWritable(remain, sizeof(*remain)); - // Remain is completely ignored if TIMER_ABSTIME is set. - *remain = rem64; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(clock_settime, [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, const timespec32* tp) -> uint64_t { - if (!tp) { - // clock_settime is required to pass a timespec. - return -EFAULT; - } - - uint64_t Result = 0; - FaultSafeUserMemAccess::VerifyIsReadable(tp, sizeof(*tp)); - const struct timespec tp64 = *tp; - Result = ::clock_settime(clockid, &tp64); - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(futimesat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const timeval32 times[2]) -> uint64_t { - return FEX::HLE::futimesat_compat(dirfd, pathname, times); - }); - - REGISTER_SYSCALL_IMPL_X32( - utimensat, [](FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const compat_ptr times, int flags) -> uint64_t { - uint64_t Result = 0; - if (times) { - FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(timeval32) * 2); - timespec times64[2] {}; - times64[0] = times[0]; - times64[1] = times[1]; - Result = ::syscall(SYSCALL_DEF(utimensat), dirfd, pathname, times64, flags); - } else { - Result = ::syscall(SYSCALL_DEF(utimensat), dirfd, pathname, nullptr, flags); - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(utimes, [](FEXCore::Core::CpuStateFrame* Frame, const char* filename, const timeval32 times[2]) -> uint64_t { - uint64_t Result = 0; - if (times) { - FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(timeval32) * 2); - struct timeval times64[2] {}; - times64[0] = times[0]; - times64[1] = times[1]; - Result = ::utimes(filename, times64); - } else { - Result = ::utimes(filename, nullptr); - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(adjtimex, [](FEXCore::Core::CpuStateFrame* Frame, compat_ptr buf) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(buf, sizeof(*buf)); - struct timex Host {}; - Host = *buf; - uint64_t Result = ::adjtimex(&Host); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = Host; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(clock_adjtime, - [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, compat_ptr buf) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(buf, sizeof(*buf)); - struct timex Host {}; - Host = *buf; - uint64_t Result = ::clock_adjtime(clk_id, &Host); - if (Result != -1) { - FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); - *buf = Host; - } - SYSCALL_ERRNO(); - }); +auto clock_getres(FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, timespec32* tp) -> uint64_t { + struct timespec tp64 {}; + uint64_t Result = ::clock_getres(clk_id, &tp64); + if (tp) { + FaultSafeUserMemAccess::VerifyIsWritable(tp, sizeof(*tp)); + *tp = tp64; + } + SYSCALL_ERRNO(); +} + +auto clock_nanosleep(FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, int flags, const timespec32* request, timespec32* remain) -> uint64_t { + struct timespec req64 {}; + struct timespec* req64_ptr {}; + + struct timespec rem64 {}; + struct timespec* rem64_ptr {}; + + if (request) { + FaultSafeUserMemAccess::VerifyIsReadable(request, sizeof(*request)); + req64 = *request; + req64_ptr = &req64; + } + + if (remain) { + FaultSafeUserMemAccess::VerifyIsReadable(remain, sizeof(*remain)); + rem64 = *remain; + rem64_ptr = &rem64; + } + + // Can't use glibc helper here since it does additional validation and data munging that breaks games. + uint64_t Result = ::syscall(SYSCALL_DEF(clock_nanosleep), clockid, flags, req64_ptr, rem64_ptr); + + if (remain && (flags & TIMER_ABSTIME) == 0) { + FaultSafeUserMemAccess::VerifyIsWritable(remain, sizeof(*remain)); + // Remain is completely ignored if TIMER_ABSTIME is set. + *remain = rem64; + } + SYSCALL_ERRNO(); +} + +auto clock_settime(FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, const timespec32* tp) -> uint64_t { + if (!tp) { + // clock_settime is required to pass a timespec. + return -EFAULT; + } + + uint64_t Result = 0; + FaultSafeUserMemAccess::VerifyIsReadable(tp, sizeof(*tp)); + const struct timespec tp64 = *tp; + Result = ::clock_settime(clockid, &tp64); + SYSCALL_ERRNO(); +} + +auto futimesat(FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const timeval32 times[2]) -> uint64_t { + return FEX::HLE::futimesat_compat(dirfd, pathname, times); +} + +auto utimensat(FEXCore::Core::CpuStateFrame* Frame, int dirfd, const char* pathname, const compat_ptr times, int flags) -> uint64_t { + uint64_t Result = 0; + if (times) { + FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(timeval32) * 2); + timespec times64[2] {}; + times64[0] = times[0]; + times64[1] = times[1]; + Result = ::syscall(SYSCALL_DEF(utimensat), dirfd, pathname, times64, flags); + } else { + Result = ::syscall(SYSCALL_DEF(utimensat), dirfd, pathname, nullptr, flags); + } + SYSCALL_ERRNO(); +} + +auto utimes(FEXCore::Core::CpuStateFrame* Frame, const char* filename, const timeval32 times[2]) -> uint64_t { + uint64_t Result = 0; + if (times) { + FaultSafeUserMemAccess::VerifyIsReadable(times, sizeof(timeval32) * 2); + struct timeval times64[2] {}; + times64[0] = times[0]; + times64[1] = times[1]; + Result = ::utimes(filename, times64); + } else { + Result = ::utimes(filename, nullptr); + } + SYSCALL_ERRNO(); +} + +auto adjtimex(FEXCore::Core::CpuStateFrame* Frame, compat_ptr buf) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(buf, sizeof(*buf)); + struct timex Host {}; + Host = *buf; + uint64_t Result = ::adjtimex(&Host); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = Host; + } + SYSCALL_ERRNO(); +} + +auto clock_adjtime(FEXCore::Core::CpuStateFrame* Frame, clockid_t clk_id, compat_ptr buf) -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(buf, sizeof(*buf)); + struct timex Host {}; + Host = *buf; + uint64_t Result = ::clock_adjtime(clk_id, &Host); + if (Result != -1) { + FaultSafeUserMemAccess::VerifyIsWritable(buf, sizeof(*buf)); + *buf = Host; + } + SYSCALL_ERRNO(); +} + +void RegisterTime(FEX::HLE::SyscallHandler* Handler) { + REGISTER_SYSCALL_IMPL_X32(time, time); + REGISTER_SYSCALL_IMPL_X32(times, times); + REGISTER_SYSCALL_IMPL_X32(utime, utime); + REGISTER_SYSCALL_IMPL_X32(gettimeofday, gettimeofday); + REGISTER_SYSCALL_IMPL_X32(settimeofday, settimeofday); + REGISTER_SYSCALL_IMPL_X32(nanosleep, nanosleep); + REGISTER_SYSCALL_IMPL_X32(clock_gettime, clock_gettime); + REGISTER_SYSCALL_IMPL_X32(clock_getres, clock_getres); + REGISTER_SYSCALL_IMPL_X32(clock_nanosleep, clock_nanosleep); + REGISTER_SYSCALL_IMPL_X32(clock_settime, clock_settime); + REGISTER_SYSCALL_IMPL_X32(futimesat, futimesat); + REGISTER_SYSCALL_IMPL_X32(utimensat, utimensat); + REGISTER_SYSCALL_IMPL_X32(utimes, utimes); + REGISTER_SYSCALL_IMPL_X32(adjtimex, adjtimex); + REGISTER_SYSCALL_IMPL_X32(clock_adjtime, clock_adjtime); } } // namespace FEX::HLE::x32 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp index 0bb9941e32..2b5ea1f56f 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Timer.cpp @@ -24,84 +24,86 @@ struct CpuStateFrame; ARG_TO_STR(FEX::HLE::x32::compat_ptr, "%lx") namespace FEX::HLE::x32 { +auto timer_settime(FEXCore::Core::CpuStateFrame* Frame, kernel_timer_t timerid, int flags, const FEX::HLE::x32::old_itimerspec32* new_value, + FEX::HLE::x32::old_itimerspec32* old_value) -> uint64_t { + itimerspec new_value_host {}; + itimerspec old_value_host {}; + itimerspec* old_value_host_p {}; + + FaultSafeUserMemAccess::VerifyIsReadable(new_value, sizeof(*new_value)); + new_value_host = *new_value; + if (old_value) { + old_value_host_p = &old_value_host; + } + uint64_t Result = ::syscall(SYSCALL_DEF(timer_settime), timerid, flags, &new_value_host, old_value_host_p); + if (Result != -1 && old_value) { + FaultSafeUserMemAccess::VerifyIsWritable(old_value, sizeof(*old_value)); + *old_value = old_value_host; + } + SYSCALL_ERRNO(); +} + +auto timer_gettime(FEXCore::Core::CpuStateFrame* Frame, kernel_timer_t timerid, FEX::HLE::x32::old_itimerspec32* curr_value) -> uint64_t { + itimerspec curr_value_host {}; + uint64_t Result = ::syscall(SYSCALL_DEF(timer_gettime), timerid, curr_value_host); + FaultSafeUserMemAccess::VerifyIsWritable(curr_value, sizeof(*curr_value)); + *curr_value = curr_value_host; + SYSCALL_ERRNO(); +} + +auto getitimer(FEXCore::Core::CpuStateFrame* Frame, int which, FEX::HLE::x32::itimerval32* curr_value) -> uint64_t { + itimerval val {}; + itimerval* val_p {}; + if (curr_value) { + val_p = &val; + } + uint64_t Result = ::getitimer(which, val_p); + if (curr_value) { + FaultSafeUserMemAccess::VerifyIsWritable(curr_value, sizeof(*curr_value)); + *curr_value = val; + } + SYSCALL_ERRNO(); +} + +auto setitimer(FEXCore::Core::CpuStateFrame* Frame, int which, const FEX::HLE::x32::itimerval32* new_value, + FEX::HLE::x32::itimerval32* old_value) -> uint64_t { + itimerval val {}; + itimerval old {}; + itimerval* val_p {}; + itimerval* old_p {}; + + if (new_value) { + FaultSafeUserMemAccess::VerifyIsReadable(new_value, sizeof(*new_value)); + val = *new_value; + val_p = &val; + } + + if (old_value) { + old_p = &old; + } + + uint64_t Result = ::setitimer(which, val_p, old_p); + + if (old_value) { + FaultSafeUserMemAccess::VerifyIsWritable(old_value, sizeof(*old_value)); + *old_value = old; + } + SYSCALL_ERRNO(); +} + +auto timer_create(FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, compat_ptr sevp, kernel_timer_t* timerid) + -> uint64_t { + FaultSafeUserMemAccess::VerifyIsReadable(sevp, sizeof(*sevp)); + sigevent Host = *sevp; + uint64_t Result = ::syscall(SYSCALL_DEF(timer_create), clockid, &Host, timerid); + SYSCALL_ERRNO(); +} + void RegisterTimer(FEX::HLE::SyscallHandler* Handler) { - REGISTER_SYSCALL_IMPL_X32(timer_settime, - [](FEXCore::Core::CpuStateFrame* Frame, kernel_timer_t timerid, int flags, - const FEX::HLE::x32::old_itimerspec32* new_value, FEX::HLE::x32::old_itimerspec32* old_value) -> uint64_t { - itimerspec new_value_host {}; - itimerspec old_value_host {}; - itimerspec* old_value_host_p {}; - - FaultSafeUserMemAccess::VerifyIsReadable(new_value, sizeof(*new_value)); - new_value_host = *new_value; - if (old_value) { - old_value_host_p = &old_value_host; - } - uint64_t Result = ::syscall(SYSCALL_DEF(timer_settime), timerid, flags, &new_value_host, old_value_host_p); - if (Result != -1 && old_value) { - FaultSafeUserMemAccess::VerifyIsWritable(old_value, sizeof(*old_value)); - *old_value = old_value_host; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - timer_gettime, [](FEXCore::Core::CpuStateFrame* Frame, kernel_timer_t timerid, FEX::HLE::x32::old_itimerspec32* curr_value) -> uint64_t { - itimerspec curr_value_host {}; - uint64_t Result = ::syscall(SYSCALL_DEF(timer_gettime), timerid, curr_value_host); - FaultSafeUserMemAccess::VerifyIsWritable(curr_value, sizeof(*curr_value)); - *curr_value = curr_value_host; - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(getitimer, [](FEXCore::Core::CpuStateFrame* Frame, int which, FEX::HLE::x32::itimerval32* curr_value) -> uint64_t { - itimerval val {}; - itimerval* val_p {}; - if (curr_value) { - val_p = &val; - } - uint64_t Result = ::getitimer(which, val_p); - if (curr_value) { - FaultSafeUserMemAccess::VerifyIsWritable(curr_value, sizeof(*curr_value)); - *curr_value = val; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32(setitimer, - [](FEXCore::Core::CpuStateFrame* Frame, int which, const FEX::HLE::x32::itimerval32* new_value, - FEX::HLE::x32::itimerval32* old_value) -> uint64_t { - itimerval val {}; - itimerval old {}; - itimerval* val_p {}; - itimerval* old_p {}; - - if (new_value) { - FaultSafeUserMemAccess::VerifyIsReadable(new_value, sizeof(*new_value)); - val = *new_value; - val_p = &val; - } - - if (old_value) { - old_p = &old; - } - - uint64_t Result = ::setitimer(which, val_p, old_p); - - if (old_value) { - FaultSafeUserMemAccess::VerifyIsWritable(old_value, sizeof(*old_value)); - *old_value = old; - } - SYSCALL_ERRNO(); - }); - - REGISTER_SYSCALL_IMPL_X32( - timer_create, - [](FEXCore::Core::CpuStateFrame* Frame, clockid_t clockid, compat_ptr sevp, kernel_timer_t* timerid) -> uint64_t { - FaultSafeUserMemAccess::VerifyIsReadable(sevp, sizeof(*sevp)); - sigevent Host = *sevp; - uint64_t Result = ::syscall(SYSCALL_DEF(timer_create), clockid, &Host, timerid); - SYSCALL_ERRNO(); - }); + REGISTER_SYSCALL_IMPL_X32(timer_settime, timer_settime); + REGISTER_SYSCALL_IMPL_X32(timer_gettime, timer_gettime); + REGISTER_SYSCALL_IMPL_X32(getitimer, getitimer); + REGISTER_SYSCALL_IMPL_X32(setitimer, setitimer); + REGISTER_SYSCALL_IMPL_X32(timer_create, timer_create); } } // namespace FEX::HLE::x32