aboutsummaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c102
1 files changed, 75 insertions, 27 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d4497dec5d..11c9116c4a 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -671,18 +671,32 @@ static inline int next_free_host_timer(void)
/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
#ifdef TARGET_ARM
-static inline int regpairs_aligned(void *cpu_env) {
+static inline int regpairs_aligned(void *cpu_env, int num)
+{
return ((((CPUARMState *)cpu_env)->eabi) == 1) ;
}
#elif defined(TARGET_MIPS) && (TARGET_ABI_BITS == 32)
-static inline int regpairs_aligned(void *cpu_env) { return 1; }
+static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
/* SysV AVI for PPC32 expects 64bit parameters to be passed on odd/even pairs
* of registers which translates to the same as ARM/MIPS, because we start with
* r3 as arg1 */
-static inline int regpairs_aligned(void *cpu_env) { return 1; }
+static inline int regpairs_aligned(void *cpu_env, int num) { return 1; }
+#elif defined(TARGET_SH4)
+/* SH4 doesn't align register pairs, except for p{read,write}64 */
+static inline int regpairs_aligned(void *cpu_env, int num)
+{
+ switch (num) {
+ case TARGET_NR_pread64:
+ case TARGET_NR_pwrite64:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
#else
-static inline int regpairs_aligned(void *cpu_env) { return 0; }
+static inline int regpairs_aligned(void *cpu_env, int num) { return 0; }
#endif
#define ERRNO_TABLE_SIZE 1200
@@ -5872,17 +5886,26 @@ static const StructEntry struct_termios_def = {
};
static bitmask_transtbl mmap_flags_tbl[] = {
- { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
- { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
- { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
- { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
- { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
- { 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 }
+ { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
+ { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
+ { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
+ { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS,
+ MAP_ANONYMOUS, MAP_ANONYMOUS },
+ { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN,
+ MAP_GROWSDOWN, MAP_GROWSDOWN },
+ { 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 },
+ { TARGET_MAP_HUGETLB, TARGET_MAP_HUGETLB, MAP_HUGETLB, MAP_HUGETLB },
+ /* MAP_STACK had been ignored by the kernel for quite some time.
+ Recognize it for the target insofar as we do not want to pass
+ it through to the host. */
+ { TARGET_MAP_STACK, TARGET_MAP_STACK, 0, 0 },
+ { 0, 0, 0, 0 }
};
#if defined(TARGET_I386)
@@ -6235,7 +6258,7 @@ static void *clone_func(void *arg)
pthread_mutex_lock(&info->mutex);
pthread_cond_broadcast(&info->cond);
pthread_mutex_unlock(&info->mutex);
- /* Wait until the parent has finshed initializing the tls state. */
+ /* Wait until the parent has finished initializing the tls state. */
pthread_mutex_lock(&clone_lock);
pthread_mutex_unlock(&clone_lock);
cpu_loop(env);
@@ -6861,7 +6884,7 @@ static inline abi_long target_truncate64(void *cpu_env, const char *arg1,
abi_long arg3,
abi_long arg4)
{
- if (regpairs_aligned(cpu_env)) {
+ if (regpairs_aligned(cpu_env, TARGET_NR_truncate64)) {
arg2 = arg3;
arg3 = arg4;
}
@@ -6875,7 +6898,7 @@ static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1,
abi_long arg3,
abi_long arg4)
{
- if (regpairs_aligned(cpu_env)) {
+ if (regpairs_aligned(cpu_env, TARGET_NR_ftruncate64)) {
arg2 = arg3;
arg3 = arg4;
}
@@ -8556,8 +8579,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_rt_sigaction:
{
#if defined(TARGET_ALPHA)
- struct target_sigaction act, oact, *pact = 0;
+ /* For Alpha and SPARC this is a 5 argument syscall, with
+ * a 'restorer' parameter which must be copied into the
+ * sa_restorer field of the sigaction struct.
+ * For Alpha that 'restorer' is arg5; for SPARC it is arg4,
+ * and arg5 is the sigsetsize.
+ * Alpha also has a separate rt_sigaction struct that it uses
+ * here; SPARC uses the usual sigaction struct.
+ */
struct target_rt_sigaction *rt_act;
+ struct target_sigaction act, oact, *pact = 0;
if (arg4 != sizeof(target_sigset_t)) {
ret = -TARGET_EINVAL;
@@ -8583,18 +8614,29 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user_struct(rt_act, arg3, 1);
}
#else
+#ifdef TARGET_SPARC
+ target_ulong restorer = arg4;
+ target_ulong sigsetsize = arg5;
+#else
+ target_ulong sigsetsize = arg4;
+#endif
struct target_sigaction *act;
struct target_sigaction *oact;
- if (arg4 != sizeof(target_sigset_t)) {
+ if (sigsetsize != sizeof(target_sigset_t)) {
ret = -TARGET_EINVAL;
break;
}
if (arg2) {
- if (!lock_user_struct(VERIFY_READ, act, arg2, 1))
+ if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
goto efault;
- } else
+ }
+#ifdef TARGET_SPARC
+ act->sa_restorer = restorer;
+#endif
+ } else {
act = NULL;
+ }
if (arg3) {
if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
ret = -TARGET_EFAULT;
@@ -10482,6 +10524,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
}
#endif
+ case PR_GET_SECCOMP:
+ case PR_SET_SECCOMP:
+ /* Disable seccomp to prevent the target disabling syscalls we
+ * need. */
+ ret = -TARGET_EINVAL;
+ break;
default:
/* Most prctl options have no pointer arguments */
ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
@@ -10499,7 +10547,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_pread64
case TARGET_NR_pread64:
- if (regpairs_aligned(cpu_env)) {
+ if (regpairs_aligned(cpu_env, num)) {
arg4 = arg5;
arg5 = arg6;
}
@@ -10509,7 +10557,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg2, ret);
break;
case TARGET_NR_pwrite64:
- if (regpairs_aligned(cpu_env)) {
+ if (regpairs_aligned(cpu_env, num)) {
arg4 = arg5;
arg5 = arg6;
}
@@ -11279,7 +11327,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
arg6 = ret;
#else
/* 6 args: fd, offset (high, low), len (high, low), advice */
- if (regpairs_aligned(cpu_env)) {
+ if (regpairs_aligned(cpu_env, num)) {
/* offset is in (3,4), len in (5,6) and advice in 7 */
arg2 = arg3;
arg3 = arg4;
@@ -11298,7 +11346,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_fadvise64
case TARGET_NR_fadvise64:
/* 5 args: fd, offset (high, low), len, advice */
- if (regpairs_aligned(cpu_env)) {
+ if (regpairs_aligned(cpu_env, num)) {
/* offset is in (3,4), len in 5 and advice in 6 */
arg2 = arg3;
arg3 = arg4;
@@ -11411,7 +11459,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_readahead
case TARGET_NR_readahead:
#if TARGET_ABI_BITS == 32
- if (regpairs_aligned(cpu_env)) {
+ if (regpairs_aligned(cpu_env, num)) {
arg2 = arg3;
arg3 = arg4;
arg4 = arg5;