#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qemu/path.h"
+#include "qemu/memfd.h"
+#include "qemu/queue.h"
#include <elf.h>
#include <endian.h>
#include <grp.h>
#include <sched.h>
#include <sys/timex.h>
#include <sys/socket.h>
+#include <linux/sockios.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <poll.h>
#include <linux/icmpv6.h>
#include <linux/errqueue.h>
#include <linux/random.h>
-#include "qemu-common.h"
#ifdef CONFIG_TIMERFD
#include <sys/timerfd.h>
#endif
#include <linux/kd.h>
#include <linux/mtio.h>
#include <linux/fs.h>
+#include <linux/fd.h>
#if defined(CONFIG_FIEMAP)
#include <linux/fiemap.h>
#endif
#include <linux/blkpg.h>
#include <netpacket/packet.h>
#include <linux/netlink.h>
+#include <linux/if_alg.h>
#include "linux_loop.h"
#include "uname.h"
#include "qemu.h"
#include "qemu/guest-random.h"
+#include "user/syscall-trace.h"
#include "qapi/error.h"
#include "fd-trans.h"
#define __NR_sys_inotify_init __NR_inotify_init
#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
+#define __NR_sys_statx __NR_statx
#if defined(__alpha__) || defined(__x86_64__) || defined(__s390x__)
#define __NR__llseek __NR_lseek
unsigned long, idx1, unsigned long, idx2)
#endif
+/*
+ * It is assumed that struct statx is architecture independent.
+ */
+#if defined(TARGET_NR_statx) && defined(__NR_statx)
+_syscall5(int, sys_statx, int, dirfd, const char *, pathname, int, flags,
+ unsigned int, mask, struct target_statx *, statxbuf)
+#endif
+
static bitmask_transtbl fcntl_flags_tbl[] = {
{ TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
{ TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
safe_syscall4(int, clock_nanosleep, const clockid_t, clock, int, flags,
const struct timespec *, req, struct timespec *, rem)
#endif
-#if !defined(__NR_msgsnd) || !defined(__NR_msgrcv) || !defined(__NR_semtimedop)
-/* This host kernel architecture uses a single ipc syscall; fake up
- * wrappers for the sub-operations to hide this implementation detail.
- * Annoyingly we can't include linux/ipc.h to get the constant definitions
- * for the call parameter because some structs in there conflict with the
- * sys/ipc.h ones. So we just define them here, and rely on them being
- * the same for all host architectures.
- */
-#define Q_SEMTIMEDOP 4
-#define Q_MSGSND 11
-#define Q_MSGRCV 12
-#define Q_IPCCALL(VERSION, OP) ((VERSION) << 16 | (OP))
-
+#ifdef __NR_ipc
safe_syscall6(int, ipc, int, call, long, first, long, second, long, third,
void *, ptr, long, fifth)
#endif
#ifdef __NR_msgsnd
safe_syscall4(int, msgsnd, int, msgid, const void *, msgp, size_t, sz,
int, flags)
-#else
-static int safe_msgsnd(int msgid, const void *msgp, size_t sz, int flags)
-{
- return safe_ipc(Q_IPCCALL(0, Q_MSGSND), msgid, sz, flags, (void *)msgp, 0);
-}
#endif
#ifdef __NR_msgrcv
safe_syscall5(int, msgrcv, int, msgid, void *, msgp, size_t, sz,
long, msgtype, int, flags)
-#else
-static int safe_msgrcv(int msgid, void *msgp, size_t sz, long type, int flags)
-{
- return safe_ipc(Q_IPCCALL(1, Q_MSGRCV), msgid, sz, flags, msgp, type);
-}
#endif
#ifdef __NR_semtimedop
safe_syscall4(int, semtimedop, int, semid, struct sembuf *, tsops,
unsigned, nsops, const struct timespec *, timeout)
-#else
-static int safe_semtimedop(int semid, struct sembuf *tsops, unsigned nsops,
- const struct timespec *timeout)
-{
- return safe_ipc(Q_IPCCALL(0, Q_SEMTIMEDOP), semid, nsops, 0, tsops,
- (long)timeout);
-}
#endif
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
{
struct target_timeval *target_tv;
- if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
+ if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) {
return -TARGET_EFAULT;
+ }
__get_user(tv->tv_sec, &target_tv->tv_sec);
__get_user(tv->tv_usec, &target_tv->tv_usec);
{
struct target_timeval *target_tv;
- if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
+ if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
return -TARGET_EFAULT;
+ }
__put_user(tv->tv_sec, &target_tv->tv_sec);
__put_user(tv->tv_usec, &target_tv->tv_usec);
return 0;
}
+static inline abi_long copy_to_user_timeval64(abi_ulong target_tv_addr,
+ const struct timeval *tv)
+{
+ struct target__kernel_sock_timeval *target_tv;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+
+ __put_user(tv->tv_sec, &target_tv->tv_sec);
+ __put_user(tv->tv_usec, &target_tv->tv_usec);
+
+ unlock_user_struct(target_tv, target_tv_addr, 1);
+
+ return 0;
+}
+
+static inline abi_long target_to_host_timespec(struct timespec *host_ts,
+ abi_ulong target_addr)
+{
+ struct target_timespec *target_ts;
+
+ if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) {
+ return -TARGET_EFAULT;
+ }
+ __get_user(host_ts->tv_sec, &target_ts->tv_sec);
+ __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
+ unlock_user_struct(target_ts, target_addr, 0);
+ return 0;
+}
+
+static inline abi_long host_to_target_timespec(abi_ulong target_addr,
+ struct timespec *host_ts)
+{
+ struct target_timespec *target_ts;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+ __put_user(host_ts->tv_sec, &target_ts->tv_sec);
+ __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
+ unlock_user_struct(target_ts, target_addr, 1);
+ return 0;
+}
+
+static inline abi_long host_to_target_timespec64(abi_ulong target_addr,
+ struct timespec *host_ts)
+{
+ struct target__kernel_timespec *target_ts;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+ __put_user(host_ts->tv_sec, &target_ts->tv_sec);
+ __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
+ unlock_user_struct(target_ts, target_addr, 1);
+ return 0;
+}
+
static inline abi_long copy_from_user_timezone(struct timezone *tz,
abi_ulong target_tz_addr)
{
sizeof(target_saddr->sa_family)) {
target_saddr->sa_family = tswap16(addr->sa_family);
}
- if (addr->sa_family == AF_NETLINK && len >= sizeof(struct sockaddr_nl)) {
- struct sockaddr_nl *target_nl = (struct sockaddr_nl *)target_saddr;
+ if (addr->sa_family == AF_NETLINK &&
+ len >= sizeof(struct target_sockaddr_nl)) {
+ struct target_sockaddr_nl *target_nl =
+ (struct target_sockaddr_nl *)target_saddr;
target_nl->nl_pid = tswap32(target_nl->nl_pid);
target_nl->nl_groups = tswap32(target_nl->nl_groups);
} else if (addr->sa_family == AF_PACKET) {
&pki, sizeof(pki)));
break;
}
+ case IPV6_ADD_MEMBERSHIP:
+ case IPV6_DROP_MEMBERSHIP:
+ {
+ struct ipv6_mreq ipv6mreq;
+
+ if (optlen < sizeof(ipv6mreq)) {
+ return -TARGET_EINVAL;
+ }
+
+ if (copy_from_user(&ipv6mreq, optval_addr, sizeof(ipv6mreq))) {
+ return -TARGET_EFAULT;
+ }
+
+ ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface);
+
+ ret = get_errno(setsockopt(sockfd, level, optname,
+ &ipv6mreq, sizeof(ipv6mreq)));
+ break;
+ }
default:
goto unimplemented;
}
goto unimplemented;
}
break;
+#if defined(SOL_ALG) && defined(ALG_SET_KEY) && defined(ALG_SET_AEAD_AUTHSIZE)
+ case SOL_ALG:
+ switch (optname) {
+ case ALG_SET_KEY:
+ {
+ char *alg_key = g_malloc(optlen);
+
+ if (!alg_key) {
+ return -TARGET_ENOMEM;
+ }
+ if (copy_from_user(alg_key, optval_addr, optlen)) {
+ g_free(alg_key);
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, level, optname,
+ alg_key, optlen));
+ g_free(alg_key);
+ break;
+ }
+ case ALG_SET_AEAD_AUTHSIZE:
+ {
+ ret = get_errno(setsockopt(sockfd, level, optname,
+ NULL, optlen));
+ break;
+ }
+ default:
+ goto unimplemented;
+ }
+ break;
+#endif
case TARGET_SOL_SOCKET:
switch (optname) {
case TARGET_SO_RCVTIMEO:
return -TARGET_EFAULT;
ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
break;
+#ifdef SOL_NETLINK
+ case SOL_NETLINK:
+ switch (optname) {
+ case NETLINK_PKTINFO:
+ case NETLINK_ADD_MEMBERSHIP:
+ case NETLINK_DROP_MEMBERSHIP:
+ case NETLINK_BROADCAST_ERROR:
+ case NETLINK_NO_ENOBUFS:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ case NETLINK_LISTEN_ALL_NSID:
+ case NETLINK_CAP_ACK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ case NETLINK_EXT_ACK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ case NETLINK_GET_STRICT_CHK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
+ break;
+ default:
+ goto unimplemented;
+ }
+ val = 0;
+ if (optlen < sizeof(uint32_t)) {
+ return -TARGET_EINVAL;
+ }
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, SOL_NETLINK, optname, &val,
+ sizeof(val)));
+ break;
+#endif /* SOL_NETLINK */
default:
unimplemented:
gemu_log("Unsupported setsockopt level=%d optname=%d\n", level, optname);
break;
}
break;
+#ifdef SOL_NETLINK
+ case SOL_NETLINK:
+ switch (optname) {
+ case NETLINK_PKTINFO:
+ case NETLINK_BROADCAST_ERROR:
+ case NETLINK_NO_ENOBUFS:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ case NETLINK_LISTEN_ALL_NSID:
+ case NETLINK_CAP_ACK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ case NETLINK_EXT_ACK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ case NETLINK_GET_STRICT_CHK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
+ if (get_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ if (len != sizeof(val)) {
+ return -TARGET_EINVAL;
+ }
+ lv = len;
+ ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+ if (ret < 0) {
+ return ret;
+ }
+ if (put_user_u32(lv, optlen)
+ || put_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ break;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ case NETLINK_LIST_MEMBERSHIPS:
+ {
+ uint32_t *results;
+ int i;
+ if (get_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ if (len < 0) {
+ return -TARGET_EINVAL;
+ }
+ results = lock_user(VERIFY_WRITE, optval_addr, len, 1);
+ if (!results) {
+ return -TARGET_EFAULT;
+ }
+ lv = len;
+ ret = get_errno(getsockopt(sockfd, level, optname, results, &lv));
+ if (ret < 0) {
+ unlock_user(results, optval_addr, 0);
+ return ret;
+ }
+ /* swap host endianess to target endianess. */
+ for (i = 0; i < (len / sizeof(uint32_t)); i++) {
+ results[i] = tswap32(results[i]);
+ }
+ if (put_user_u32(lv, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ unlock_user(results, optval_addr, 0);
+ break;
+ }
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
+ default:
+ goto unimplemented;
+ }
+ break;
+#endif /* SOL_NETLINK */
default:
unimplemented:
gemu_log("getsockopt level=%d optname=%d not yet supported\n",
static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
{
struct sembuf sops[nsops];
+ abi_long ret;
if (target_to_host_sembuf(sops, ptr, nsops))
return -TARGET_EFAULT;
- return get_errno(safe_semtimedop(semid, sops, nsops, NULL));
+ ret = -TARGET_ENOSYS;
+#ifdef __NR_semtimedop
+ ret = get_errno(safe_semtimedop(semid, sops, nsops, NULL));
+#endif
+#ifdef __NR_ipc
+ if (ret == -TARGET_ENOSYS) {
+ ret = get_errno(safe_ipc(IPCOP_semtimedop, semid, nsops, 0, sops, 0));
+ }
+#endif
+ return ret;
}
struct target_msqid_ds
}
host_mb->mtype = (abi_long) tswapal(target_mb->mtype);
memcpy(host_mb->mtext, target_mb->mtext, msgsz);
+ ret = -TARGET_ENOSYS;
+#ifdef __NR_msgsnd
ret = get_errno(safe_msgsnd(msqid, host_mb, msgsz, msgflg));
+#endif
+#ifdef __NR_ipc
+ if (ret == -TARGET_ENOSYS) {
+ ret = get_errno(safe_ipc(IPCOP_msgsnd, msqid, msgsz, msgflg,
+ host_mb, 0));
+ }
+#endif
g_free(host_mb);
unlock_user_struct(target_mb, msgp, 0);
ret = -TARGET_ENOMEM;
goto end;
}
+ ret = -TARGET_ENOSYS;
+#ifdef __NR_msgrcv
ret = get_errno(safe_msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
+#endif
+#ifdef __NR_ipc
+ if (ret == -TARGET_ENOSYS) {
+ ret = get_errno(safe_ipc(IPCOP_CALL(1, IPCOP_msgrcv), msqid, msgsz,
+ msgflg, host_mb, msgtyp));
+ }
+#endif
if (ret > 0) {
abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
}
+static abi_long do_ioctl_SIOCGSTAMP(const IOCTLEntry *ie, uint8_t *buf_temp,
+ int fd, int cmd, abi_long arg)
+{
+ struct timeval tv;
+ abi_long ret;
+
+ ret = get_errno(safe_ioctl(fd, SIOCGSTAMP, &tv));
+ if (is_error(ret)) {
+ return ret;
+ }
+
+ if (cmd == (int)TARGET_SIOCGSTAMP_OLD) {
+ if (copy_to_user_timeval(arg, &tv)) {
+ return -TARGET_EFAULT;
+ }
+ } else {
+ if (copy_to_user_timeval64(arg, &tv)) {
+ return -TARGET_EFAULT;
+ }
+ }
+
+ return ret;
+}
+
+static abi_long do_ioctl_SIOCGSTAMPNS(const IOCTLEntry *ie, uint8_t *buf_temp,
+ int fd, int cmd, abi_long arg)
+{
+ struct timespec ts;
+ abi_long ret;
+
+ ret = get_errno(safe_ioctl(fd, SIOCGSTAMPNS, &ts));
+ if (is_error(ret)) {
+ return ret;
+ }
+
+ if (cmd == (int)TARGET_SIOCGSTAMPNS_OLD) {
+ if (host_to_target_timespec(arg, &ts)) {
+ return -TARGET_EFAULT;
+ }
+ } else{
+ if (host_to_target_timespec64(arg, &ts)) {
+ return -TARGET_EFAULT;
+ }
+ }
+
+ return ret;
+}
+
#ifdef TIOCGPTPEER
static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
int fd, int cmd, abi_long arg)
/* we create a new CPU instance. */
new_env = cpu_copy(env);
/* Init regs that differ from the parent. */
- cpu_clone_regs(new_env, newsp);
+ cpu_clone_regs_child(new_env, newsp, flags);
+ cpu_clone_regs_parent(env, flags);
new_cpu = env_cpu(new_env);
new_cpu->opaque = ts;
ts->bprm = parent_ts->bprm;
ret = fork();
if (ret == 0) {
/* Child Process. */
- cpu_clone_regs(env, newsp);
+ cpu_clone_regs_child(env, newsp, flags);
fork_end(1);
/* There is a race condition here. The parent process could
theoretically read the TID in the child process before the child
if (flags & CLONE_CHILD_CLEARTID)
ts->child_tidptr = child_tidptr;
} else {
+ cpu_clone_regs_parent(env, flags);
fork_end(0);
}
}
}
#endif
-static inline abi_long target_to_host_timespec(struct timespec *host_ts,
- abi_ulong target_addr)
-{
- struct target_timespec *target_ts;
-
- if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
- return -TARGET_EFAULT;
- __get_user(host_ts->tv_sec, &target_ts->tv_sec);
- __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
- unlock_user_struct(target_ts, target_addr, 0);
- return 0;
-}
-
-static inline abi_long host_to_target_timespec(abi_ulong target_addr,
- struct timespec *host_ts)
-{
- struct target_timespec *target_ts;
-
- if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
- return -TARGET_EFAULT;
- __put_user(host_ts->tv_sec, &target_ts->tv_sec);
- __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
- unlock_user_struct(target_ts, target_addr, 1);
- return 0;
-}
-
static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec,
abi_ulong target_addr)
{
}
#endif
+#if defined(TARGET_NR_statx) && defined(__NR_statx)
+static inline abi_long host_to_target_statx(struct target_statx *host_stx,
+ abi_ulong target_addr)
+{
+ struct target_statx *target_stx;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_stx, target_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+ memset(target_stx, 0, sizeof(*target_stx));
+
+ __put_user(host_stx->stx_mask, &target_stx->stx_mask);
+ __put_user(host_stx->stx_blksize, &target_stx->stx_blksize);
+ __put_user(host_stx->stx_attributes, &target_stx->stx_attributes);
+ __put_user(host_stx->stx_nlink, &target_stx->stx_nlink);
+ __put_user(host_stx->stx_uid, &target_stx->stx_uid);
+ __put_user(host_stx->stx_gid, &target_stx->stx_gid);
+ __put_user(host_stx->stx_mode, &target_stx->stx_mode);
+ __put_user(host_stx->stx_ino, &target_stx->stx_ino);
+ __put_user(host_stx->stx_size, &target_stx->stx_size);
+ __put_user(host_stx->stx_blocks, &target_stx->stx_blocks);
+ __put_user(host_stx->stx_attributes_mask, &target_stx->stx_attributes_mask);
+ __put_user(host_stx->stx_atime.tv_sec, &target_stx->stx_atime.tv_sec);
+ __put_user(host_stx->stx_atime.tv_nsec, &target_stx->stx_atime.tv_nsec);
+ __put_user(host_stx->stx_btime.tv_sec, &target_stx->stx_btime.tv_sec);
+ __put_user(host_stx->stx_btime.tv_nsec, &target_stx->stx_btime.tv_nsec);
+ __put_user(host_stx->stx_ctime.tv_sec, &target_stx->stx_ctime.tv_sec);
+ __put_user(host_stx->stx_ctime.tv_nsec, &target_stx->stx_ctime.tv_nsec);
+ __put_user(host_stx->stx_mtime.tv_sec, &target_stx->stx_mtime.tv_sec);
+ __put_user(host_stx->stx_mtime.tv_nsec, &target_stx->stx_mtime.tv_nsec);
+ __put_user(host_stx->stx_rdev_major, &target_stx->stx_rdev_major);
+ __put_user(host_stx->stx_rdev_minor, &target_stx->stx_rdev_minor);
+ __put_user(host_stx->stx_dev_major, &target_stx->stx_dev_major);
+ __put_user(host_stx->stx_dev_minor, &target_stx->stx_dev_minor);
+
+ unlock_user_struct(target_stx, target_addr, 1);
+
+ return 0;
+}
+#endif
+
+
/* ??? Using host futex calls even when target atomic operations
are not really atomic probably breaks things. However implementing
futexes locally would make futexes shared between multiple processes
abi_long ret;
#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) \
|| defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64) \
- || defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64)
+ || defined(TARGET_NR_fstat) || defined(TARGET_NR_fstat64) \
+ || defined(TARGET_NR_statx)
struct stat st;
#endif
#if defined(TARGET_NR_statfs) || defined(TARGET_NR_statfs64) \
#ifdef TARGET_NR_stime /* not on alpha */
case TARGET_NR_stime:
{
- time_t host_time;
- if (get_user_sal(host_time, arg1))
+ struct timespec ts;
+ ts.tv_nsec = 0;
+ if (get_user_sal(ts.tv_sec, arg1)) {
return -TARGET_EFAULT;
- return get_errno(stime(&host_time));
+ }
+ return get_errno(clock_settime(CLOCK_REALTIME, &ts));
}
#endif
#ifdef TARGET_NR_alarm /* not on alpha */
aarch64_sve_narrow_vq(env, vq);
}
env->vfp.zcr_el[1] = vq - 1;
+ arm_rebuild_hflags(env);
ret = vq * 16;
}
return ret;
ret = host_to_target_stat64(cpu_env, arg3, &st);
return ret;
#endif
+#if defined(TARGET_NR_statx)
+ case TARGET_NR_statx:
+ {
+ struct target_statx *target_stx;
+ int dirfd = arg1;
+ int flags = arg3;
+
+ p = lock_user_string(arg2);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+#if defined(__NR_statx)
+ {
+ /*
+ * It is assumed that struct statx is architecture independent.
+ */
+ struct target_statx host_stx;
+ int mask = arg4;
+
+ ret = get_errno(sys_statx(dirfd, p, flags, mask, &host_stx));
+ if (!is_error(ret)) {
+ if (host_to_target_statx(&host_stx, arg5) != 0) {
+ unlock_user(p, arg2, 0);
+ return -TARGET_EFAULT;
+ }
+ }
+
+ if (ret != -TARGET_ENOSYS) {
+ unlock_user(p, arg2, 0);
+ return ret;
+ }
+ }
+#endif
+ ret = get_errno(fstatat(dirfd, path(p), &st, flags));
+ unlock_user(p, arg2, 0);
+
+ if (!is_error(ret)) {
+ if (!lock_user_struct(VERIFY_WRITE, target_stx, arg5, 0)) {
+ return -TARGET_EFAULT;
+ }
+ memset(target_stx, 0, sizeof(*target_stx));
+ __put_user(major(st.st_dev), &target_stx->stx_dev_major);
+ __put_user(minor(st.st_dev), &target_stx->stx_dev_minor);
+ __put_user(st.st_ino, &target_stx->stx_ino);
+ __put_user(st.st_mode, &target_stx->stx_mode);
+ __put_user(st.st_uid, &target_stx->stx_uid);
+ __put_user(st.st_gid, &target_stx->stx_gid);
+ __put_user(st.st_nlink, &target_stx->stx_nlink);
+ __put_user(major(st.st_rdev), &target_stx->stx_rdev_major);
+ __put_user(minor(st.st_rdev), &target_stx->stx_rdev_minor);
+ __put_user(st.st_size, &target_stx->stx_size);
+ __put_user(st.st_blksize, &target_stx->stx_blksize);
+ __put_user(st.st_blocks, &target_stx->stx_blocks);
+ __put_user(st.st_atime, &target_stx->stx_atime.tv_sec);
+ __put_user(st.st_mtime, &target_stx->stx_mtime.tv_sec);
+ __put_user(st.st_ctime, &target_stx->stx_ctime.tv_sec);
+ unlock_user_struct(target_stx, arg5, 1);
+ }
+ }
+ return ret;
+#endif
#ifdef TARGET_NR_lchown
case TARGET_NR_lchown:
if (!(p = lock_user_string(arg1)))
timer_t htimer = g_posix_timers[timerid];
ret = get_errno(timer_getoverrun(htimer));
}
- fd_trans_unregister(ret);
return ret;
}
#endif
/* PowerPC specific. */
return do_swapcontext(cpu_env, arg1, arg2, arg3);
#endif
+#ifdef TARGET_NR_memfd_create
+ case TARGET_NR_memfd_create:
+ p = lock_user_string(arg1);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(memfd_create(p, arg2));
+ fd_trans_unregister(ret);
+ unlock_user(p, arg1, 0);
+ return ret;
+#endif
default:
qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
}
#endif
- trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4,
- arg5, arg6, arg7, arg8);
+ record_syscall_start(cpu, num, arg1,
+ arg2, arg3, arg4, arg5, arg6, arg7, arg8);
if (unlikely(do_strace)) {
print_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
arg5, arg6, arg7, arg8);
}
- trace_guest_user_syscall_ret(cpu, num, ret);
+ record_syscall_return(cpu, num, ret);
return ret;
}