diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h index 15a0100335..ed13d9a718 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/syscall.h @@ -39,6 +39,7 @@ struct target_pt_regs { }; #define UNAME_MACHINE "alpha" +#define UNAME_MINIMUM_RELEASE "2.6.32" #undef TARGET_EDEADLK #define TARGET_EDEADLK 11 diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index 73f29314f6..ce2c2a8ed0 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -40,5 +40,6 @@ struct target_pt_regs { #else #define UNAME_MACHINE "armv5tel" #endif +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h index 832ee64bd8..f5783c0557 100644 --- a/linux-user/cris/syscall.h +++ b/linux-user/cris/syscall.h @@ -1,8 +1,8 @@ #ifndef CRIS_SYSCALL_H #define CRIS_SYSCALL_H 1 - #define UNAME_MACHINE "cris" +#define UNAME_MINIMUM_RELEASE "2.6.32" /* pt_regs not only specifices the format in the user-struct during * ptrace but is also the frame format used in the kernel prologue/epilogues diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index 12b8c3b672..9bfc1ad8f7 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -144,5 +144,6 @@ struct target_vm86plus_struct { }; #define UNAME_MACHINE "i686" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/syscall.h index 26187930db..889eaf7323 100644 --- a/linux-user/m68k/syscall.h +++ b/linux-user/m68k/syscall.h @@ -15,7 +15,7 @@ struct target_pt_regs { uint16_t __fill; }; - #define UNAME_MACHINE "m68k" +#define UNAME_MINIMUM_RELEASE "2.6.32" void do_m68k_simcall(CPUM68KState *, int); diff --git a/linux-user/main.c b/linux-user/main.c index be9491bc7d..dee10841c3 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2400,6 +2400,10 @@ static int do_break(CPUMIPSState *env, target_siginfo_t *info, ret = 0; break; default: + info->si_signo = TARGET_SIGTRAP; + info->si_errno = 0; + queue_signal(env, info->si_signo, &*info); + ret = 0; break; } diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h index d550989d5e..5b5f6b447d 100644 --- a/linux-user/microblaze/syscall.h +++ b/linux-user/microblaze/syscall.h @@ -1,8 +1,8 @@ #ifndef MICROBLAZE_SYSCALLS_H #define MICROBLAZE_SYSCALLS_H 1 - #define UNAME_MACHINE "microblaze" +#define UNAME_MINIMUM_RELEASE "2.6.32" /* We use microblaze_reg_t to keep things similar to the kernel sources. */ typedef uint32_t microblaze_reg_t; diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 9d437d918b..5bc56962a4 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -225,5 +225,6 @@ struct target_pt_regs { #define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index 1710f766e2..a7f5a5802a 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -222,5 +222,6 @@ struct target_pt_regs { #define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips64" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/openrisc/syscall.h b/linux-user/openrisc/syscall.h index bdbb577fc3..c3b36da83c 100644 --- a/linux-user/openrisc/syscall.h +++ b/linux-user/openrisc/syscall.h @@ -22,3 +22,4 @@ struct target_pt_regs { }; #define UNAME_MACHINE "openrisc" +#define UNAME_MINIMUM_RELEASE "2.6.32" diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index ba36acbc33..6514c637a5 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -62,5 +62,6 @@ struct target_revectored_struct { #else #define UNAME_MACHINE "ppc" #endif +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index e5ce30b667..aaad512d4d 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -21,5 +21,6 @@ struct target_pt_regs { }; #define UNAME_MACHINE "s390x" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS2 diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h index 014bf58fc3..ccd2216e38 100644 --- a/linux-user/sh4/syscall.h +++ b/linux-user/sh4/syscall.h @@ -10,3 +10,4 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sh4" +#define UNAME_MINIMUM_RELEASE "2.6.32" diff --git a/linux-user/signal.c b/linux-user/signal.c index 04638e2ead..c8a1da0749 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1233,8 +1233,14 @@ static int target_restore_sigframe(CPUARMState *env, return 1; } - for (i = 0; i < 32 * 2; i++) { - __get_user(env->vfp.regs[i], &aux->fpsimd.vregs[i]); + for (i = 0; i < 32; i++) { +#ifdef TARGET_WORDS_BIGENDIAN + __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]); + __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]); +#else + __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]); + __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]); +#endif } __get_user(fpsr, &aux->fpsimd.fpsr); vfp_set_fpsr(env, fpsr); @@ -1267,7 +1273,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, CPUARMState *env) { struct target_rt_sigframe *frame; - abi_ulong frame_addr; + abi_ulong frame_addr, return_addr; frame_addr = get_sigframe(ka, env); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { @@ -1284,15 +1290,19 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); target_setup_sigframe(frame, env, set); - /* mov x8,#__NR_rt_sigreturn; svc #0 */ - __put_user(0xd2801168, &frame->tramp[0]); - __put_user(0xd4000001, &frame->tramp[1]); + if (ka->sa_flags & TARGET_SA_RESTORER) { + return_addr = ka->sa_restorer; + } else { + /* mov x8,#__NR_rt_sigreturn; svc #0 */ + __put_user(0xd2801168, &frame->tramp[0]); + __put_user(0xd4000001, &frame->tramp[1]); + return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp); + } env->xregs[0] = usig; env->xregs[31] = frame_addr; env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp); env->pc = ka->_sa_handler; - env->xregs[30] = env->xregs[31] + - offsetof(struct target_rt_sigframe, tramp); + env->xregs[30] = return_addr; if (info) { if (copy_siginfo_to_user(&frame->info, info)) { goto give_sigsegv; diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index 4cd64bf41d..9549ea0a2f 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -7,6 +7,7 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4" +#define UNAME_MINIMUM_RELEASE "2.6.32" /* SPARC kernels don't define this in their Kconfig, but they have the * same ABI as if they did, implemented by sparc-specific code which fishes diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h index e60bf311c0..82b1680cb6 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/syscall.h @@ -8,6 +8,7 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4u" +#define UNAME_MINIMUM_RELEASE "2.6.32" /* SPARC kernels don't define this in their Kconfig, but they have the * same ABI as if they did, implemented by sparc-specific code which fishes diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1407b7a546..e2c10cc0bd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1904,23 +1904,16 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr, return get_errno(connect(sockfd, addr, addrlen)); } -/* do_sendrecvmsg() Must return target values and target errnos. */ -static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, - int flags, int send) +/* do_sendrecvmsg_locked() Must return target values and target errnos. */ +static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, + int flags, int send) { abi_long ret, len; - struct target_msghdr *msgp; struct msghdr msg; int count; struct iovec *vec; abi_ulong target_vec; - /* FIXME */ - if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, - msgp, - target_msg, - send ? 1 : 0)) - return -TARGET_EFAULT; if (msgp->msg_name) { msg.msg_namelen = tswap32(msgp->msg_namelen); msg.msg_name = alloca(msg.msg_namelen); @@ -1975,10 +1968,75 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, out: unlock_iovec(vec, target_vec, count, !send); out2: + return ret; +} + +static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, + int flags, int send) +{ + abi_long ret; + struct target_msghdr *msgp; + + if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, + msgp, + target_msg, + send ? 1 : 0)) { + return -TARGET_EFAULT; + } + ret = do_sendrecvmsg_locked(fd, msgp, flags, send); unlock_user_struct(msgp, target_msg, send ? 0 : 1); return ret; } +#ifdef TARGET_NR_sendmmsg +/* We don't rely on the C library to have sendmmsg/recvmmsg support, + * so it might not have this *mmsg-specific flag either. + */ +#ifndef MSG_WAITFORONE +#define MSG_WAITFORONE 0x10000 +#endif + +static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec, + unsigned int vlen, unsigned int flags, + int send) +{ + struct target_mmsghdr *mmsgp; + abi_long ret = 0; + int i; + + if (vlen > UIO_MAXIOV) { + vlen = UIO_MAXIOV; + } + + mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1); + if (!mmsgp) { + return -TARGET_EFAULT; + } + + for (i = 0; i < vlen; i++) { + ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send); + if (is_error(ret)) { + break; + } + mmsgp[i].msg_len = tswap32(ret); + /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ + if (flags & MSG_WAITFORONE) { + flags |= MSG_DONTWAIT; + } + } + + unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i); + + /* Return number of datagrams sent if we sent any at all; + * otherwise return the error. + */ + if (i) { + return i; + } + return ret; +} +#endif + /* If we don't have a system accept4() then just call accept. * The callsites to do_accept4() will ensure that they don't * pass a non-zero flags argument in this config. @@ -4528,6 +4586,9 @@ static inline int tswapid(int id) { return tswap16(id); } + +#define put_user_id(x, gaddr) put_user_u16(x, gaddr) + #else /* !USE_UID16 */ static inline int high2lowuid(int uid) { @@ -4549,6 +4610,9 @@ static inline int tswapid(int id) { return tswap32(id); } + +#define put_user_id(x, gaddr) put_user_u32(x, gaddr) + #endif /* USE_UID16 */ void syscall_init(void) @@ -6121,11 +6185,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, puts = NULL; } ret = get_errno(sigtimedwait(&set, &uinfo, puts)); - if (!is_error(ret) && arg2) { - if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0))) - goto efault; - host_to_target_siginfo(p, &uinfo); - unlock_user(p, arg2, sizeof(target_siginfo_t)); + if (!is_error(ret)) { + if (arg2) { + p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), + 0); + if (!p) { + goto efault; + } + host_to_target_siginfo(p, &uinfo); + unlock_user(p, arg2, sizeof(target_siginfo_t)); + } + ret = host_to_target_signal(ret); } } break; @@ -6710,6 +6780,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_sendrecvmsg(arg1, arg2, arg3, 1); break; #endif +#ifdef TARGET_NR_sendmmsg + case TARGET_NR_sendmmsg: + ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1); + break; + case TARGET_NR_recvmmsg: + ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0); + break; +#endif #ifdef TARGET_NR_sendto case TARGET_NR_sendto: ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6); @@ -7805,9 +7883,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, uid_t ruid, euid, suid; ret = get_errno(getresuid(&ruid, &euid, &suid)); if (!is_error(ret)) { - if (put_user_u16(high2lowuid(ruid), arg1) - || put_user_u16(high2lowuid(euid), arg2) - || put_user_u16(high2lowuid(suid), arg3)) + if (put_user_id(high2lowuid(ruid), arg1) + || put_user_id(high2lowuid(euid), arg2) + || put_user_id(high2lowuid(suid), arg3)) goto efault; } } @@ -7826,9 +7904,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, gid_t rgid, egid, sgid; ret = get_errno(getresgid(&rgid, &egid, &sgid)); if (!is_error(ret)) { - if (put_user_u16(high2lowgid(rgid), arg1) - || put_user_u16(high2lowgid(egid), arg2) - || put_user_u16(high2lowgid(sgid), arg3)) + if (put_user_id(high2lowgid(rgid), arg1) + || put_user_id(high2lowgid(egid), arg2) + || put_user_id(high2lowgid(sgid), arg3)) goto efault; } } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 3c8869e073..732c9e3dbb 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -53,7 +53,8 @@ #define TARGET_IOC_NRBITS 8 #define TARGET_IOC_TYPEBITS 8 -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ +#if defined(TARGET_I386) || (defined(TARGET_ARM) && defined(TARGET_ABI32)) \ + || defined(TARGET_SPARC) \ || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) /* 16 bit uid wrappers emulation */ #define USE_UID16 @@ -239,6 +240,10 @@ __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cms return __cmsg; } +struct target_mmsghdr { + struct target_msghdr msg_hdr; /* Message header */ + unsigned int msg_len; /* Number of bytes transmitted */ +}; struct target_rusage { struct target_timeval ru_utime; /* user time used */ diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h index 010cdd896e..f7e55254cf 100644 --- a/linux-user/unicore32/syscall.h +++ b/linux-user/unicore32/syscall.h @@ -51,5 +51,6 @@ struct target_pt_regs { #define UC32_SYSCALL_NR_set_tls (UC32_SYSCALL_ARCH_BASE + 5) #define UNAME_MACHINE "UniCore-II" +#define UNAME_MINIMUM_RELEASE "2.6.32" #endif /* __UC32_SYSCALL_H__ */ diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h index 81314cfae6..e03b5a0cfc 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/syscall.h @@ -91,6 +91,7 @@ struct target_msqid64_ds { }; #define UNAME_MACHINE "x86_64" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_ARCH_SET_GS 0x1001 #define TARGET_ARCH_SET_FS 0x1002