From 229d3376a38bf97aa09b6f73a957c5389badcd06 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 19 Sep 2012 04:39:53 +0200 Subject: [PATCH 01/11] linux-user: fix statfs The statfs syscall should always memset(0) its full struct extent before writing to it. Newer versions of the syscall use one of the reserved fields for flags, which would otherwise get stale values from uncleaned memory. This fixes libarchive for me, which got confused about the return value of pathconf("/", _PC_REC_XFER_ALIGN) otherwise, as it some times gave old pointers as return value. Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 471d0605f7..1a381699ef 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6529,6 +6529,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); __put_user(stfs.f_namelen, &target_stfs->f_namelen); + __put_user(stfs.f_frsize, &target_stfs->f_frsize); + memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare)); unlock_user_struct(target_stfs, arg2, 1); } break; @@ -6557,6 +6559,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, __put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]); __put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]); __put_user(stfs.f_namelen, &target_stfs->f_namelen); + __put_user(stfs.f_frsize, &target_stfs->f_frsize); + memset(target_stfs->f_spare, 0, sizeof(target_stfs->f_spare)); unlock_user_struct(target_stfs, arg3, 1); } break; From 1bdd7c7ea8a711efcb5141663865cc1f7e4e824d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 30 May 2012 14:45:21 +0200 Subject: [PATCH 02/11] linux-user: fix multi-threaded /proc/self/maps When reading our faked /proc/self/maps from a secondary thread, we get an invalid stack entry. This is because ts->stack_base is not initialized in non-primary threads. However, ts->info is, and the stack layout information we're looking for is there too. So let's use that one instead! Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1a381699ef..cf0b3858fa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4962,8 +4962,8 @@ static int open_self_maps(void *cpu_env, int fd) #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n", (unsigned long long)ts->info->stack_limit, - (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1)) - & TARGET_PAGE_MASK, + (unsigned long long)(ts->info->start_stack + + (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK, (unsigned long long)0); #endif From f287b2c2d4d20d35880ab6dca44bda0476e67dce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 15 Sep 2012 13:20:25 -0700 Subject: [PATCH 03/11] linux-user: Perform more checks on iovec lists Validate count between 0 and IOV_MAX. Limit total length of operation in the same way the kernel does. Signed-off-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/syscall.c | 166 +++++++++++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 62 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cf0b3858fa..038aefe548 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1744,55 +1744,96 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, return ret; } -/* FIXME - * lock_iovec()/unlock_iovec() have a return code of 0 for success where - * other lock functions have a return code of 0 for failure. - */ -static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, - int count, int copy) +static struct iovec *lock_iovec(int type, abi_ulong target_addr, + int count, int copy) { struct target_iovec *target_vec; - abi_ulong base; + struct iovec *vec; + abi_ulong total_len, max_len; int i; - target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); - if (!target_vec) - return -TARGET_EFAULT; - for(i = 0;i < count; i++) { - base = tswapal(target_vec[i].iov_base); - vec[i].iov_len = tswapal(target_vec[i].iov_len); - if (vec[i].iov_len != 0) { - vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); - /* Don't check lock_user return value. We must call writev even - if a element has invalid base address. */ - } else { - /* zero length pointer is ignored */ - vec[i].iov_base = NULL; - } + if (count == 0) { + errno = 0; + return NULL; } - unlock_user (target_vec, target_addr, 0); - return 0; + if (count > IOV_MAX) { + errno = EINVAL; + return NULL; + } + + vec = calloc(count, sizeof(struct iovec)); + if (vec == NULL) { + errno = ENOMEM; + return NULL; + } + + target_vec = lock_user(VERIFY_READ, target_addr, + count * sizeof(struct target_iovec), 1); + if (target_vec == NULL) { + errno = EFAULT; + goto fail2; + } + + /* ??? If host page size > target page size, this will result in a + value larger than what we can actually support. */ + max_len = 0x7fffffff & TARGET_PAGE_MASK; + total_len = 0; + + for (i = 0; i < count; i++) { + abi_ulong base = tswapal(target_vec[i].iov_base); + abi_long len = tswapal(target_vec[i].iov_len); + + if (len < 0) { + errno = EINVAL; + goto fail; + } else if (len == 0) { + /* Zero length pointer is ignored. */ + vec[i].iov_base = 0; + } else { + vec[i].iov_base = lock_user(type, base, len, copy); + if (!vec[i].iov_base) { + errno = EFAULT; + goto fail; + } + if (len > max_len - total_len) { + len = max_len - total_len; + } + } + vec[i].iov_len = len; + total_len += len; + } + + unlock_user(target_vec, target_addr, 0); + return vec; + + fail: + free(vec); + fail2: + unlock_user(target_vec, target_addr, 0); + return NULL; } -static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) +static void unlock_iovec(struct iovec *vec, abi_ulong target_addr, + int count, int copy) { struct target_iovec *target_vec; - abi_ulong base; int i; - target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); - if (!target_vec) - return -TARGET_EFAULT; - for(i = 0;i < count; i++) { - if (target_vec[i].iov_base) { - base = tswapal(target_vec[i].iov_base); + target_vec = lock_user(VERIFY_READ, target_addr, + count * sizeof(struct target_iovec), 1); + if (target_vec) { + for (i = 0; i < count; i++) { + abi_ulong base = tswapal(target_vec[i].iov_base); + abi_long len = tswapal(target_vec[i].iov_base); + if (len < 0) { + break; + } unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); } + unlock_user(target_vec, target_addr, 0); } - unlock_user (target_vec, target_addr, 0); - return 0; + free(vec); } /* do_socket() Must return target values and target errnos. */ @@ -1888,8 +1929,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, ret = target_to_host_sockaddr(msg.msg_name, tswapal(msgp->msg_name), msg.msg_namelen); if (ret) { - unlock_user_struct(msgp, target_msg, send ? 0 : 1); - return ret; + goto out2; } } else { msg.msg_name = NULL; @@ -1900,9 +1940,13 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, msg.msg_flags = tswap32(msgp->msg_flags); count = tswapal(msgp->msg_iovlen); - vec = alloca(count * sizeof(struct iovec)); target_vec = tswapal(msgp->msg_iov); - lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, vec, target_vec, count, send); + vec = lock_iovec(send ? VERIFY_READ : VERIFY_WRITE, + target_vec, count, send); + if (vec == NULL) { + ret = -host_to_target_errno(errno); + goto out2; + } msg.msg_iovlen = count; msg.msg_iov = vec; @@ -1932,6 +1976,7 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, out: unlock_iovec(vec, target_vec, count, !send); +out2: unlock_user_struct(msgp, target_msg, send ? 0 : 1); return ret; } @@ -7188,26 +7233,24 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; case TARGET_NR_readv: { - int count = arg3; - struct iovec *vec; - - vec = alloca(count * sizeof(struct iovec)); - if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0) - goto efault; - ret = get_errno(readv(arg1, vec, count)); - unlock_iovec(vec, arg2, count, 1); + struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0); + if (vec != NULL) { + ret = get_errno(readv(arg1, vec, arg3)); + unlock_iovec(vec, arg2, arg3, 1); + } else { + ret = -host_to_target_errno(errno); + } } break; case TARGET_NR_writev: { - int count = arg3; - struct iovec *vec; - - vec = alloca(count * sizeof(struct iovec)); - if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) - goto efault; - ret = get_errno(writev(arg1, vec, count)); - unlock_iovec(vec, arg2, count, 0); + struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1); + if (vec != NULL) { + ret = get_errno(writev(arg1, vec, arg3)); + unlock_iovec(vec, arg2, arg3, 0); + } else { + ret = -host_to_target_errno(errno); + } } break; case TARGET_NR_getsid: @@ -8632,14 +8675,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_vmsplice case TARGET_NR_vmsplice: { - int count = arg3; - struct iovec *vec; - - vec = alloca(count * sizeof(struct iovec)); - if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) - goto efault; - ret = get_errno(vmsplice(arg1, vec, count, arg4)); - unlock_iovec(vec, arg2, count, 0); + struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1); + if (vec != NULL) { + ret = get_errno(vmsplice(arg1, vec, arg3, arg4)); + unlock_iovec(vec, arg2, arg3, 0); + } else { + ret = -host_to_target_errno(errno); + } } break; #endif From 3d21d29c32380384e5ee5b804d0b0bf720469d97 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 15 Sep 2012 13:20:46 -0700 Subject: [PATCH 04/11] linux-user: Implement gethostname Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/syscall.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 038aefe548..89c74ada23 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8867,6 +8867,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; } +#endif +#ifdef TARGET_NR_gethostname + case TARGET_NR_gethostname: + { + char *name = lock_user(VERIFY_WRITE, arg1, arg2, 0); + if (name) { + ret = get_errno(gethostname(name, arg2)); + unlock_user(name, arg1, arg2); + } else { + ret = -TARGET_EFAULT; + } + break; + } #endif default: unimplemented: From b7fb2310136090aab86004363f7c031b30845f2f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Sep 2012 15:59:24 -0700 Subject: [PATCH 05/11] alpha-linux-user: Fix sigaltstack structure definition Signed-off-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/alpha/target_signal.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h index 94f15f612f..d3822da60e 100644 --- a/linux-user/alpha/target_signal.h +++ b/linux-user/alpha/target_signal.h @@ -6,9 +6,10 @@ /* this struct defines a stack used during syscall handling */ typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; + abi_ulong ss_sp; + int32_t ss_flags; + int32_t dummy; + abi_ulong ss_size; } target_stack_t; From a05c64091509056b7e321537196db967f2545601 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 15 Sep 2012 11:34:20 -0700 Subject: [PATCH 06/11] linux-user: Fix siginfo handling Compare signal numbers in the proper domain. Convert all of the fields for SIGIO and SIGCHLD. Signed-off-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/qemu.h | 3 +++ linux-user/signal.c | 59 ++++++++++++++++++++++++++++++-------------- linux-user/syscall.c | 2 +- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index fc4cc00b9f..5e53dca09e 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -219,6 +219,9 @@ unsigned long init_guest_space(unsigned long host_start, #include "qemu-log.h" +/* syscall.c */ +int host_to_target_waitstatus(int status); + /* strace.c */ void print_syscall(int num, abi_long arg1, abi_long arg2, abi_long arg3, diff --git a/linux-user/signal.c b/linux-user/signal.c index 15bc4e8f62..95e2ffa007 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -202,46 +202,67 @@ void target_to_host_old_sigset(sigset_t *sigset, static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, const siginfo_t *info) { - int sig; - sig = host_to_target_signal(info->si_signo); + int sig = host_to_target_signal(info->si_signo); tinfo->si_signo = sig; tinfo->si_errno = 0; tinfo->si_code = info->si_code; - if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || - sig == SIGBUS || sig == SIGTRAP) { - /* should never come here, but who knows. The information for - the target is irrelevant */ + + if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV + || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) { + /* Should never come here, but who knows. The information for + the target is irrelevant. */ tinfo->_sifields._sigfault._addr = 0; - } else if (sig == SIGIO) { + } else if (sig == TARGET_SIGIO) { + tinfo->_sifields._sigpoll._band = info->si_band; tinfo->_sifields._sigpoll._fd = info->si_fd; + } else if (sig == TARGET_SIGCHLD) { + tinfo->_sifields._sigchld._pid = info->si_pid; + tinfo->_sifields._sigchld._uid = info->si_uid; + tinfo->_sifields._sigchld._status + = host_to_target_waitstatus(info->si_status); + tinfo->_sifields._sigchld._utime = info->si_utime; + tinfo->_sifields._sigchld._stime = info->si_stime; } else if (sig >= TARGET_SIGRTMIN) { tinfo->_sifields._rt._pid = info->si_pid; tinfo->_sifields._rt._uid = info->si_uid; /* XXX: potential problem if 64 bit */ - tinfo->_sifields._rt._sigval.sival_ptr = - (abi_ulong)(unsigned long)info->si_value.sival_ptr; + tinfo->_sifields._rt._sigval.sival_ptr + = (abi_ulong)(unsigned long)info->si_value.sival_ptr; } } static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) { - int sig; - sig = info->si_signo; + int sig = info->si_signo; tinfo->si_signo = tswap32(sig); tinfo->si_errno = tswap32(info->si_errno); tinfo->si_code = tswap32(info->si_code); - if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || - sig == SIGBUS || sig == SIGTRAP) { - tinfo->_sifields._sigfault._addr = - tswapal(info->_sifields._sigfault._addr); - } else if (sig == SIGIO) { - tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd); + + if (sig == TARGET_SIGILL || sig == TARGET_SIGFPE || sig == TARGET_SIGSEGV + || sig == TARGET_SIGBUS || sig == TARGET_SIGTRAP) { + tinfo->_sifields._sigfault._addr + = tswapal(info->_sifields._sigfault._addr); + } else if (sig == TARGET_SIGIO) { + tinfo->_sifields._sigpoll._band + = tswap32(info->_sifields._sigpoll._band); + tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd); + } else if (sig == TARGET_SIGCHLD) { + tinfo->_sifields._sigchld._pid + = tswap32(info->_sifields._sigchld._pid); + tinfo->_sifields._sigchld._uid + = tswap32(info->_sifields._sigchld._uid); + tinfo->_sifields._sigchld._status + = tswap32(info->_sifields._sigchld._status); + tinfo->_sifields._sigchld._utime + = tswapal(info->_sifields._sigchld._utime); + tinfo->_sifields._sigchld._stime + = tswapal(info->_sifields._sigchld._stime); } else if (sig >= TARGET_SIGRTMIN) { tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); - tinfo->_sifields._rt._sigval.sival_ptr = - tswapal(info->_sifields._rt._sigval.sival_ptr); + tinfo->_sifields._rt._sigval.sival_ptr + = tswapal(info->_sifields._rt._sigval.sival_ptr); } } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 89c74ada23..009bf8f1a9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4918,7 +4918,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, /* Map host to target signal numbers for the wait family of syscalls. Assume all other status bits are the same. */ -static int host_to_target_waitstatus(int status) +int host_to_target_waitstatus(int status) { if (WIFSIGNALED(status)) { return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f); From 885c1d10b803fc37e6656e733ba916c702b6f515 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 24 Aug 2012 06:55:53 +0000 Subject: [PATCH 07/11] linux-user: If loading fails, print error as string, not number If the attempt to load the guest executable fails, print the error message as a string, not a number. This requires us to fix a couple of places in loader_exec() where we were returning -1 instead of a valid negative errno. The change allows us to drop the "Unknown binary format" message because the strerror-enhanced message is now a more self-explanatory "Error while loading $guest-binary: Exec format error". Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/linuxload.c | 8 ++++---- linux-user/main.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index b47025f08a..381ab8914b 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -140,8 +140,9 @@ int loader_exec(const char * filename, char ** argv, char ** envp, bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); memset(bprm->page, 0, sizeof(bprm->page)); retval = open(filename, O_RDONLY); - if (retval < 0) - return retval; + if (retval < 0) { + return -errno; + } bprm->fd = retval; bprm->filename = (char *)filename; bprm->argc = count(argv); @@ -165,8 +166,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp, retval = load_flt_binary(bprm,regs,infop); #endif } else { - fprintf(stderr, "Unknown binary format\n"); - return -1; + return -ENOEXEC; } } diff --git a/linux-user/main.c b/linux-user/main.c index 9f3476ba57..bcaadb67cb 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3569,7 +3569,7 @@ int main(int argc, char **argv, char **envp) ret = loader_exec(filename, target_argv, target_environ, regs, info, &bprm); if (ret != 0) { - printf("Error %d while loading %s\n", ret, filename); + printf("Error while loading %s: %s\n", filename, strerror(-ret)); _exit(1); } From 30163d89953e2ec3e5fc53918682c8bc4b1b3b8d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 9 Oct 2012 03:16:49 +0000 Subject: [PATCH 08/11] configure: Remove unnecessary host_guest_base code All TCG hosts now support guest-base functionality, so we can remove the setting of host_guest_base to 'yes' in every arm of the case "$cpu" statement, and simply set guest_base to default to 'yes'. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Riku Voipio --- configure | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/configure b/configure index c4a78376b6..a6bdf9aff9 100755 --- a/configure +++ b/configure @@ -198,7 +198,7 @@ cocoa="no" softmmu="yes" linux_user="no" bsd_user="no" -guest_base="" +guest_base="yes" uname_release="" mixemu="no" aix="no" @@ -867,63 +867,36 @@ for opt do esac done -host_guest_base="no" case "$cpu" in sparc) LDFLAGS="-m32 $LDFLAGS" QEMU_CFLAGS="-m32 -mcpu=ultrasparc $QEMU_CFLAGS" - host_guest_base="yes" ;; sparc64) LDFLAGS="-m64 $LDFLAGS" QEMU_CFLAGS="-m64 -mcpu=ultrasparc $QEMU_CFLAGS" - host_guest_base="yes" ;; s390) QEMU_CFLAGS="-m31 -march=z990 $QEMU_CFLAGS" LDFLAGS="-m31 $LDFLAGS" - host_guest_base="yes" ;; s390x) QEMU_CFLAGS="-m64 -march=z990 $QEMU_CFLAGS" LDFLAGS="-m64 $LDFLAGS" - host_guest_base="yes" ;; i386) QEMU_CFLAGS="-m32 $QEMU_CFLAGS" LDFLAGS="-m32 $LDFLAGS" cc_i386='$(CC) -m32' - host_guest_base="yes" ;; x86_64) QEMU_CFLAGS="-m64 $QEMU_CFLAGS" LDFLAGS="-m64 $LDFLAGS" cc_i386='$(CC) -m32' - host_guest_base="yes" - ;; - arm*) - host_guest_base="yes" - ;; - ppc*) - host_guest_base="yes" - ;; - mips*) - host_guest_base="yes" - ;; - ia64*) - host_guest_base="yes" - ;; - hppa*) - host_guest_base="yes" - ;; - unicore32*) - host_guest_base="yes" ;; + # No special flags required for other host CPUs esac -[ -z "$guest_base" ] && guest_base="$host_guest_base" - - default_target_list="" # these targets are portable From 07e10e5de1470bdf1d1ed97c85cb7ed9e4826775 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 9 Oct 2012 03:16:50 +0000 Subject: [PATCH 09/11] tcg: Remove TCG_TARGET_HAS_GUEST_BASE define GUEST_BASE support is now supported by all TCG backends, and is now mandatory. Drop the now-pointless TCG_TARGET_HAS_GUEST_BASE define (set by every backend) and the error if it is unset. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Riku Voipio --- tcg/arm/tcg-target.h | 2 -- tcg/hppa/tcg-target.h | 2 -- tcg/i386/tcg-target.h | 2 -- tcg/ia64/tcg-target.h | 3 --- tcg/mips/tcg-target.h | 3 --- tcg/ppc/tcg-target.h | 2 -- tcg/ppc64/tcg-target.h | 1 - tcg/s390/tcg-target.h | 2 -- tcg/sparc/tcg-target.h | 2 -- tcg/tcg.c | 4 ---- tcg/tci/tcg-target.h | 3 --- 11 files changed, 26 deletions(-) diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index e2299cadd3..2bc7dff846 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -75,8 +75,6 @@ typedef enum { #define TCG_TARGET_HAS_deposit_i32 0 #define TCG_TARGET_HAS_movcond_i32 0 -#define TCG_TARGET_HAS_GUEST_BASE - enum { TCG_AREG0 = TCG_REG_R6, }; diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h index 5351353719..f43fb419ae 100644 --- a/tcg/hppa/tcg-target.h +++ b/tcg/hppa/tcg-target.h @@ -103,8 +103,6 @@ typedef enum { #define TCG_TARGET_HAS_ext8u_i32 0 /* and rd, rs, 0xff */ #define TCG_TARGET_HAS_ext16u_i32 0 /* and rd, rs, 0xffff */ -#define TCG_TARGET_HAS_GUEST_BASE - #define TCG_AREG0 TCG_REG_R17 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index ace63ba37b..dbc6756414 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -125,8 +125,6 @@ typedef enum { ((ofs) == 0 && (len) == 16)) #define TCG_TARGET_deposit_i64_valid TCG_TARGET_deposit_i32_valid -#define TCG_TARGET_HAS_GUEST_BASE - #if TCG_TARGET_REG_BITS == 64 # define TCG_AREG0 TCG_REG_R14 #else diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index 368aee4196..b7e01b25ae 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -144,9 +144,6 @@ typedef enum { #define TCG_AREG0 TCG_REG_R7 -/* Guest base is supported */ -#define TCG_TARGET_HAS_GUEST_BASE - static inline void flush_icache_range(tcg_target_ulong start, tcg_target_ulong stop) { diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 7020d65845..65b5c59e89 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -116,9 +116,6 @@ typedef enum { #define TCG_AREG0 TCG_REG_S0 -/* guest base is supported */ -#define TCG_TARGET_HAS_GUEST_BASE - #ifdef __OpenBSD__ #include #else diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 3259d898ab..ad433ae5bb 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -96,8 +96,6 @@ typedef enum { #define TCG_AREG0 TCG_REG_R27 -#define TCG_TARGET_HAS_GUEST_BASE - #define tcg_qemu_tb_exec(env, tb_ptr) \ ((long __attribute__ ((longcall)) \ (*)(void *, void *))code_gen_prologue)(env, tb_ptr) diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h index 57569e8938..97fc5c9885 100644 --- a/tcg/ppc64/tcg-target.h +++ b/tcg/ppc64/tcg-target.h @@ -108,5 +108,4 @@ typedef enum { #define TCG_AREG0 TCG_REG_R27 -#define TCG_TARGET_HAS_GUEST_BASE #define TCG_TARGET_EXTEND_ARGS 1 diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index ed55c331c6..a0181aef74 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -88,8 +88,6 @@ typedef enum TCGReg { #define TCG_TARGET_HAS_movcond_i64 0 #endif -#define TCG_TARGET_HAS_GUEST_BASE - /* used for function call generation */ #define TCG_REG_CALL_STACK TCG_REG_R15 #define TCG_TARGET_STACK_ALIGN 8 diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index 6314ffb303..4a17f1e118 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -124,8 +124,6 @@ typedef enum { #define TCG_TARGET_HAS_movcond_i64 0 #endif -#define TCG_TARGET_HAS_GUEST_BASE - #define TCG_AREG0 TCG_REG_I0 static inline void flush_icache_range(tcg_target_ulong start, diff --git a/tcg/tcg.c b/tcg/tcg.c index 32cd0c6b65..a171f784a4 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -62,10 +62,6 @@ #include "elf.h" -#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE) -#error GUEST_BASE not supported on this host. -#endif - /* Forward declarations for functions declared in tcg-target.c and used here. */ static void tcg_target_init(TCGContext *s); static void tcg_target_qemu_prologue(TCGContext *s); diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 6d894953aa..37f28c0522 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -102,9 +102,6 @@ #define TCG_TARGET_HAS_movcond_i64 0 #endif /* TCG_TARGET_REG_BITS == 64 */ -/* Offset to user memory in user mode. */ -#define TCG_TARGET_HAS_GUEST_BASE - /* Number of registers available. For 32 bit hosts, we need more than 8 registers (call arguments). */ /* #define TCG_TARGET_NB_REGS 8 */ From 4a1def4e4ec2f0eb72b15596a04a030cdc889370 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 29 Sep 2012 15:32:38 +0000 Subject: [PATCH 10/11] linux-user: ppc: mark as long long aligned The SysV PPC32 ABI dictates that long long (64bit) parameters are pass in odd/even register pairs. Because unlike ARM and MIPS we start at an odd register number, we can reuse the same aligning code that ARM and MIPS use. Clarified inline comment that it is SysV ABI that requires long long aligned parameters - Riku Signed-off-by: Alexander Graf Signed-off-by: Riku Voipio --- linux-user/syscall.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 009bf8f1a9..3da8e5137c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -587,12 +587,17 @@ extern int setfsgid(int); extern int setgroups(int, gid_t *); /* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ -#ifdef TARGET_ARM +#ifdef TARGET_ARM static inline int regpairs_aligned(void *cpu_env) { return ((((CPUARMState *)cpu_env)->eabi) == 1) ; } #elif defined(TARGET_MIPS) static inline int regpairs_aligned(void *cpu_env) { 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; } #else static inline int regpairs_aligned(void *cpu_env) { return 0; } #endif From ae017a5b95962f68ece21065376cd3266998fd02 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 29 Sep 2012 15:32:39 +0000 Subject: [PATCH 11/11] linux-user: register align p{read, write}64 pread64 and pwrite64 pass 64bit parameters which for some architectures need to be aligned to special argument pairs, creating a gap argument. Handle this special case the same way we handle it in other places of the code. Reported-by: Alex Barcelo Signed-off-by: Alexander Graf Tested-by: Alex Barcelo Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3da8e5137c..14a6b32ab1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7467,12 +7467,20 @@ 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)) { + arg4 = arg5; + arg5 = arg6; + } if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) goto efault; ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5))); unlock_user(p, arg2, ret); break; case TARGET_NR_pwrite64: + if (regpairs_aligned(cpu_env)) { + arg4 = arg5; + arg5 = arg6; + } if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) goto efault; ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));