Commit 4f9c5be9 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/riku/linux-user-for-upstream' into staging



* remotes/riku/linux-user-for-upstream:
  linux-user: support the SIOCGIFINDEX ioctl
  linux-user: support the KDSIGACCEPT ioctl
  linux-user: allow NULL tv argument for settimeofday
  linux-user: respect timezone for settimeofday
  linux-user: fix struct target_epoll_event layout for MIPS
  linux-user: support strace of epoll_create1
  linux-user: allow NULL arguments to mount
  linux-user: support SO_PASSSEC setsockopt option
  linux-user: support SO_{SND, RCV}BUFFORCE setsockopt options
  linux-user: support SO_ACCEPTCONN getsockopt option
  linux-user: translate the result of getsockopt SO_TYPE
  linux-user: added fake open() for /proc/self/cmdline
  Add support for MAP_NORESERVE mmap flag.

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 4daebe01 f63eb01a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@
     IOCTL(KDSKBLED, 0, TYPE_INT)
     IOCTL(KDGETLED, 0, TYPE_INT)
     IOCTL(KDSETLED, 0, TYPE_INT)
     IOCTL_SPECIAL(KDSIGACCEPT, 0, do_ioctl_kdsigaccept, TYPE_INT)

     IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT))
     IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT))
@@ -117,6 +118,7 @@
  IOCTL(SIOCSIFMEM, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq)))
  IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
  IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
  IOCTL(SIOCGIFINDEX, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
  IOCTL(SIOCSIFLINK, 0, TYPE_NULL)
  IOCTL_SPECIAL(SIOCGIFCONF, IOC_W | IOC_R, do_ioctl_ifconf,
                MK_PTR(MK_STRUCT(STRUCT_ifconf)))
+5 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@
    #define TARGET_SO_PEERSEC              30
    #define TARGET_SO_SNDBUFFORCE          31
    #define TARGET_SO_RCVBUFFORCE          33
    #define TARGET_SO_PASSSEC              34

    /** sock_type - Socket types
     *
@@ -242,6 +243,10 @@

    #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
    #define TARGET_SOCK_TYPE_MASK    0xf  /* Covers up to TARGET_SOCK_MAX-1. */

    #define TARGET_SO_PASSSEC        31
#else
    #define TARGET_SO_PASSSEC        34
#endif

    /* For setsockopt(2) */
+3 −0
Original line number Diff line number Diff line
@@ -114,6 +114,9 @@
#ifdef TARGET_NR_epoll_create
{ TARGET_NR_epoll_create, "epoll_create" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_epoll_create1
{ TARGET_NR_epoll_create1, "epoll_create1" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_epoll_ctl
{ TARGET_NR_epoll_ctl, "epoll_ctl" , NULL, NULL, NULL },
#endif
+189 −26
Original line number Diff line number Diff line
@@ -592,6 +592,37 @@ char *target_strerror(int err)
    return strerror(target_to_host_errno(err));
}

static inline int host_to_target_sock_type(int host_type)
{
    int target_type;

    switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
    case SOCK_DGRAM:
        target_type = TARGET_SOCK_DGRAM;
        break;
    case SOCK_STREAM:
        target_type = TARGET_SOCK_STREAM;
        break;
    default:
        target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
        break;
    }

#if defined(SOCK_CLOEXEC)
    if (host_type & SOCK_CLOEXEC) {
        target_type |= TARGET_SOCK_CLOEXEC;
    }
#endif

#if defined(SOCK_NONBLOCK)
    if (host_type & SOCK_NONBLOCK) {
        target_type |= TARGET_SOCK_NONBLOCK;
    }
#endif

    return target_type;
}

static abi_ulong target_brk;
static abi_ulong target_original_brk;
static abi_ulong brk_page;
@@ -904,6 +935,23 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
    return 0;
}

static inline abi_long copy_from_user_timezone(struct timezone *tz,
                                               abi_ulong target_tz_addr)
{
    struct target_timezone *target_tz;

    if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
        return -TARGET_EFAULT;
    }

    __get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
    __get_user(tz->tz_dsttime, &target_tz->tz_dsttime);

    unlock_user_struct(target_tz, target_tz_addr, 0);

    return 0;
}

#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
#include <mqueue.h>

@@ -1471,9 +1519,15 @@ set_timeout:
        case TARGET_SO_SNDBUF:
		optname = SO_SNDBUF;
		break;
        case TARGET_SO_SNDBUFFORCE:
                optname = SO_SNDBUFFORCE;
                break;
        case TARGET_SO_RCVBUF:
		optname = SO_RCVBUF;
		break;
        case TARGET_SO_RCVBUFFORCE:
                optname = SO_RCVBUFFORCE;
                break;
        case TARGET_SO_KEEPALIVE:
		optname = SO_KEEPALIVE;
		break;
@@ -1494,6 +1548,9 @@ set_timeout:
        case TARGET_SO_PASSCRED:
		optname = SO_PASSCRED;
		break;
        case TARGET_SO_PASSSEC:
                optname = SO_PASSSEC;
                break;
        case TARGET_SO_TIMESTAMP:
		optname = SO_TIMESTAMP;
		break;
@@ -1621,6 +1678,9 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
        case TARGET_SO_RCVLOWAT:
            optname = SO_RCVLOWAT;
            goto int_case;
        case TARGET_SO_ACCEPTCONN:
            optname = SO_ACCEPTCONN;
            goto int_case;
        default:
            goto int_case;
        }
@@ -1636,6 +1696,9 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
        ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
        if (ret < 0)
            return ret;
        if (optname == SO_TYPE) {
            val = host_to_target_sock_type(val);
        }
        if (len > lv)
            len = lv;
        if (len == 4) {
@@ -3626,6 +3689,13 @@ static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
    return ret;
}

