Linux manages to have three separate orderings of the arguments to the clone() syscall on different architectures. In the kernel these are selected via CONFIG_CLONE_BACKWARDS and CONFIG_CLONE_BACKWARDS2. Clean up our implementation of this to use similar #define names rather than a TARGET_* ifdef ladder.
This includes behaviour changes fixing bugs on cris, x86-64, m68k, openrisc and unicore32. cris had explicit but wrong handling; the others were just incorrectly using QEMU's default, which happened to be the equivalent of CONFIG_CLONE_BACKWARDS. (unicore32 appears to be broken in the mainline kernel in that it tries to use arg3 for both parent_tidptr and newtls simultaneously -- we don't attempt to emulate this bug...) Signed-off-by: Peter Maydell <peter.mayd...@linaro.org> --- linux-user/arm/syscall.h | 2 ++ linux-user/cris/syscall.h | 2 ++ linux-user/i386/syscall.h | 2 ++ linux-user/microblaze/syscall.h | 2 ++ linux-user/mips/syscall.h | 2 ++ linux-user/mips64/syscall.h | 2 ++ linux-user/ppc/syscall.h | 2 ++ linux-user/s390x/syscall.h | 2 ++ linux-user/sparc/syscall.h | 7 +++++++ linux-user/sparc64/syscall.h | 7 +++++++ linux-user/syscall.c | 18 +++++++++++------- 11 files changed, 41 insertions(+), 7 deletions(-) diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index 003d424..73f2931 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -40,3 +40,5 @@ struct target_pt_regs { #else #define UNAME_MACHINE "armv5tel" #endif + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h index 50e50b4..832ee64 100644 --- a/linux-user/cris/syscall.h +++ b/linux-user/cris/syscall.h @@ -38,4 +38,6 @@ struct target_pt_regs { unsigned long eda; }; +#define TARGET_CLONE_BACKWARDS2 + #endif diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index 266e2c4..12b8c3b 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -144,3 +144,5 @@ struct target_vm86plus_struct { }; #define UNAME_MACHINE "i686" + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h index c3e5c55..d550989 100644 --- a/linux-user/microblaze/syscall.h +++ b/linux-user/microblaze/syscall.h @@ -48,4 +48,6 @@ struct target_pt_regs { uint32_t kernel_mode; }; +#define TARGET_CLONE_BACKWARDS + #endif diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 3deb862..9d437d9 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -225,3 +225,5 @@ struct target_pt_regs { #define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips" + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index cd707df..1710f76 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -222,3 +222,5 @@ struct target_pt_regs { #define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips64" + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index 481047b..ba36acb 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -62,3 +62,5 @@ struct target_revectored_struct { #else #define UNAME_MACHINE "ppc" #endif + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index e4603b7..ea8c304 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -21,3 +21,5 @@ struct target_pt_regs { }; #define UNAME_MACHINE "s390x" + +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index 5a9bb7e..4cd64bf 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -7,3 +7,10 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4" + +/* 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 + * directly in the u_regs() struct for half the parameters in sparc_do_fork() + * and copy_thread(). + */ +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h index 81a816d..e60bf31 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/syscall.h @@ -8,3 +8,10 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4u" + +/* 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 + * directly in the u_regs() struct for half the parameters in sparc_do_fork() + * and copy_thread(). + */ +#define TARGET_CLONE_BACKWARDS diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 642d0a3..b167d7f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6956,16 +6956,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(fsync(arg1)); break; case TARGET_NR_clone: -#if defined(TARGET_SH4) || defined(TARGET_ALPHA) - ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); -#elif defined(TARGET_CRIS) - ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5)); -#elif defined(TARGET_MICROBLAZE) + /* Linux manages to have three different orderings for its + * arguments to clone(); the BACKWARDS and BACKWARDS2 defines + * match the kernel's CONFIG_CLONE_* settings. + * Microblaze is further special in that it uses a sixth + * implicit argument to clone for the TLS pointer. + */ +#if defined(TARGET_MICROBLAZE) ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5)); -#elif defined(TARGET_S390X) +#elif defined(TARGET_CLONE_BACKWARDS) + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5)); +#elif defined(TARGET_CLONE_BACKWARDS2) ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4)); #else - ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5)); + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4)); #endif break; #ifdef __NR_exit_group -- 1.7.9.5