aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-03-10 16:22:39 +0000
committerPeter Maydell <peter.maydell@linaro.org>2014-03-10 16:22:39 +0000
commit3f1506704eca5f0f26dd7b5c56f4a8ca6d21f745 (patch)
tree9ef2ff882e53ec6062d218b1ff52a46e713b68d1 /linux-user
parent0c126db27ceaca994548214656a457c9b011dc17 (diff)
parentcbc14e6f286169949105c10ec60c924e086521ad (diff)
downloadqemu-3f1506704eca5f0f26dd7b5c56f4a8ca6d21f745.zip
qemu-3f1506704eca5f0f26dd7b5c56f4a8ca6d21f745.tar.gz
qemu-3f1506704eca5f0f26dd7b5c56f4a8ca6d21f745.tar.bz2
Merge remote-tracking branch 'remotes/riku/linux-user-for-upstream' into staging
* remotes/riku/linux-user-for-upstream: linux-user: set minimum kernel version to 2.6.32 linux-user: correct handling of break exception for MIPS linux-user: translate signal number on return from sigtimedwait linux-user: Implement sendmmsg syscall linux-user: Fix getresuid, getresgid if !USE_UID16 linux-user: Don't use UID16 on AArch64 linux-user: AArch64: Implement SA_RESTORER for signal handlers linux-user/signal.c: Fix AArch64 big-endian FP register restore Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/alpha/syscall.h1
-rw-r--r--linux-user/arm/syscall.h1
-rw-r--r--linux-user/cris/syscall.h2
-rw-r--r--linux-user/i386/syscall.h1
-rw-r--r--linux-user/m68k/syscall.h2
-rw-r--r--linux-user/main.c4
-rw-r--r--linux-user/microblaze/syscall.h2
-rw-r--r--linux-user/mips/syscall.h1
-rw-r--r--linux-user/mips64/syscall.h1
-rw-r--r--linux-user/openrisc/syscall.h1
-rw-r--r--linux-user/ppc/syscall.h1
-rw-r--r--linux-user/s390x/syscall.h1
-rw-r--r--linux-user/sh4/syscall.h1
-rw-r--r--linux-user/signal.c26
-rw-r--r--linux-user/sparc/syscall.h1
-rw-r--r--linux-user/sparc64/syscall.h1
-rw-r--r--linux-user/syscall.c120
-rw-r--r--linux-user/syscall_defs.h7
-rw-r--r--linux-user/unicore32/syscall.h1
-rw-r--r--linux-user/x86_64/syscall.h1
20 files changed, 143 insertions, 33 deletions
diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h
index 15a0100..ed13d9a 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 73f2931..ce2c2a8 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 832ee64..f5783c0 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 12b8c3b..9bfc1ad 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 2618793..889eaf7 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 be9491b..dee1084 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 d550989..5b5f6b4 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 9d437d9..5bc5696 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 1710f76..a7f5a58 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 bdbb577..c3b36da 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 ba36acb..6514c63 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 e5ce30b..aaad512 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 014bf58..ccd2216 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 04638e2..c8a1da0 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 4cd64bf..9549ea0 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 e60bf31..82b1680 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 1407b7a..e2c10cc 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 3c8869e..732c9e3 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 010cdd8..f7e5525 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 81314cf..e03b5a0 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