static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
                                     int fd, abi_long cmd, abi_long arg)
{
    int sig = target_to_host_signal(arg);
    return get_errno(ioctl(fd, ie->host_cmd, sig));
}

static IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \
    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
@@ -3908,6 +3978,8 @@ static bitmask_transtbl mmap_flags_tbl[] = {
	{ TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
	{ TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
	{ TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
        { TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
          MAP_NORESERVE },
	{ 0, 0, 0, 0 }
};

@@ -4947,6 +5019,51 @@ int host_to_target_waitstatus(int status)
    return status;
}

static int open_self_cmdline(void *cpu_env, int fd)
{
    int fd_orig = -1;
    bool word_skipped = false;

    fd_orig = open("/proc/self/cmdline", O_RDONLY);
    if (fd_orig < 0) {
        return fd_orig;
    }

    while (true) {
        ssize_t nb_read;
        char buf[128];
        char *cp_buf = buf;

        nb_read = read(fd_orig, buf, sizeof(buf));
        if (nb_read < 0) {
            fd_orig = close(fd_orig);
            return -1;
        } else if (nb_read == 0) {
            break;
        }

        if (!word_skipped) {
            /* Skip the first string, which is the path to qemu-*-static
               instead of the actual command. */
            cp_buf = memchr(buf, 0, sizeof(buf));
            if (cp_buf) {
                /* Null byte found, skip one string */
                cp_buf++;
                nb_read -= cp_buf - buf;
                word_skipped = true;
            }
        }

        if (word_skipped) {
            if (write(fd, cp_buf, nb_read) != nb_read) {
                return -1;
            }
        }
    }

    return close(fd_orig);
}

static int open_self_maps(void *cpu_env, int fd)
{
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
@@ -5148,6 +5265,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
        { "maps", open_self_maps, is_proc_myself },
        { "stat", open_self_stat, is_proc_myself },
        { "auxv", open_self_auxv, is_proc_myself },
        { "cmdline", open_self_cmdline, is_proc_myself },
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
        { "/proc/net/route", open_net_route, is_proc },
#endif
@@ -5523,26 +5641,57 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
        {
            /* need to look at the data field */
            void *p2, *p3;

            if (arg1) {
                p = lock_user_string(arg1);
                if (!p) {
                    goto efault;
                }
            } else {
                p = NULL;
            }

            p2 = lock_user_string(arg2);
            if (!p2) {
                if (arg1) {
                    unlock_user(p, arg1, 0);
                }
                goto efault;
            }

            if (arg3) {
                p3 = lock_user_string(arg3);
                        if (!p || !p2 || !p3)
                            ret = -TARGET_EFAULT;
                        else {
                if (!p3) {
                    if (arg1) {
                        unlock_user(p, arg1, 0);
                    }
                    unlock_user(p2, arg2, 0);
                    goto efault;
                }
            } else {
                p3 = NULL;
            }

            /* FIXME - arg5 should be locked, but it isn't clear how to
             * do that since it's not guaranteed to be a NULL-terminated
             * string.
             */
                            if ( ! arg5 )
                                ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
                            else
                                ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
            if (!arg5) {
                ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
            } else {
                ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
            }
            ret = get_errno(ret);

            if (arg1) {
                unlock_user(p, arg1, 0);
            }
            unlock_user(p2, arg2, 0);
            if (arg3) {
                unlock_user(p3, arg3, 0);
			break;
            }
        }
        break;
#ifdef TARGET_NR_umount
    case TARGET_NR_umount:
        if (!(p = lock_user_string(arg1)))
@@ -6259,10 +6408,24 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
        break;
    case TARGET_NR_settimeofday:
        {
            struct timeval tv;
            if (copy_from_user_timeval(&tv, arg1))
            struct timeval tv, *ptv = NULL;
            struct timezone tz, *ptz = NULL;

            if (arg1) {
                if (copy_from_user_timeval(&tv, arg1)) {
                    goto efault;
                }
                ptv = &tv;
            }

            if (arg2) {
                if (copy_from_user_timezone(&tz, arg2)) {
                    goto efault;
            ret = get_errno(settimeofday(&tv, NULL));
                }
                ptz = &tz;
            }

            ret = get_errno(settimeofday(ptv, ptz));
        }
        break;
#if defined(TARGET_NR_select)
+8 −1
Original line number Diff line number Diff line
@@ -165,6 +165,11 @@ struct target_timespec {
    abi_long tv_nsec;
};

struct target_timezone {
    abi_int tz_minuteswest;
    abi_int tz_dsttime;
};

struct target_itimerval {
    struct target_timeval it_interval;
    struct target_timeval it_value;
@@ -826,6 +831,7 @@ struct target_pollfd {
#define TARGET_KDSKBLED        0x4B65	/* set led flags (not lights) */
#define TARGET_KDGETLED        0x4B31	/* return current led state */
#define TARGET_KDSETLED        0x4B32	/* set led state [lights, not flags] */
#define TARGET_KDSIGACCEPT     0x4B4E

#define TARGET_SIOCATMARK      0x8905

@@ -859,6 +865,7 @@ struct target_pollfd {
#define TARGET_SIOCSIFSLAVE    0x8930
#define TARGET_SIOCADDMULTI    0x8931          /* Multicast address lists      */
#define TARGET_SIOCDELMULTI    0x8932
#define TARGET_SIOCGIFINDEX    0x8933

/* Bridging control calls */
#define TARGET_SIOCGIFBR       0x8940          /* Bridging support             */
@@ -2528,7 +2535,7 @@ typedef union target_epoll_data {

struct target_epoll_event {
    uint32_t events;
#ifdef TARGET_ARM
#if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_MIPS64)
    uint32_t __pad;
#endif
    target_epoll_data_t data;