From aa07f5ecf9828bb2ff8d796cb0b17ad8534201c7 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Fri, 2 May 2014 11:17:07 +0300 Subject: [PATCH 01/15] linux-user: Add /proc/self/exe open forwarding QEMU already supports /proc/self/{maps,stat,auxv} so addition of /proc/self/exe is rather trivial. Fixes https://bugs.launchpad.net/qemu/+bug/1299190 Signed-off-by: Maxim Ostapenko Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9864813b7a..5203cc4577 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5225,6 +5225,11 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) { NULL, NULL, NULL } }; + if (is_proc_myself(pathname, "exe")) { + int execfd = qemu_getauxval(AT_EXECFD); + return execfd ? execfd : get_errno(open(exec_path, flags, mode)); + } + for (fake_open = fakes; fake_open->filename; fake_open++) { if (fake_open->cmp(pathname, fake_open->filename)) { break; From 8c0f0a60d48a6f62c20f4ce77dceb82047d3d57f Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 25 Mar 2014 23:21:50 +0000 Subject: [PATCH 02/15] linux-user: Assert stack used for auxvec, envp, argv Assert that the amount of stack space used for auxvec, envp & argv exactly matches the amount allocated. This catches if DLINFO_ITEMS isn't updated when another NEW_AUX_ENT is added. Signed-off-by: James Hogan Cc: Riku Voipio Cc: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/elfload.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d2380b6ccb..ecf6f350e3 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1455,6 +1455,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, info->auxv_len = sp_auxv - sp; sp = loader_build_argptr(envc, argc, sp, p, 0); + /* Check the right amount of stack was allocated for auxvec, envp & argv. */ + assert(sp_auxv - sp == size); return sp; } From 52b6549442988e0a0819b6b7fb36ded164952a34 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Thu, 17 Apr 2014 14:02:47 +0100 Subject: [PATCH 03/15] linux-user: Move if-elses to a switch statement. This makes adding more message types cleaner. Signed-off-by: Huw Davies Signed-off-by: Riku Voipio --- linux-user/syscall.c | 49 +++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5203cc4577..52bd0008d9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1242,25 +1242,40 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len)); - if ((cmsg->cmsg_level == SOL_SOCKET) && - (cmsg->cmsg_type == SCM_RIGHTS)) { - int *fd = (int *)data; - int *target_fd = (int *)target_data; - int i, numfds = len / sizeof(int); + switch (cmsg->cmsg_level) { + case SOL_SOCKET: + switch (cmsg->cmsg_type) { + case SCM_RIGHTS: + { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); - for (i = 0; i < numfds; i++) - target_fd[i] = tswap32(fd[i]); - } else if ((cmsg->cmsg_level == SOL_SOCKET) && - (cmsg->cmsg_type == SO_TIMESTAMP) && - (len == sizeof(struct timeval))) { - /* copy struct timeval to target */ - struct timeval *tv = (struct timeval *)data; - struct target_timeval *target_tv = - (struct target_timeval *)target_data; + for (i = 0; i < numfds; i++) + target_fd[i] = tswap32(fd[i]); + break; + } + case SO_TIMESTAMP: + { + struct timeval *tv = (struct timeval *)data; + struct target_timeval *target_tv = + (struct target_timeval *)target_data; - target_tv->tv_sec = tswapal(tv->tv_sec); - target_tv->tv_usec = tswapal(tv->tv_usec); - } else { + if (len != sizeof(struct timeval)) + goto unimplemented; + + /* copy struct timeval to target */ + target_tv->tv_sec = tswapal(tv->tv_sec); + target_tv->tv_usec = tswapal(tv->tv_usec); + break; + } + default: + goto unimplemented; + } + break; + + default: + unimplemented: gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); memcpy(target_data, data, len); From 4bc2975698773afdca2f79ebcff9f3b588f646fc Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Thu, 17 Apr 2014 14:02:48 +0100 Subject: [PATCH 04/15] linux-user: Add support for SCM_CREDENTIALS. Signed-off-by: Huw Davies Signed-off-by: Riku Voipio --- linux-user/syscall.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 52bd0008d9..27073b17b0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1269,6 +1269,17 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, target_tv->tv_usec = tswapal(tv->tv_usec); break; } + case SCM_CREDENTIALS: + { + struct ucred *cred = (struct ucred *)data; + struct target_ucred *target_cred = + (struct target_ucred *)target_data; + + __put_user(cred->pid, &target_cred->pid); + __put_user(cred->uid, &target_cred->uid); + __put_user(cred->gid, &target_cred->gid); + break; + } default: goto unimplemented; } From a29e5ba21f3dc01cd7f12aac9216e06e7bdd0e9e Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 25 Mar 2014 21:51:08 +0000 Subject: [PATCH 05/15] linux-user: Handle arches with llseek instead of _llseek Recently merged kernel ports (such as OpenRISC and Meta) have an llseek system call instead of _llseek. This is handled for the host architecture by defining __NR__llseek as __NR_llseek, but not for the target architecture. Handle it in the same way for these architectures, defining TARGET_NR__llseek as TARGET_NR_llseek. Signed-off-by: James Hogan Cc: Riku Voipio Cc: Jia Liu Signed-off-by: Riku Voipio --- linux-user/syscall.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 27073b17b0..15de6f8d3d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -198,6 +198,11 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \ #define __NR__llseek __NR_lseek #endif +/* Newer kernel ports have llseek() instead of _llseek() */ +#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek) +#define TARGET_NR__llseek TARGET_NR_llseek +#endif + #ifdef __NR_gettid _syscall0(int, gettid) #else From 34d6086236baeb59f4b46e2380f2b271acd6f6cf Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Tue, 29 Apr 2014 13:11:20 +0200 Subject: [PATCH 06/15] linux-user: avoid using glibc internals in _syscall5 and in definition of target_sigevent struct Use the public sigset_t instead of the glibc specific internal __sigset_t in _syscall. Calculate the sigevent pad size is calculated in similar way as kernel does it instead of using glibc internal field _pad. This is needed for building with musl libc. Signed-off-by: Natanael Copa Signed-off-by: Riku Voipio Reviewed-by: Peter Maydell --- linux-user/syscall.c | 2 +- linux-user/syscall_defs.h | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 15de6f8d3d..af0bb3565c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -411,7 +411,7 @@ static int sys_inotify_init1(int flags) #endif #define __NR_sys_ppoll __NR_ppoll _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds, - struct timespec *, timeout, const __sigset_t *, sigmask, + struct timespec *, timeout, const sigset_t *, sigmask, size_t, sigsetsize) #endif diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index fdf9a47595..69c3982ee6 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2552,12 +2552,26 @@ struct target_timer_t { abi_ulong ptr; }; +#define TARGET_SIGEV_MAX_SIZE 64 + +/* This is architecture-specific but most architectures use the default */ +#ifdef TARGET_MIPS +#define TARGET_SIGEV_PREAMBLE_SIZE (sizeof(int32_t) * 2 + sizeof(abi_long)) +#else +#define TARGET_SIGEV_PREAMBLE_SIZE (sizeof(int32_t) * 2 \ + + sizeof(target_sigval_t)) +#endif + +#define TARGET_SIGEV_PAD_SIZE ((TARGET_SIGEV_MAX_SIZE \ + - TARGET_SIGEV_PREAMBLE_SIZE) \ + / sizeof(int32_t)) + struct target_sigevent { target_sigval_t sigev_value; int32_t sigev_signo; int32_t sigev_notify; union { - int32_t _pad[ARRAY_SIZE(((struct sigevent *)0)->_sigev_un._pad)]; + int32_t _pad[TARGET_SIGEV_PAD_SIZE]; int32_t _tid; struct { From 7af03928b1194befa1ad12e25b0e53e6770ba18c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 1 May 2014 18:36:17 +0100 Subject: [PATCH 07/15] linux-user/signal.c: Set fault address in AArch64 signal info Set the fault address correctly in the signal information passed to a signal handler for AArch64 guests. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/signal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 7d6246f448..5b8a01f998 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1242,8 +1242,7 @@ static int target_setup_sigframe(struct target_rt_sigframe *sf, __put_user(env->pc, &sf->uc.tuc_mcontext.pc); __put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate); - __put_user(/*current->thread.fault_address*/ 0, - &sf->uc.tuc_mcontext.fault_address); + __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address); for (i = 0; i < TARGET_NSIG_WORDS; i++) { __put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]); From 18cb008865d078c30f8efcd28c774788ae13d6a3 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 19 Feb 2014 12:59:58 +0200 Subject: [PATCH 08/15] linux-user: rename cpu-uname -> uname To move more uname related functions out of syscall.c, rename cpu-uname.{c,h} to uname.{c.h} Signed-off-by: Riku Voipio --- linux-user/Makefile.objs | 2 +- linux-user/syscall.c | 2 +- linux-user/{cpu-uname.c => uname.c} | 2 +- linux-user/{cpu-uname.h => uname.h} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename linux-user/{cpu-uname.c => uname.c} (99%) rename linux-user/{cpu-uname.h => uname.h} (100%) diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs index 5899d72d3e..fd5021788f 100644 --- a/linux-user/Makefile.objs +++ b/linux-user/Makefile.objs @@ -1,5 +1,5 @@ obj-y = main.o syscall.o strace.o mmap.o signal.o \ - elfload.o linuxload.o uaccess.o cpu-uname.o + elfload.o linuxload.o uaccess.o uname.o obj-$(TARGET_HAS_BFLT) += flatload.o obj-$(TARGET_I386) += vm86.o diff --git a/linux-user/syscall.c b/linux-user/syscall.c index af0bb3565c..0f4a092a70 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -110,7 +110,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include "linux_loop.h" -#include "cpu-uname.h" +#include "uname.h" #include "qemu.h" diff --git a/linux-user/cpu-uname.c b/linux-user/uname.c similarity index 99% rename from linux-user/cpu-uname.c rename to linux-user/uname.c index 5db6e89567..26e90e5792 100644 --- a/linux-user/cpu-uname.c +++ b/linux-user/uname.c @@ -21,7 +21,7 @@ #include "qemu.h" //#include "qemu-common.h" -#include "cpu-uname.h" +#include "uname.h" /* return highest utsname machine name for emulated instruction set * diff --git a/linux-user/cpu-uname.h b/linux-user/uname.h similarity index 100% rename from linux-user/cpu-uname.h rename to linux-user/uname.h From 6d30db19caab3cc71a9353cab772b258f0545503 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 19 Feb 2014 15:35:35 +0200 Subject: [PATCH 09/15] linux-user: move uname functions to uname.c Make syscall.c slightly smaller by moving uname-related functions to uname.c. Signed-off-by: Riku Voipio --- linux-user/syscall.c | 102 ------------------------------------------- linux-user/uname.c | 101 ++++++++++++++++++++++++++++++++++++++++++ linux-user/uname.h | 9 ++++ 3 files changed, 110 insertions(+), 102 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0f4a092a70..9fc28bd1ba 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -60,7 +60,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include -#include //#include #include #include @@ -92,7 +91,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include -#include #include #include #include @@ -287,40 +285,6 @@ static bitmask_transtbl fcntl_flags_tbl[] = { { 0, 0, 0, 0 } }; -#define COPY_UTSNAME_FIELD(dest, src) \ - do { \ - /* __NEW_UTS_LEN doesn't include terminating null */ \ - (void) strncpy((dest), (src), __NEW_UTS_LEN); \ - (dest)[__NEW_UTS_LEN] = '\0'; \ - } while (0) - -static int sys_uname(struct new_utsname *buf) -{ - struct utsname uts_buf; - - if (uname(&uts_buf) < 0) - return (-1); - - /* - * Just in case these have some differences, we - * translate utsname to new_utsname (which is the - * struct linux kernel uses). - */ - - memset(buf, 0, sizeof(*buf)); - COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname); - COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename); - COPY_UTSNAME_FIELD(buf->release, uts_buf.release); - COPY_UTSNAME_FIELD(buf->version, uts_buf.version); - COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine); -#ifdef _GNU_SOURCE - COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname); -#endif - return (0); - -#undef COPY_UTSNAME_FIELD -} - static int sys_getcwd1(char *buf, size_t size) { if (getcwd(buf, size) == NULL) { @@ -4983,72 +4947,6 @@ int host_to_target_waitstatus(int status) return status; } -static int relstr_to_int(const char *s) -{ - /* Convert a uname release string like "2.6.18" to an integer - * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.) - */ - int i, n, tmp; - - tmp = 0; - for (i = 0; i < 3; i++) { - n = 0; - while (*s >= '0' && *s <= '9') { - n *= 10; - n += *s - '0'; - s++; - } - tmp = (tmp << 8) + n; - if (*s == '.') { - s++; - } - } - return tmp; -} - -int get_osversion(void) -{ - static int osversion; - struct new_utsname buf; - const char *s; - - if (osversion) - return osversion; - if (qemu_uname_release && *qemu_uname_release) { - s = qemu_uname_release; - } else { - if (sys_uname(&buf)) - return 0; - s = buf.release; - } - osversion = relstr_to_int(s); - return osversion; -} - -void init_qemu_uname_release(void) -{ - /* Initialize qemu_uname_release for later use. - * If the host kernel is too old and the user hasn't asked for - * a specific fake version number, we might want to fake a minimum - * target kernel version. - */ -#ifdef UNAME_MINIMUM_RELEASE - struct new_utsname buf; - - if (qemu_uname_release && *qemu_uname_release) { - return; - } - - if (sys_uname(&buf)) { - return; - } - - if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) { - qemu_uname_release = UNAME_MINIMUM_RELEASE; - } -#endif -} - static int open_self_maps(void *cpu_env, int fd) { #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) diff --git a/linux-user/uname.c b/linux-user/uname.c index 26e90e5792..fa5013e76c 100644 --- a/linux-user/uname.c +++ b/linux-user/uname.c @@ -70,3 +70,104 @@ const char *cpu_to_uname_machine(void *cpu_env) return UNAME_MACHINE; #endif } + + +#define COPY_UTSNAME_FIELD(dest, src) \ + do { \ + /* __NEW_UTS_LEN doesn't include terminating null */ \ + (void) strncpy((dest), (src), __NEW_UTS_LEN); \ + (dest)[__NEW_UTS_LEN] = '\0'; \ + } while (0) + +int sys_uname(struct new_utsname *buf) +{ + struct utsname uts_buf; + + if (uname(&uts_buf) < 0) + return (-1); + + /* + * Just in case these have some differences, we + * translate utsname to new_utsname (which is the + * struct linux kernel uses). + */ + + memset(buf, 0, sizeof(*buf)); + COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname); + COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename); + COPY_UTSNAME_FIELD(buf->release, uts_buf.release); + COPY_UTSNAME_FIELD(buf->version, uts_buf.version); + COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine); +#ifdef _GNU_SOURCE + COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname); +#endif + return (0); + +#undef COPY_UTSNAME_FIELD +} + +static int relstr_to_int(const char *s) +{ + /* Convert a uname release string like "2.6.18" to an integer + * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.) + */ + int i, n, tmp; + + tmp = 0; + for (i = 0; i < 3; i++) { + n = 0; + while (*s >= '0' && *s <= '9') { + n *= 10; + n += *s - '0'; + s++; + } + tmp = (tmp << 8) + n; + if (*s == '.') { + s++; + } + } + return tmp; +} + +int get_osversion(void) +{ + static int osversion; + struct new_utsname buf; + const char *s; + + if (osversion) + return osversion; + if (qemu_uname_release && *qemu_uname_release) { + s = qemu_uname_release; + } else { + if (sys_uname(&buf)) + return 0; + s = buf.release; + } + osversion = relstr_to_int(s); + return osversion; +} + +void init_qemu_uname_release(void) +{ + /* Initialize qemu_uname_release for later use. + * If the host kernel is too old and the user hasn't asked for + * a specific fake version number, we might want to fake a minimum + * target kernel version. + */ +#ifdef UNAME_MINIMUM_RELEASE + struct new_utsname buf; + + if (qemu_uname_release && *qemu_uname_release) { + return; + } + + if (sys_uname(&buf)) { + return; + } + + if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) { + qemu_uname_release = UNAME_MINIMUM_RELEASE; + } +#endif +} diff --git a/linux-user/uname.h b/linux-user/uname.h index 32492de71a..cc62e76cc1 100644 --- a/linux-user/uname.h +++ b/linux-user/uname.h @@ -1 +1,10 @@ +#ifndef UNAME_H +#define UNAME_H 1 + +#include +#include + const char *cpu_to_uname_machine(void *cpu_env); +int sys_uname(struct new_utsname *buf); + +#endif /* UNAME _H */ From e586822a58b6609edb5ea929e8a4aa394d32389f Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Tue, 4 Mar 2014 04:28:43 +0200 Subject: [PATCH 10/15] linux-user: remove configure option for setting uname release --enable-uname-release was a rather heavyweight hammer, as it allows providing values less that UNAME_MINIMUM_RELEASE. Also, it affects all built linux-user targets, which in most cases is not what user wants. Now that we have UNAME_MINIMUM_RELEASE for all linux-user platforms, we can drop --enable-uname-release and the related CONFIG_UNAME_RELEASE define. Users can still override the variable with QEMU_UNAME=2.6.32 or -r command line option. If distributors need to update a minimum version for a specific target, it can be done by updating UNAME_MINIMUM_RELEASE. Signed-off-by: Riku Voipio --- configure | 8 -------- linux-user/main.c | 2 +- linux-user/uname.c | 2 -- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/configure b/configure index 870c939f1d..8c50d78f87 100755 --- a/configure +++ b/configure @@ -285,7 +285,6 @@ softmmu="yes" linux_user="no" bsd_user="no" guest_base="yes" -uname_release="" aix="no" blobs="yes" pkgversion="" @@ -945,8 +944,6 @@ for opt do ;; --disable-pie) pie="no" ;; - --enable-uname-release=*) uname_release="$optarg" - ;; --enable-werror) werror="yes" ;; --disable-werror) werror="no" @@ -1295,7 +1292,6 @@ Advanced options (experts only): --fmod-lib path to FMOD library --fmod-inc path to FMOD includes --oss-lib path to OSS library - --enable-uname-release=R Return R for uname -r in usermode emulation --cpu=CPU Build for host CPU [$cpu] --disable-uuid disable uuid support --enable-uuid enable uuid support @@ -4128,8 +4124,6 @@ echo "xen support $xen" echo "brlapi support $brlapi" echo "bluez support $bluez" echo "Documentation $docs" -[ ! -z "$uname_release" ] && \ -echo "uname -r $uname_release" echo "GUEST_BASE $guest_base" echo "PIE $pie" echo "vde support $vde" @@ -4544,8 +4538,6 @@ if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak fi -echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak - if test "$zero_malloc" = "yes" ; then echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak fi diff --git a/linux-user/main.c b/linux-user/main.c index 947358a886..c38fecfdd9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -69,7 +69,7 @@ unsigned long reserved_va; static void usage(void); static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; -const char *qemu_uname_release = CONFIG_UNAME_RELEASE; +const char *qemu_uname_release; /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so we allocate a bigger stack. Need a better solution, for example diff --git a/linux-user/uname.c b/linux-user/uname.c index fa5013e76c..f5d4c66f59 100644 --- a/linux-user/uname.c +++ b/linux-user/uname.c @@ -155,7 +155,6 @@ void init_qemu_uname_release(void) * a specific fake version number, we might want to fake a minimum * target kernel version. */ -#ifdef UNAME_MINIMUM_RELEASE struct new_utsname buf; if (qemu_uname_release && *qemu_uname_release) { @@ -169,5 +168,4 @@ void init_qemu_uname_release(void) if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) { qemu_uname_release = UNAME_MINIMUM_RELEASE; } -#endif } From 43ce393ee5f7b96d2ac22fedc40d6b6fb3f65a3e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 May 2014 14:45:12 +0100 Subject: [PATCH 11/15] linux-user/elfload.c: Fix incorrect ARM HWCAP bits The ELF HWCAP bits for ARM features THUMBEE, NEON, VFPv3 and VFPv3D16 are all off by one compared to the kernel definitions. Fix this discrepancy and add in the missing CRUNCH bit which was the cause of the off-by-one error. (We don't emulate any of the CPUs which have that weird hardware, so it's otherwise uninteresting to us.) Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/elfload.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ecf6f350e3..18ea1b34a1 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -346,10 +346,11 @@ enum ARM_HWCAP_ARM_EDSP = 1 << 7, ARM_HWCAP_ARM_JAVA = 1 << 8, ARM_HWCAP_ARM_IWMMXT = 1 << 9, - ARM_HWCAP_ARM_THUMBEE = 1 << 10, - ARM_HWCAP_ARM_NEON = 1 << 11, - ARM_HWCAP_ARM_VFPv3 = 1 << 12, - ARM_HWCAP_ARM_VFPv3D16 = 1 << 13, + ARM_HWCAP_ARM_CRUNCH = 1 << 10, + ARM_HWCAP_ARM_THUMBEE = 1 << 11, + ARM_HWCAP_ARM_NEON = 1 << 12, + ARM_HWCAP_ARM_VFPv3 = 1 << 13, + ARM_HWCAP_ARM_VFPv3D16 = 1 << 14, }; #ifndef TARGET_AARCH64 From 24682654654a2e7b50afc27880f4098e5fca3742 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 May 2014 14:45:13 +0100 Subject: [PATCH 12/15] linux-user/elfload.c: Update ARM HWCAP bits The kernel has added support for a number of new ARM HWCAP bits; add them to QEMU, including support for setting them where we have a corresponding CPU feature bit. We were also incorrectly setting the VFPv3D16 HWCAP -- this means "only 16 D registers", not "supports 16-bit floating point format"; since QEMU always has 32 D registers for VFPv3, we can just remove the line that incorrectly set this bit. The kernel does not set the HWCAP_FPA even if it is providing FPA emulation via nwfpe, so don't set this bit in QEMU either. Signed-off-by: Peter Maydell Cc: qemu-stable@nongnu.org Signed-off-by: Riku Voipio --- linux-user/elfload.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 18ea1b34a1..d372300886 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -351,6 +351,13 @@ enum ARM_HWCAP_ARM_NEON = 1 << 12, ARM_HWCAP_ARM_VFPv3 = 1 << 13, ARM_HWCAP_ARM_VFPv3D16 = 1 << 14, + ARM_HWCAP_ARM_TLS = 1 << 15, + ARM_HWCAP_ARM_VFPv4 = 1 << 16, + ARM_HWCAP_ARM_IDIVA = 1 << 17, + ARM_HWCAP_ARM_IDIVT = 1 << 18, + ARM_HWCAP_ARM_VFPD32 = 1 << 19, + ARM_HWCAP_ARM_LPAE = 1 << 20, + ARM_HWCAP_ARM_EVTSTRM = 1 << 21, }; #ifndef TARGET_AARCH64 @@ -428,17 +435,28 @@ static uint32_t get_elf_hwcap(void) hwcaps |= ARM_HWCAP_ARM_HALF; hwcaps |= ARM_HWCAP_ARM_THUMB; hwcaps |= ARM_HWCAP_ARM_FAST_MULT; - hwcaps |= ARM_HWCAP_ARM_FPA; /* probe for the extra features */ #define GET_FEATURE(feat, hwcap) \ do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) + /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */ + GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP); GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP); GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT); GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE); GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON); GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3); - GET_FEATURE(ARM_FEATURE_VFP_FP16, ARM_HWCAP_ARM_VFPv3D16); + GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS); + GET_FEATURE(ARM_FEATURE_VFP4, ARM_HWCAP_ARM_VFPv4); + GET_FEATURE(ARM_FEATURE_ARM_DIV, ARM_HWCAP_ARM_IDIVA); + GET_FEATURE(ARM_FEATURE_THUMB_DIV, ARM_HWCAP_ARM_IDIVT); + /* All QEMU's VFPv3 CPUs have 32 registers, see VFP_DREG in translate.c. + * Note that the ARM_HWCAP_ARM_VFPv3D16 bit is always the inverse of + * ARM_HWCAP_ARM_VFPD32 (and so always clear for QEMU); it is unrelated + * to our VFP_FP16 feature bit. + */ + GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32); + GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); #undef GET_FEATURE return hwcaps; From 24e76ff06bcd0936ee8b04b15dca42efb7d614d1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 May 2014 14:45:14 +0100 Subject: [PATCH 13/15] linux-user/elfload.c: Fix A64 code which was incorrectly acting like A32 The ARM target-specific code in elfload.c was incorrectly allowing the 64-bit ARM target to use most of the existing 32-bit definitions: most noticably this meant that our HWCAP bits passed to the guest were wrong, and register handling when dumping core was totally broken. Fix this by properly separating the 64 and 32 bit code, since they have more differences than similarities. Signed-off-by: Peter Maydell Cc: qemu-stable@nongnu.org Signed-off-by: Riku Voipio --- linux-user/elfload.c | 86 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d372300886..ad07c43e75 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -267,17 +267,15 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en #ifdef TARGET_ARM +#ifndef TARGET_AARCH64 +/* 32 bit ARM definitions */ + #define ELF_START_MMAP 0x80000000 #define elf_check_arch(x) ((x) == ELF_MACHINE) #define ELF_ARCH ELF_MACHINE - -#ifdef TARGET_AARCH64 -#define ELF_CLASS ELFCLASS64 -#else #define ELF_CLASS ELFCLASS32 -#endif static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) @@ -285,10 +283,6 @@ static inline void init_thread(struct target_pt_regs *regs, abi_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); -#ifdef TARGET_AARCH64 - regs->pc = infop->entry & ~0x3ULL; - regs->sp = stack; -#else regs->ARM_cpsr = 0x10; if (infop->entry & 1) regs->ARM_cpsr |= CPSR_T; @@ -302,7 +296,6 @@ static inline void init_thread(struct target_pt_regs *regs, /* For uClinux PIC binaries. */ /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ regs->ARM_r10 = infop->start_data; -#endif } #define ELF_NREG 18 @@ -360,7 +353,6 @@ enum ARM_HWCAP_ARM_EVTSTRM = 1 << 21, }; -#ifndef TARGET_AARCH64 /* The commpage only exists for 32 bit kernels */ #define TARGET_HAS_VALIDATE_GUEST_SPACE @@ -422,7 +414,6 @@ static int validate_guest_space(unsigned long guest_base, return 1; /* All good */ } -#endif #define ELF_HWCAP get_elf_hwcap() @@ -462,7 +453,76 @@ static uint32_t get_elf_hwcap(void) return hwcaps; } -#endif +#else +/* 64 bit ARM definitions */ +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ((x) == ELF_MACHINE) + +#define ELF_ARCH ELF_MACHINE +#define ELF_CLASS ELFCLASS64 +#define ELF_PLATFORM "aarch64" + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + abi_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + + regs->pc = infop->entry & ~0x3ULL; + regs->sp = stack; +} + +#define ELF_NREG 34 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPUARMState *env) +{ + int i; + + for (i = 0; i < 32; i++) { + (*regs)[i] = tswapreg(env->xregs[i]); + } + (*regs)[32] = tswapreg(env->pc); + (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env)); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +enum { + ARM_HWCAP_A64_FP = 1 << 0, + ARM_HWCAP_A64_ASIMD = 1 << 1, + ARM_HWCAP_A64_EVTSTRM = 1 << 2, + ARM_HWCAP_A64_AES = 1 << 3, + ARM_HWCAP_A64_PMULL = 1 << 4, + ARM_HWCAP_A64_SHA1 = 1 << 5, + ARM_HWCAP_A64_SHA2 = 1 << 6, + ARM_HWCAP_A64_CRC32 = 1 << 7, +}; + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + hwcaps |= ARM_HWCAP_A64_FP; + hwcaps |= ARM_HWCAP_A64_ASIMD; + + /* probe for the extra features */ +#define GET_FEATURE(feat, hwcap) \ + do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) + GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP_A64_PMULL); +#undef GET_FEATURE + + return hwcaps; +} + +#endif /* not TARGET_AARCH64 */ +#endif /* TARGET_ARM */ #ifdef TARGET_UNICORE32 From ad6919dc0ab3b8ae26d772e883aa8e709785d249 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 May 2014 14:45:15 +0100 Subject: [PATCH 14/15] linux-user/elfload.c: Support ARM HWCAP2 flags The ARM kernel has chosen to spill into the HWCAP2 ELF feature bit flags early, even though it hasn't yet exhausted all 32 bits of the HWCAP word. Add support for setting this in the same way we do for HWCAP. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- include/elf.h | 1 + linux-user/elfload.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/elf.h b/include/elf.h index 667af6fc63..1599ab22d8 100644 --- a/include/elf.h +++ b/include/elf.h @@ -254,6 +254,7 @@ typedef int64_t Elf64_Sxword; #define AT_SECURE 23 /* boolean, was exec suid-like? */ #define AT_BASE_PLATFORM 24 /* string identifying real platforms */ #define AT_RANDOM 25 /* address of 16 random bytes */ +#define AT_HWCAP2 26 /* extension of AT_HWCAP */ #define AT_EXECFN 31 /* filename of the executable */ #define AT_SYSINFO 32 /* address of kernel entry point */ #define AT_SYSINFO_EHDR 33 /* address of kernel vdso */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ad07c43e75..995f999768 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -20,6 +20,7 @@ #undef ARCH_DLINFO #undef ELF_PLATFORM #undef ELF_HWCAP +#undef ELF_HWCAP2 #undef ELF_CLASS #undef ELF_DATA #undef ELF_ARCH @@ -353,6 +354,14 @@ enum ARM_HWCAP_ARM_EVTSTRM = 1 << 21, }; +enum { + ARM_HWCAP2_ARM_AES = 1 << 0, + ARM_HWCAP2_ARM_PMULL = 1 << 1, + ARM_HWCAP2_ARM_SHA1 = 1 << 2, + ARM_HWCAP2_ARM_SHA2 = 1 << 3, + ARM_HWCAP2_ARM_CRC32 = 1 << 4, +}; + /* The commpage only exists for 32 bit kernels */ #define TARGET_HAS_VALIDATE_GUEST_SPACE @@ -416,6 +425,7 @@ static int validate_guest_space(unsigned long guest_base, } #define ELF_HWCAP get_elf_hwcap() +#define ELF_HWCAP2 get_elf_hwcap2() static uint32_t get_elf_hwcap(void) { @@ -448,11 +458,22 @@ static uint32_t get_elf_hwcap(void) */ GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32); GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); -#undef GET_FEATURE return hwcaps; } +static uint32_t get_elf_hwcap2(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP2_ARM_AES); + GET_FEATURE(ARM_FEATURE_CRC, ARM_HWCAP2_ARM_CRC32); + return hwcaps; +} + +#undef GET_FEATURE + #else /* 64 bit ARM definitions */ #define ELF_START_MMAP 0x80000000 @@ -1485,6 +1506,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, size += 2; #ifdef DLINFO_ARCH_ITEMS size += DLINFO_ARCH_ITEMS * 2; +#endif +#ifdef ELF_HWCAP2 + size += 2; #endif size += envc + argc + 2; size += 1; /* argc itself */ @@ -1519,6 +1543,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes); +#ifdef ELF_HWCAP2 + NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2); +#endif + if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO From a39fb273bddd315b440b0617783051456a148242 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Tue, 8 Apr 2014 19:24:30 +0200 Subject: [PATCH 15/15] linux-user: fix getrusage and wait4 failures with invalid rusage struct Implementations of system calls getrusage and wait4 have not previously handled correctly cases when incorrect address of struct rusage is passed. This change makes sure return values are correctly set for these cases. Signed-off-by: Petar Jovanovic Signed-off-by: Riku Voipio --- linux-user/syscall.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9fc28bd1ba..6efeeff2bf 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6243,7 +6243,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct rusage rusage; ret = get_errno(getrusage(arg1, &rusage)); if (!is_error(ret)) { - host_to_target_rusage(arg2, &rusage); + ret = host_to_target_rusage(arg2, &rusage); } } break; @@ -6908,6 +6908,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, abi_long status_ptr = arg2; struct rusage rusage, *rusage_ptr; abi_ulong target_rusage = arg4; + abi_long rusage_err; if (target_rusage) rusage_ptr = &rusage; else @@ -6919,8 +6920,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (put_user_s32(status, status_ptr)) goto efault; } - if (target_rusage) - host_to_target_rusage(target_rusage, &rusage); + if (target_rusage) { + rusage_err = host_to_target_rusage(target_rusage, &rusage); + if (rusage_err) { + ret = rusage_err; + } + } } } break;