mirror of https://github.com/xemu-project/xemu.git
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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
4f9c5be919
|
@ -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)))
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -5520,29 +5638,60 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
|||
break;
|
||||
#endif
|
||||
case TARGET_NR_mount:
|
||||
{
|
||||
/* need to look at the data field */
|
||||
void *p2, *p3;
|
||||
p = lock_user_string(arg1);
|
||||
p2 = lock_user_string(arg2);
|
||||
p3 = lock_user_string(arg3);
|
||||
if (!p || !p2 || !p3)
|
||||
ret = -TARGET_EFAULT;
|
||||
else {
|
||||
/* 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)));
|
||||
}
|
||||
{
|
||||
/* 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 (!p3) {
|
||||
if (arg1) {
|
||||
unlock_user(p, arg1, 0);
|
||||
unlock_user(p2, arg2, 0);
|
||||
unlock_user(p3, arg3, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 = 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;
|
||||
#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))
|
||||
goto efault;
|
||||
ret = get_errno(settimeofday(&tv, NULL));
|
||||
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;
|
||||
}
|
||||
ptz = &tz;
|
||||
}
|
||||
|
||||
ret = get_errno(settimeofday(ptv, ptz));
|
||||
}
|
||||
break;
|
||||
#if defined(TARGET_NR_select)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue