From 229d3376a38bf97aa09b6f73a957c5389badcd06 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 19 Sep 2012 04:39:53 +0200 Subject: [PATCH 001/160] 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 002/160] 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 003/160] 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 004/160] 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 005/160] 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 006/160] 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 007/160] 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 008/160] 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 009/160] 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 010/160] 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 011/160] 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))); From 7762c2c1e02e44fdc473cbe75105faba08b906cc Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 20 Sep 2012 16:02:51 +0300 Subject: [PATCH 012/160] memory: rename 'exec-obsolete.h' exec-obsolete.h used to hold pre-memory-API functions that were used from device code prior to the transition to the memory API. Now that the transition is complete, the name no longer describes the file. The functions still need to be merged better into the memory core, but there's no danger of anyone using them. Reviewed-by: Anthony Liguori Signed-off-by: Avi Kivity --- cputlb.c | 3 +-- exec.c | 3 +-- exec-obsolete.h => memory-internal.h | 8 ++------ memory.c | 3 +-- 4 files changed, 5 insertions(+), 12 deletions(-) rename exec-obsolete.h => memory-internal.h (97%) diff --git a/cputlb.c b/cputlb.c index 51b5897d37..0627f32e35 100644 --- a/cputlb.c +++ b/cputlb.c @@ -24,8 +24,7 @@ #include "cputlb.h" -#define WANT_EXEC_OBSOLETE -#include "exec-obsolete.h" +#include "memory-internal.h" //#define DEBUG_TLB //#define DEBUG_TLB_CHECK diff --git a/exec.c b/exec.c index 7899042ce9..eb0ec93f9a 100644 --- a/exec.c +++ b/exec.c @@ -59,8 +59,7 @@ #include "cputlb.h" -#define WANT_EXEC_OBSOLETE -#include "exec-obsolete.h" +#include "memory-internal.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH diff --git a/exec-obsolete.h b/memory-internal.h similarity index 97% rename from exec-obsolete.h rename to memory-internal.h index 286e2f75e1..43fa886264 100644 --- a/exec-obsolete.h +++ b/memory-internal.h @@ -16,12 +16,8 @@ * The functions declared here will be removed soon. */ -#ifndef EXEC_OBSOLETE_H -#define EXEC_OBSOLETE_H - -#ifndef WANT_EXEC_OBSOLETE -#error Do not include exec-obsolete.h -#endif +#ifndef MEMORY_INTERNAL_H +#define MEMORY_INTERNAL_H #ifndef CONFIG_USER_ONLY #include "hw/xen.h" diff --git a/memory.c b/memory.c index 4f3ade06dd..1aeca08dda 100644 --- a/memory.c +++ b/memory.c @@ -20,8 +20,7 @@ #include "kvm.h" #include -#define WANT_EXEC_OBSOLETE -#include "exec-obsolete.h" +#include "memory-internal.h" unsigned memory_region_transaction_depth = 0; static bool global_dirty_log = false; From 0fada67420e29f389119ca6f44285203400e0730 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 30 Sep 2012 22:02:53 +0200 Subject: [PATCH 013/160] vhost: use MemoryListener filtering to only monitor RAM address space Instead of checking manually, let the listener filter for us. This prepares us for DMA address spaces. Signed-off-by: Avi Kivity --- hw/vhost.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index d0ce5aad9b..100f7659a0 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -434,8 +434,7 @@ static void vhost_set_memory(MemoryListener *listener, static bool vhost_section(MemoryRegionSection *section) { - return section->address_space == get_system_memory() - && memory_region_is_ram(section->mr); + return memory_region_is_ram(section->mr); } static void vhost_begin(MemoryListener *listener) @@ -793,7 +792,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, hdev->log_size = 0; hdev->log_enabled = false; hdev->started = false; - memory_listener_register(&hdev->memory_listener, NULL); + memory_listener_register(&hdev->memory_listener, get_system_memory()); hdev->force = force; return 0; fail: From d22b096ef6e0b20810193b68a1d472f3fb8a4f9e Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 30 Sep 2012 22:21:11 +0200 Subject: [PATCH 014/160] kvm: use separate MemoryListeners for memory and I/O The construct if (address_space == get_system_memory()) { // memory thing } else { // io thing } fails if we have more than two address spaces. Use a separate listener for memory and I/O, and utilize MemoryListener's address space filtering to fix this. Signed-off-by: Avi Kivity --- kvm-all.c | 83 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index 92a71374ed..c69e012004 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -755,9 +755,16 @@ static void kvm_log_global_stop(struct MemoryListener *listener) assert(r >= 0); } -static void kvm_mem_ioeventfd_add(MemoryRegionSection *section, - bool match_data, uint64_t data, int fd) +static void kvm_log_nop(struct MemoryListener *listener) { +} + +static void kvm_mem_ioeventfd_add(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) +{ + int fd = event_notifier_get_fd(e); int r; assert(match_data && section->size <= 8); @@ -769,9 +776,12 @@ static void kvm_mem_ioeventfd_add(MemoryRegionSection *section, } } -static void kvm_mem_ioeventfd_del(MemoryRegionSection *section, - bool match_data, uint64_t data, int fd) +static void kvm_mem_ioeventfd_del(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) { + int fd = event_notifier_get_fd(e); int r; r = kvm_set_ioeventfd_mmio(fd, section->offset_within_address_space, @@ -781,9 +791,12 @@ static void kvm_mem_ioeventfd_del(MemoryRegionSection *section, } } -static void kvm_io_ioeventfd_add(MemoryRegionSection *section, - bool match_data, uint64_t data, int fd) +static void kvm_io_ioeventfd_add(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) { + int fd = event_notifier_get_fd(e); int r; assert(match_data && section->size == 2); @@ -795,10 +808,13 @@ static void kvm_io_ioeventfd_add(MemoryRegionSection *section, } } -static void kvm_io_ioeventfd_del(MemoryRegionSection *section, - bool match_data, uint64_t data, int fd) +static void kvm_io_ioeventfd_del(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) { + int fd = event_notifier_get_fd(e); int r; r = kvm_set_ioeventfd_pio_word(fd, section->offset_within_address_space, @@ -808,34 +824,6 @@ static void kvm_io_ioeventfd_del(MemoryRegionSection *section, } } -static void kvm_eventfd_add(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ - if (section->address_space == get_system_memory()) { - kvm_mem_ioeventfd_add(section, match_data, data, - event_notifier_get_fd(e)); - } else { - kvm_io_ioeventfd_add(section, match_data, data, - event_notifier_get_fd(e)); - } -} - -static void kvm_eventfd_del(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ - if (section->address_space == get_system_memory()) { - kvm_mem_ioeventfd_del(section, match_data, data, - event_notifier_get_fd(e)); - } else { - kvm_io_ioeventfd_del(section, match_data, data, - event_notifier_get_fd(e)); - } -} - static MemoryListener kvm_memory_listener = { .begin = kvm_begin, .commit = kvm_commit, @@ -847,8 +835,24 @@ static MemoryListener kvm_memory_listener = { .log_sync = kvm_log_sync, .log_global_start = kvm_log_global_start, .log_global_stop = kvm_log_global_stop, - .eventfd_add = kvm_eventfd_add, - .eventfd_del = kvm_eventfd_del, + .eventfd_add = kvm_mem_ioeventfd_add, + .eventfd_del = kvm_mem_ioeventfd_del, + .priority = 10, +}; + +static MemoryListener kvm_io_listener = { + .begin = kvm_begin, + .commit = kvm_commit, + .region_add = kvm_region_nop, + .region_del = kvm_region_nop, + .region_nop = kvm_region_nop, + .log_start = kvm_region_nop, + .log_stop = kvm_region_nop, + .log_sync = kvm_region_nop, + .log_global_start = kvm_log_nop, + .log_global_stop = kvm_log_nop, + .eventfd_add = kvm_io_ioeventfd_add, + .eventfd_del = kvm_io_ioeventfd_del, .priority = 10, }; @@ -1401,7 +1405,8 @@ int kvm_init(void) } kvm_state = s; - memory_listener_register(&kvm_memory_listener, NULL); + memory_listener_register(&kvm_memory_listener, get_system_memory()); + memory_listener_register(&kvm_io_listener, get_system_io()); s->many_ioeventfds = kvm_check_many_ioeventfds(); From 12b40e471f33e552fa3d962887b416cf67831446 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 30 Sep 2012 22:21:11 +0200 Subject: [PATCH 015/160] xen_pt: use separate MemoryListeners for memory and I/O Using an unfiltered memory listener will cause regions to be reported fails multiple times if we have more than two address spaces. Use a separate listener for memory and I/O, and utilize MemoryListener's address space filtering to fix this. Signed-off-by: Avi Kivity --- hw/xen_pt.c | 38 +++++++++++++++++++++++++++++++++++++- hw/xen_pt.h | 1 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 838bcea4d6..4f90ad9e7a 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -59,6 +59,7 @@ #include "xen_backend.h" #include "xen_pt.h" #include "range.h" +#include "exec-memory.h" #define XEN_PT_NR_IRQS (256) static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0}; @@ -624,6 +625,22 @@ static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec) xen_pt_region_update(s, sec, false); } +static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec) +{ + XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, + io_listener); + + xen_pt_region_update(s, sec, true); +} + +static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec) +{ + XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, + io_listener); + + xen_pt_region_update(s, sec, false); +} + static void xen_pt_region_nop(MemoryListener *l, MemoryRegionSection *s) { } @@ -657,6 +674,22 @@ static const MemoryListener xen_pt_memory_listener = { .priority = 10, }; +static const MemoryListener xen_pt_io_listener = { + .begin = xen_pt_begin, + .commit = xen_pt_commit, + .region_add = xen_pt_io_region_add, + .region_nop = xen_pt_region_nop, + .region_del = xen_pt_io_region_del, + .log_start = xen_pt_log_fns, + .log_stop = xen_pt_log_fns, + .log_sync = xen_pt_log_fns, + .log_global_start = xen_pt_log_global_fns, + .log_global_stop = xen_pt_log_global_fns, + .eventfd_add = xen_pt_eventfd_fns, + .eventfd_del = xen_pt_eventfd_fns, + .priority = 10, +}; + /* init */ static int xen_pt_initfn(PCIDevice *d) @@ -694,6 +727,7 @@ static int xen_pt_initfn(PCIDevice *d) } s->memory_listener = xen_pt_memory_listener; + s->io_listener = xen_pt_io_listener; /* Handle real device's MMIO/PIO BARs */ xen_pt_register_regions(s); @@ -760,7 +794,8 @@ static int xen_pt_initfn(PCIDevice *d) } out: - memory_listener_register(&s->memory_listener, NULL); + memory_listener_register(&s->memory_listener, get_system_memory()); + memory_listener_register(&s->io_listener, get_system_io()); XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n", bus, slot, func); @@ -815,6 +850,7 @@ static void xen_pt_unregister_device(PCIDevice *d) xen_pt_unregister_regions(s); memory_listener_unregister(&s->memory_listener); + memory_listener_unregister(&s->io_listener); xen_host_pci_device_put(&s->real_device); } diff --git a/hw/xen_pt.h b/hw/xen_pt.h index 112477a881..f15e69a290 100644 --- a/hw/xen_pt.h +++ b/hw/xen_pt.h @@ -209,6 +209,7 @@ struct XenPCIPassthroughState { MemoryRegion rom; MemoryListener memory_listener; + MemoryListener io_listener; }; int xen_pt_config_init(XenPCIPassthroughState *s); From 8786db7cb96f8ce5c75c6e1e074319c9dca8d356 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 13:53:41 +0200 Subject: [PATCH 016/160] memory: prepare AddressSpace for exporting AddressSpace contains a member, current_map, of type FlatView. Since we want to limit the leakage of internal types to public headers, switch to a pointer to a FlatView. There is no performance impact as this isn't used during lookups, only address space reconfigurations. Reviewed-by: Anthony Liguori Signed-off-by: Avi Kivity --- memory.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/memory.c b/memory.c index 1aeca08dda..7e9e373a8c 100644 --- a/memory.c +++ b/memory.c @@ -222,7 +222,7 @@ typedef struct AddressSpaceOps AddressSpaceOps; /* A system address space - I/O, memory, etc. */ struct AddressSpace { MemoryRegion *root; - FlatView current_map; + FlatView *current_map; int ioeventfd_nb; MemoryRegionIoeventfd *ioeventfds; }; @@ -631,7 +631,7 @@ static void address_space_update_ioeventfds(AddressSpace *as) AddrRange tmp; unsigned i; - FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { for (i = 0; i < fr->mr->ioeventfd_nb; ++i) { tmp = addrrange_shift(fr->mr->ioeventfds[i].addr, int128_sub(fr->addr.start, @@ -719,13 +719,13 @@ static void address_space_update_topology_pass(AddressSpace *as, static void address_space_update_topology(AddressSpace *as) { - FlatView old_view = as->current_map; + FlatView old_view = *as->current_map; FlatView new_view = generate_memory_topology(as->root); address_space_update_topology_pass(as, old_view, new_view, false); address_space_update_topology_pass(as, old_view, new_view, true); - as->current_map = new_view; + *as->current_map = new_view; flatview_destroy(&old_view); address_space_update_ioeventfds(as); } @@ -1083,7 +1083,7 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr) { FlatRange *fr; - FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { + FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) { if (fr->mr == mr) { MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, Forward, log_sync); @@ -1135,7 +1135,7 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr) CoalescedMemoryRange *cmr; AddrRange tmp; - FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) { + FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) { if (fr->mr == mr) { qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start), int128_get64(fr->addr.size)); @@ -1399,7 +1399,7 @@ static int cmp_flatrange_addr(const void *addr_, const void *fr_) static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr) { - return bsearch(&addr, as->current_map.ranges, as->current_map.nr, + return bsearch(&addr, as->current_map->ranges, as->current_map->nr, sizeof(FlatRange), cmp_flatrange_addr); } @@ -1416,7 +1416,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space, return ret; } - while (fr > as->current_map.ranges + while (fr > as->current_map->ranges && addrrange_intersects(fr[-1].addr, range)) { --fr; } @@ -1437,7 +1437,7 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) AddressSpace *as = memory_region_to_address_space(address_space); FlatRange *fr; - FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); } } @@ -1459,6 +1459,10 @@ static void listener_add_address_space(MemoryListener *listener, { FlatRange *fr; + if (!as->root) { + return; + } + if (listener->address_space_filter && listener->address_space_filter != as->root) { return; @@ -1467,7 +1471,7 @@ static void listener_add_address_space(MemoryListener *listener, if (global_dirty_log) { listener->log_global_start(listener); } - FOR_EACH_FLAT_RANGE(fr, &as->current_map) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { MemoryRegionSection section = { .mr = fr->mr, .address_space = as->root, @@ -1506,18 +1510,23 @@ void memory_listener_unregister(MemoryListener *listener) QTAILQ_REMOVE(&memory_listeners, listener, link); } -void set_system_memory_map(MemoryRegion *mr) +static void address_space_init(AddressSpace *as, MemoryRegion *root) { memory_region_transaction_begin(); - address_space_memory.root = mr; + as->root = root; + as->current_map = g_new(FlatView, 1); + flatview_init(as->current_map); memory_region_transaction_commit(); } +void set_system_memory_map(MemoryRegion *mr) +{ + address_space_init(&address_space_memory, mr); +} + void set_system_io_map(MemoryRegion *mr) { - memory_region_transaction_begin(); - address_space_io.root = mr; - memory_region_transaction_commit(); + address_space_init(&address_space_io, mr); } uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size) From 9ad2bbc16788d3048d514f3450d0975e59d46119 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 14:59:23 +0200 Subject: [PATCH 017/160] memory: export AddressSpace The DMA API will use an AddressSpace to differentiate among different initiators. Reviewed-by: Anthony Liguori Signed-off-by: Avi Kivity --- memory.c | 11 +---------- memory.h | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/memory.c b/memory.c index 7e9e373a8c..431a8672a2 100644 --- a/memory.c +++ b/memory.c @@ -216,17 +216,8 @@ struct FlatView { unsigned nr_allocated; }; -typedef struct AddressSpace AddressSpace; typedef struct AddressSpaceOps AddressSpaceOps; -/* A system address space - I/O, memory, etc. */ -struct AddressSpace { - MemoryRegion *root; - FlatView *current_map; - int ioeventfd_nb; - MemoryRegionIoeventfd *ioeventfds; -}; - #define FOR_EACH_FLAT_RANGE(var, view) \ for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var) @@ -1510,7 +1501,7 @@ void memory_listener_unregister(MemoryListener *listener) QTAILQ_REMOVE(&memory_listeners, listener, link); } -static void address_space_init(AddressSpace *as, MemoryRegion *root) +void address_space_init(AddressSpace *as, MemoryRegion *root) { memory_region_transaction_begin(); as->root = root; diff --git a/memory.h b/memory.h index 37ce1517ca..a1d75e761c 100644 --- a/memory.h +++ b/memory.h @@ -157,6 +157,19 @@ struct MemoryRegionPortio { #define PORTIO_END_OF_LIST() { } +typedef struct AddressSpace AddressSpace; + +/** + * AddressSpace: describes a mapping of addresses to #MemoryRegion objects + */ +struct AddressSpace { + /* All fields are private. */ + MemoryRegion *root; + struct FlatView *current_map; + int ioeventfd_nb; + struct MemoryRegionIoeventfd *ioeventfds; +}; + typedef struct MemoryRegionSection MemoryRegionSection; /** @@ -776,6 +789,14 @@ void memory_global_dirty_log_stop(void); void mtree_info(fprintf_function mon_printf, void *f); +/** + * address_space_init: initializes an address space + * + * @as: an uninitialized #AddressSpace + * @root: a #MemoryRegion that routes addesses for the address space + */ +void address_space_init(AddressSpace *as, MemoryRegion *root); + #endif #endif From 0d673e36a74d366ce090ab096955317b581c0fb0 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 15:28:50 +0200 Subject: [PATCH 018/160] memory: maintain a list of address spaces Instead of embedding knowledge of the memory and I/O address spaces in the memory core, maintain a list of all address spaces. This list will later be extended dynamically for other bus masters. Reviewed-by: Anthony Liguori Signed-off-by: Avi Kivity --- memory.c | 75 ++++++++++++++++++++++++++++++++++---------------------- memory.h | 2 ++ 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/memory.c b/memory.c index 431a8672a2..b58b97ccdd 100644 --- a/memory.c +++ b/memory.c @@ -28,6 +28,9 @@ static bool global_dirty_log = false; static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners = QTAILQ_HEAD_INITIALIZER(memory_listeners); +static QTAILQ_HEAD(, AddressSpace) address_spaces + = QTAILQ_HEAD_INITIALIZER(address_spaces); + typedef struct AddrRange AddrRange; /* @@ -449,14 +452,15 @@ static AddressSpace address_space_io; static AddressSpace *memory_region_to_address_space(MemoryRegion *mr) { + AddressSpace *as; + while (mr->parent) { mr = mr->parent; } - if (mr == address_space_memory.root) { - return &address_space_memory; - } - if (mr == address_space_io.root) { - return &address_space_io; + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + if (mr == as->root) { + return as; + } } abort(); } @@ -729,16 +733,15 @@ void memory_region_transaction_begin(void) void memory_region_transaction_commit(void) { + AddressSpace *as; + assert(memory_region_transaction_depth); --memory_region_transaction_depth; if (!memory_region_transaction_depth) { MEMORY_LISTENER_CALL_GLOBAL(begin, Forward); - if (address_space_memory.root) { - address_space_update_topology(&address_space_memory); - } - if (address_space_io.root) { - address_space_update_topology(&address_space_io); + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + address_space_update_topology(as); } MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); @@ -1072,12 +1075,14 @@ void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr, void memory_region_sync_dirty_bitmap(MemoryRegion *mr) { + AddressSpace *as; FlatRange *fr; - FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) { - if (fr->mr == mr) { - MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, - Forward, log_sync); + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { + if (fr->mr == mr) { + MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); + } } } } @@ -1120,13 +1125,13 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr) return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK); } -static void memory_region_update_coalesced_range(MemoryRegion *mr) +static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as) { FlatRange *fr; CoalescedMemoryRange *cmr; AddrRange tmp; - FOR_EACH_FLAT_RANGE(fr, address_space_memory.current_map) { + FOR_EACH_FLAT_RANGE(fr, as->current_map) { if (fr->mr == mr) { qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start), int128_get64(fr->addr.size)); @@ -1145,6 +1150,15 @@ static void memory_region_update_coalesced_range(MemoryRegion *mr) } } +static void memory_region_update_coalesced_range(MemoryRegion *mr) +{ + AddressSpace *as; + + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + memory_region_update_coalesced_range_as(mr, as); + } +} + void memory_region_set_coalescing(MemoryRegion *mr) { memory_region_clear_coalescing(mr); @@ -1450,10 +1464,6 @@ static void listener_add_address_space(MemoryListener *listener, { FlatRange *fr; - if (!as->root) { - return; - } - if (listener->address_space_filter && listener->address_space_filter != as->root) { return; @@ -1478,6 +1488,7 @@ static void listener_add_address_space(MemoryListener *listener, void memory_listener_register(MemoryListener *listener, MemoryRegion *filter) { MemoryListener *other = NULL; + AddressSpace *as; listener->address_space_filter = filter; if (QTAILQ_EMPTY(&memory_listeners) @@ -1492,8 +1503,10 @@ void memory_listener_register(MemoryListener *listener, MemoryRegion *filter) } QTAILQ_INSERT_BEFORE(other, listener, link); } - listener_add_address_space(listener, &address_space_memory); - listener_add_address_space(listener, &address_space_io); + + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + listener_add_address_space(listener, as); + } } void memory_listener_unregister(MemoryListener *listener) @@ -1507,17 +1520,21 @@ void address_space_init(AddressSpace *as, MemoryRegion *root) as->root = root; as->current_map = g_new(FlatView, 1); flatview_init(as->current_map); + QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); + as->name = NULL; memory_region_transaction_commit(); } void set_system_memory_map(MemoryRegion *mr) { address_space_init(&address_space_memory, mr); + address_space_memory.name = "memory"; } void set_system_io_map(MemoryRegion *mr) { address_space_init(&address_space_io, mr); + address_space_io.name = "I/O"; } uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size) @@ -1637,16 +1654,16 @@ void mtree_info(fprintf_function mon_printf, void *f) { MemoryRegionListHead ml_head; MemoryRegionList *ml, *ml2; + AddressSpace *as; QTAILQ_INIT(&ml_head); - mon_printf(f, "memory\n"); - mtree_print_mr(mon_printf, f, address_space_memory.root, 0, 0, &ml_head); - - if (address_space_io.root && - !QTAILQ_EMPTY(&address_space_io.root->subregions)) { - mon_printf(f, "I/O\n"); - mtree_print_mr(mon_printf, f, address_space_io.root, 0, 0, &ml_head); + QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { + if (!as->name) { + continue; + } + mon_printf(f, "%s\n", as->name); + mtree_print_mr(mon_printf, f, as->root, 0, 0, &ml_head); } mon_printf(f, "aliases\n"); diff --git a/memory.h b/memory.h index a1d75e761c..46bc5e1cfd 100644 --- a/memory.h +++ b/memory.h @@ -164,10 +164,12 @@ typedef struct AddressSpace AddressSpace; */ struct AddressSpace { /* All fields are private. */ + const char *name; MemoryRegion *root; struct FlatView *current_map; int ioeventfd_nb; struct MemoryRegionIoeventfd *ioeventfds; + QTAILQ_ENTRY(AddressSpace) address_spaces_link; }; typedef struct MemoryRegionSection MemoryRegionSection; From 975aefe011197453284a4ab777000183e6096d5b Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 16:39:57 +0200 Subject: [PATCH 019/160] memory: provide defaults for MemoryListener operations Many listeners don't need to respond to all MemoryListener callbacks; provide suitable no-op defaults instead. Signed-off-by: Avi Kivity --- memory.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/memory.c b/memory.c index b58b97ccdd..269af3f6b0 100644 --- a/memory.c +++ b/memory.c @@ -99,13 +99,17 @@ static bool memory_listener_match(MemoryListener *listener, switch (_direction) { \ case Forward: \ QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ - _listener->_callback(_listener, ##_args); \ + if (_listener->_callback) { \ + _listener->_callback(_listener, ##_args); \ + } \ } \ break; \ case Reverse: \ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ memory_listeners, link) { \ - _listener->_callback(_listener, ##_args); \ + if (_listener->_callback) { \ + _listener->_callback(_listener, ##_args); \ + } \ } \ break; \ default: \ @@ -120,7 +124,8 @@ static bool memory_listener_match(MemoryListener *listener, switch (_direction) { \ case Forward: \ QTAILQ_FOREACH(_listener, &memory_listeners, link) { \ - if (memory_listener_match(_listener, _section)) { \ + if (_listener->_callback \ + && memory_listener_match(_listener, _section)) { \ _listener->_callback(_listener, _section, ##_args); \ } \ } \ @@ -128,7 +133,8 @@ static bool memory_listener_match(MemoryListener *listener, case Reverse: \ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \ memory_listeners, link) { \ - if (memory_listener_match(_listener, _section)) { \ + if (_listener->_callback \ + && memory_listener_match(_listener, _section)) { \ _listener->_callback(_listener, _section, ##_args); \ } \ } \ @@ -1470,8 +1476,11 @@ static void listener_add_address_space(MemoryListener *listener, } if (global_dirty_log) { - listener->log_global_start(listener); + if (listener->log_global_start) { + listener->log_global_start(listener); + } } + FOR_EACH_FLAT_RANGE(fr, as->current_map) { MemoryRegionSection section = { .mr = fr->mr, @@ -1481,7 +1490,9 @@ static void listener_add_address_space(MemoryListener *listener, .offset_within_address_space = int128_get64(fr->addr.start), .readonly = fr->readonly, }; - listener->region_add(listener, §ion); + if (listener->region_add) { + listener->region_add(listener, §ion); + } } } From 9a2c913b77b54f650d60680d14b995bacbc63e50 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 16:42:23 +0200 Subject: [PATCH 020/160] memory: drop no-op MemoryListener callbacks Removes quite a bit of useless code. Signed-off-by: Avi Kivity --- exec.c | 96 ---------------------------------------------------------- 1 file changed, 96 deletions(-) diff --git a/exec.c b/exec.c index eb0ec93f9a..6558728d09 100644 --- a/exec.c +++ b/exec.c @@ -3194,32 +3194,12 @@ static void core_region_add(MemoryListener *listener, cpu_register_physical_memory_log(section, section->readonly); } -static void core_region_del(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - static void core_region_nop(MemoryListener *listener, MemoryRegionSection *section) { cpu_register_physical_memory_log(section, section->readonly); } -static void core_log_start(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void core_log_stop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void core_log_sync(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - static void core_log_global_start(MemoryListener *listener) { cpu_physical_memory_set_dirty_tracking(1); @@ -3230,26 +3210,6 @@ static void core_log_global_stop(MemoryListener *listener) cpu_physical_memory_set_dirty_tracking(0); } -static void core_eventfd_add(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, EventNotifier *e) -{ -} - -static void core_eventfd_del(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, EventNotifier *e) -{ -} - -static void io_begin(MemoryListener *listener) -{ -} - -static void io_commit(MemoryListener *listener) -{ -} - static void io_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -3268,75 +3228,19 @@ static void io_region_del(MemoryListener *listener, isa_unassign_ioport(section->offset_within_address_space, section->size); } -static void io_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void io_log_start(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void io_log_stop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void io_log_sync(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - -static void io_log_global_start(MemoryListener *listener) -{ -} - -static void io_log_global_stop(MemoryListener *listener) -{ -} - -static void io_eventfd_add(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, EventNotifier *e) -{ -} - -static void io_eventfd_del(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, EventNotifier *e) -{ -} - static MemoryListener core_memory_listener = { .begin = core_begin, .commit = core_commit, .region_add = core_region_add, - .region_del = core_region_del, .region_nop = core_region_nop, - .log_start = core_log_start, - .log_stop = core_log_stop, - .log_sync = core_log_sync, .log_global_start = core_log_global_start, .log_global_stop = core_log_global_stop, - .eventfd_add = core_eventfd_add, - .eventfd_del = core_eventfd_del, .priority = 0, }; static MemoryListener io_memory_listener = { - .begin = io_begin, - .commit = io_commit, .region_add = io_region_add, .region_del = io_region_del, - .region_nop = io_region_nop, - .log_start = io_log_start, - .log_stop = io_log_stop, - .log_sync = io_log_sync, - .log_global_start = io_log_global_start, - .log_global_stop = io_log_global_stop, - .eventfd_add = io_eventfd_add, - .eventfd_del = io_eventfd_del, .priority = 0, }; From e71e602cb5ac194ea414816068f398080d913abb Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 16:42:23 +0200 Subject: [PATCH 021/160] vfio: drop no-op MemoryListener callbacks Removes quite a bit of useless code. Signed-off-by: Avi Kivity --- hw/vfio_pci.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 639371e7a2..49e11e7db3 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -930,25 +930,6 @@ static int vfio_dma_map(VFIOContainer *container, target_phys_addr_t iova, return -errno; } -static void vfio_listener_dummy1(MemoryListener *listener) -{ - /* We don't do batching (begin/commit) or care about logging */ -} - -static void vfio_listener_dummy2(MemoryListener *listener, - MemoryRegionSection *section) -{ - /* We don't do logging or care about nops */ -} - -static void vfio_listener_dummy3(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ - /* We don't care about eventfds */ -} - static bool vfio_listener_skipped_section(MemoryRegionSection *section) { return !memory_region_is_ram(section->mr); @@ -1040,18 +1021,8 @@ static void vfio_listener_region_del(MemoryListener *listener, } static MemoryListener vfio_memory_listener = { - .begin = vfio_listener_dummy1, - .commit = vfio_listener_dummy1, .region_add = vfio_listener_region_add, .region_del = vfio_listener_region_del, - .region_nop = vfio_listener_dummy2, - .log_start = vfio_listener_dummy2, - .log_stop = vfio_listener_dummy2, - .log_sync = vfio_listener_dummy2, - .log_global_start = vfio_listener_dummy1, - .log_global_stop = vfio_listener_dummy1, - .eventfd_add = vfio_listener_dummy3, - .eventfd_del = vfio_listener_dummy3, }; static void vfio_listener_release(VFIOContainer *container) From 6381fc188cd1c41c69ce947853dd1281d8f3c07e Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 16:42:23 +0200 Subject: [PATCH 022/160] xen_pt: drop no-op MemoryListener callbacks Removes quite a bit of useless code. Signed-off-by: Avi Kivity --- hw/xen_pt.c | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 4f90ad9e7a..d5dc11e582 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -601,14 +601,6 @@ static void xen_pt_region_update(XenPCIPassthroughState *s, } } -static void xen_pt_begin(MemoryListener *l) -{ -} - -static void xen_pt_commit(MemoryListener *l) -{ -} - static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec) { XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, @@ -641,52 +633,15 @@ static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec) xen_pt_region_update(s, sec, false); } -static void xen_pt_region_nop(MemoryListener *l, MemoryRegionSection *s) -{ -} - -static void xen_pt_log_fns(MemoryListener *l, MemoryRegionSection *s) -{ -} - -static void xen_pt_log_global_fns(MemoryListener *l) -{ -} - -static void xen_pt_eventfd_fns(MemoryListener *l, MemoryRegionSection *s, - bool match_data, uint64_t data, EventNotifier *n) -{ -} - static const MemoryListener xen_pt_memory_listener = { - .begin = xen_pt_begin, - .commit = xen_pt_commit, .region_add = xen_pt_region_add, - .region_nop = xen_pt_region_nop, .region_del = xen_pt_region_del, - .log_start = xen_pt_log_fns, - .log_stop = xen_pt_log_fns, - .log_sync = xen_pt_log_fns, - .log_global_start = xen_pt_log_global_fns, - .log_global_stop = xen_pt_log_global_fns, - .eventfd_add = xen_pt_eventfd_fns, - .eventfd_del = xen_pt_eventfd_fns, .priority = 10, }; static const MemoryListener xen_pt_io_listener = { - .begin = xen_pt_begin, - .commit = xen_pt_commit, .region_add = xen_pt_io_region_add, - .region_nop = xen_pt_region_nop, .region_del = xen_pt_io_region_del, - .log_start = xen_pt_log_fns, - .log_stop = xen_pt_log_fns, - .log_sync = xen_pt_log_fns, - .log_global_start = xen_pt_log_global_fns, - .log_global_stop = xen_pt_log_global_fns, - .eventfd_add = xen_pt_eventfd_fns, - .eventfd_del = xen_pt_eventfd_fns, .priority = 10, }; From ad1ff3d99a55f559e00a11de14d91ca33a139252 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 16:42:23 +0200 Subject: [PATCH 023/160] kvm: drop no-op MemoryListener callbacks Removes quite a bit of useless code. Signed-off-by: Avi Kivity --- kvm-all.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index c69e012004..46cf7e9ec4 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -703,14 +703,6 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) } } -static void kvm_begin(MemoryListener *listener) -{ -} - -static void kvm_commit(MemoryListener *listener) -{ -} - static void kvm_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -723,11 +715,6 @@ static void kvm_region_del(MemoryListener *listener, kvm_set_phys_mem(section, false); } -static void kvm_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - static void kvm_log_sync(MemoryListener *listener, MemoryRegionSection *section) { @@ -755,10 +742,6 @@ static void kvm_log_global_stop(struct MemoryListener *listener) assert(r >= 0); } -static void kvm_log_nop(struct MemoryListener *listener) -{ -} - static void kvm_mem_ioeventfd_add(MemoryListener *listener, MemoryRegionSection *section, bool match_data, uint64_t data, @@ -825,11 +808,8 @@ static void kvm_io_ioeventfd_del(MemoryListener *listener, } static MemoryListener kvm_memory_listener = { - .begin = kvm_begin, - .commit = kvm_commit, .region_add = kvm_region_add, .region_del = kvm_region_del, - .region_nop = kvm_region_nop, .log_start = kvm_log_start, .log_stop = kvm_log_stop, .log_sync = kvm_log_sync, @@ -841,16 +821,6 @@ static MemoryListener kvm_memory_listener = { }; static MemoryListener kvm_io_listener = { - .begin = kvm_begin, - .commit = kvm_commit, - .region_add = kvm_region_nop, - .region_del = kvm_region_nop, - .region_nop = kvm_region_nop, - .log_start = kvm_region_nop, - .log_stop = kvm_region_nop, - .log_sync = kvm_region_nop, - .log_global_start = kvm_log_nop, - .log_global_stop = kvm_log_nop, .eventfd_add = kvm_io_ioeventfd_add, .eventfd_del = kvm_io_ioeventfd_del, .priority = 10, From bf83601fddb976753b498a879cbdc8f107f59f53 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 16:42:23 +0200 Subject: [PATCH 024/160] xen: drop no-op MemoryListener callbacks Removes quite a bit of useless code. Signed-off-by: Avi Kivity --- xen-all.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/xen-all.c b/xen-all.c index bcb7ef7c84..8731e1165b 100644 --- a/xen-all.c +++ b/xen-all.c @@ -454,14 +454,6 @@ static void xen_set_memory(struct MemoryListener *listener, } } -static void xen_begin(MemoryListener *listener) -{ -} - -static void xen_commit(MemoryListener *listener) -{ -} - static void xen_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -474,11 +466,6 @@ static void xen_region_del(MemoryListener *listener, xen_set_memory(listener, section, false); } -static void xen_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - static void xen_sync_dirty_bitmap(XenIOState *state, target_phys_addr_t start_addr, ram_addr_t size) @@ -565,33 +552,14 @@ static void xen_log_global_stop(MemoryListener *listener) xen_in_migration = false; } -static void xen_eventfd_add(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ -} - -static void xen_eventfd_del(MemoryListener *listener, - MemoryRegionSection *section, - bool match_data, uint64_t data, - EventNotifier *e) -{ -} - static MemoryListener xen_memory_listener = { - .begin = xen_begin, - .commit = xen_commit, .region_add = xen_region_add, .region_del = xen_region_del, - .region_nop = xen_region_nop, .log_start = xen_log_start, .log_stop = xen_log_stop, .log_sync = xen_log_sync, .log_global_start = xen_log_global_start, .log_global_stop = xen_log_global_stop, - .eventfd_add = xen_eventfd_add, - .eventfd_del = xen_eventfd_del, .priority = 10, }; From 7fc645bf7a313d75904f8901f4e231008e79999a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 26 Sep 2012 19:48:54 +0100 Subject: [PATCH 025/160] tcg/arm: Factor out code to emit immediate or reg-reg op The code to emit either an immediate cmp or a register cmp insn is duplicated in several places; factor it out into its own function. Signed-off-by: Peter Maydell Signed-off-by: Aurelien Jarno --- tcg/arm/tcg-target.c | 46 +++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 737200e5e6..3596bce325 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -467,6 +467,21 @@ static inline void tcg_out_movi32(TCGContext *s, } } +static inline void tcg_out_dat_rI(TCGContext *s, int cond, int opc, TCGArg dst, + TCGArg lhs, TCGArg rhs, int rhs_is_const) +{ + /* Emit either the reg,imm or reg,reg form of a data-processing insn. + * rhs must satisfy the "rI" constraint. + */ + if (rhs_is_const) { + int rot = encode_imm(rhs); + assert(rot >= 0); + tcg_out_dat_imm(s, cond, opc, dst, lhs, rotl(rhs, rot) | (rot << 7)); + } else { + tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0)); + } +} + static inline void tcg_out_mul32(TCGContext *s, int cond, int rd, int rs, int rm) { @@ -1576,14 +1591,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, c = ARITH_EOR; /* Fall through. */ gen_arith: - if (const_args[2]) { - int rot; - rot = encode_imm(args[2]); - tcg_out_dat_imm(s, COND_AL, c, - args[0], args[1], rotl(args[2], rot) | (rot << 7)); - } else - tcg_out_dat_reg(s, COND_AL, c, - args[0], args[1], args[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_rI(s, COND_AL, c, args[0], args[1], args[2], const_args[2]); break; case INDEX_op_add2_i32: tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC, @@ -1643,15 +1651,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_brcond_i32: - if (const_args[1]) { - int rot; - rot = encode_imm(args[1]); - tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, - args[0], rotl(args[1], rot) | (rot << 7)); - } else { - tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, - args[0], args[1], SHIFT_IMM_LSL(0)); - } + tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, + args[0], args[1], const_args[1]); tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]); break; case INDEX_op_brcond2_i32: @@ -1670,15 +1671,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]); break; case INDEX_op_setcond_i32: - if (const_args[2]) { - int rot; - rot = encode_imm(args[2]); - tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, - args[1], rotl(args[2], rot) | (rot << 7)); - } else { - tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, - args[1], args[2], SHIFT_IMM_LSL(0)); - } + tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, + args[1], args[2], const_args[2]); tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]], ARITH_MOV, args[0], 0, 1); tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])], From 4a1d241e3cc0a0cacb5de9084a4edb543d529d51 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 26 Sep 2012 19:48:55 +0100 Subject: [PATCH 026/160] tcg/arm: Implement movcond_i32 Implement movcond_i32 for ARM, as the sequence mov dst, v2 (implicitly done by the tcg common code) cmp c1, c2 movCC dst, v1 Signed-off-by: Peter Maydell Signed-off-by: Aurelien Jarno --- tcg/arm/tcg-target.c | 10 ++++++++++ tcg/arm/tcg-target.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 3596bce325..e790bf04b4 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -1572,6 +1572,15 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_movi_i32: tcg_out_movi32(s, COND_AL, args[0], args[1]); break; + case INDEX_op_movcond_i32: + /* Constraints mean that v2 is always in the same register as dest, + * so we only need to do "if condition passed, move v1 to dest". + */ + tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, + args[1], args[2], const_args[2]); + tcg_out_dat_rI(s, tcg_cond_to_arm_cond[args[5]], + ARITH_MOV, args[0], 0, args[3], const_args[3]); + break; case INDEX_op_add_i32: c = ARITH_ADD; goto gen_arith; @@ -1782,6 +1791,7 @@ static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_brcond_i32, { "r", "rI" } }, { INDEX_op_setcond_i32, { "r", "r", "rI" } }, + { INDEX_op_movcond_i32, { "r", "r", "rI", "rI", "0" } }, /* TODO: "r", "r", "r", "r", "ri", "ri" */ { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index e2299cadd3..0df33520f8 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -73,7 +73,7 @@ typedef enum { #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 0 -#define TCG_TARGET_HAS_movcond_i32 0 +#define TCG_TARGET_HAS_movcond_i32 1 #define TCG_TARGET_HAS_GUEST_BASE From da897bf5ae2d0276dcabe941ba3a402aa718b740 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Tue, 9 Oct 2012 21:53:55 +0200 Subject: [PATCH 027/160] tcg/ia64: use stack for TCG temps Use stack instead of temp_buf array in CPUState for TCG temps. Signed-off-by: Blue Swirl Signed-off-by: Aurelien Jarno --- tcg/ia64/tcg-target.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 705712f775..4cba344bdc 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -2269,9 +2269,12 @@ static void tcg_target_qemu_prologue(TCGContext *s) int frame_size; /* reserve some stack space */ - frame_size = TCG_STATIC_CALL_ARGS_SIZE; + frame_size = TCG_STATIC_CALL_ARGS_SIZE + + CPU_TEMP_BUF_NLONGS * sizeof(long); frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) & ~(TCG_TARGET_STACK_ALIGN - 1); + tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE, + CPU_TEMP_BUF_NLONGS * sizeof(long)); /* First emit adhoc function descriptor */ *(uint64_t *)(s->code_ptr) = (uint64_t)s->code_ptr + 16; /* entry point */ @@ -2378,6 +2381,4 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(s->reserved_regs, TCG_REG_R6); tcg_add_target_add_op_defs(ia64_op_defs); - tcg_set_frame(s, TCG_AREG0, offsetof(CPUArchState, temp_buf), - CPU_TEMP_BUF_NLONGS * sizeof(long)); } From b90cf716928d7934f4c1392f9097247a84b295d2 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 9 Oct 2012 21:53:55 +0200 Subject: [PATCH 028/160] tcg/ia64: implement movcond_i32/64 Implement movcond_i32/64 on ia64 hosts. It is not possible to have immediate compare arguments without adding a new bundle, but it is possible to have 22-bit immediate value arguments. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/ia64/tcg-target.c | 38 ++++++++++++++++++++++++++++++++++++++ tcg/ia64/tcg-target.h | 4 ++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 4cba344bdc..d4d350fe36 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -1404,6 +1404,34 @@ static inline void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGArg ret, tcg_opc_a5(TCG_REG_P7, OPC_ADDL_A5, ret, 0, TCG_REG_R0)); } +static inline void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGArg ret, + TCGArg c1, TCGArg c2, + TCGArg v1, int const_v1, + TCGArg v2, int const_v2, int cmp4) +{ + uint64_t opc1, opc2; + + if (const_v1) { + opc1 = tcg_opc_a5(TCG_REG_P6, OPC_ADDL_A5, ret, v1, TCG_REG_R0); + } else if (ret == v1) { + opc1 = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0); + } else { + opc1 = tcg_opc_a4(TCG_REG_P6, OPC_ADDS_A4, ret, 0, v1); + } + if (const_v2) { + opc2 = tcg_opc_a5(TCG_REG_P7, OPC_ADDL_A5, ret, v2, TCG_REG_R0); + } else if (ret == v2) { + opc2 = tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0); + } else { + opc2 = tcg_opc_a4(TCG_REG_P7, OPC_ADDS_A4, ret, 0, v2); + } + + tcg_out_bundle(s, MmI, + tcg_opc_cmp_a(TCG_REG_P0, cond, c1, c2, cmp4), + opc1, + opc2); +} + #if defined(CONFIG_SOFTMMU) #include "../../softmmu_defs.h" @@ -2106,6 +2134,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_setcond_i64: tcg_out_setcond(s, args[3], args[0], args[1], args[2], 0); break; + case INDEX_op_movcond_i32: + tcg_out_movcond(s, args[5], args[0], args[1], args[2], + args[3], const_args[3], args[4], const_args[4], 1); + break; + case INDEX_op_movcond_i64: + tcg_out_movcond(s, args[5], args[0], args[1], args[2], + args[3], const_args[3], args[4], const_args[4], 0); + break; case INDEX_op_qemu_ld8u: tcg_out_qemu_ld(s, args, 0); @@ -2196,6 +2232,7 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_brcond_i32, { "rI", "rI" } }, { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rI", "rI" } }, { INDEX_op_mov_i64, { "r", "r" } }, { INDEX_op_movi_i64, { "r" } }, @@ -2245,6 +2282,7 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_brcond_i64, { "rI", "rI" } }, { INDEX_op_setcond_i64, { "r", "rZ", "rZ" } }, + { INDEX_op_movcond_i64, { "r", "rZ", "rZ", "rI", "rI" } }, { INDEX_op_qemu_ld8u, { "r", "r" } }, { INDEX_op_qemu_ld8s, { "r", "r" } }, diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index 368aee4196..5e7d970982 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -131,10 +131,10 @@ typedef enum { #define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_rot_i64 1 +#define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_movcond_i64 1 #define TCG_TARGET_HAS_deposit_i32 0 #define TCG_TARGET_HAS_deposit_i64 0 -#define TCG_TARGET_HAS_movcond_i32 0 -#define TCG_TARGET_HAS_movcond_i64 0 /* optional instructions automatically implemented */ #define TCG_TARGET_HAS_neg_i32 0 /* sub r1, r0, r3 */ From 2174d1e1ff3522f6f64260bad460185b7ca5bd26 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 9 Oct 2012 21:53:55 +0200 Subject: [PATCH 029/160] tcg/ia64: remove suboptimal register shifting in qemu_ld/st ops Remove suboptimal register shifting in qemu_ld/st ops, introduced at the CONFIG_TCG_PASS_AREG0 time. As mem_idx is now loaded in register R58/R59 for the slow path, we have to make sure to do it last, to not add additional register constraints. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/ia64/tcg-target.c | 82 +++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index d4d350fe36..16edc1b85a 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -1438,7 +1438,7 @@ static inline void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGArg ret, /* Load and compare a TLB entry, and return the result in (p6, p7). R2 is loaded with the address of the addend TLB entry. - R56 is loaded with the address, zero extented on 32-bit targets. */ + R57 is loaded with the address, zero extented on 32-bit targets. */ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, int s_bits, uint64_t offset_rw, uint64_t offset_addend) @@ -1456,9 +1456,9 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R2, offset_rw, TCG_REG_R2), #if TARGET_LONG_BITS == 32 - tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29, TCG_REG_R56, addr_reg), + tcg_opc_i29(TCG_REG_P0, OPC_ZXT4_I29, TCG_REG_R57, addr_reg), #else - tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R56, + tcg_opc_a4(TCG_REG_P0, OPC_ADDS_A4, TCG_REG_R57, 0, addr_reg), #endif tcg_opc_a1 (TCG_REG_P0, OPC_ADD_A1, TCG_REG_R2, @@ -1466,12 +1466,12 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, tcg_out_bundle(s, mII, tcg_opc_m3 (TCG_REG_P0, (TARGET_LONG_BITS == 32 - ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R57, + ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R56, TCG_REG_R2, offset_addend - offset_rw), tcg_opc_a1 (TCG_REG_P0, OPC_AND_A1, TCG_REG_R3, - TCG_REG_R3, TCG_REG_R56), + TCG_REG_R3, TCG_REG_R57), tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6, - TCG_REG_P7, TCG_REG_R3, TCG_REG_R57)); + TCG_REG_P7, TCG_REG_R3, TCG_REG_R56)); } /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, @@ -1508,8 +1508,8 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) /* P6 is the fast path, and P7 the slow path */ tcg_out_bundle(s, mLX, - tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R57, - mem_index, TCG_REG_R0), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, + TCG_REG_R56, 0, TCG_AREG0), tcg_opc_l2 ((tcg_target_long) qemu_ld_helpers[s_bits]), tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2, (tcg_target_long) qemu_ld_helpers[s_bits])); @@ -1517,7 +1517,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3, TCG_REG_R2, 8), tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3, - TCG_REG_R3, TCG_REG_R56), + TCG_REG_R3, TCG_REG_R57), tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6, TCG_REG_R3, 0)); if (bswap && s_bits == 1) { @@ -1541,23 +1541,17 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0)); } - /* XXX/FIXME: suboptimal */ - tcg_out_bundle(s, mII, - tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58, - mem_index, TCG_REG_R0), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R57, 0, TCG_REG_R56), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R56, 0, TCG_AREG0)); if (!bswap || s_bits == 0) { tcg_out_bundle(s, miB, - tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), + tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58, + mem_index, TCG_REG_R0), tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5, TCG_REG_B0, TCG_REG_B6)); } else { tcg_out_bundle(s, miB, - tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), + tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58, + mem_index, TCG_REG_R0), tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3, TCG_REG_R8, TCG_REG_R8, 0xb), tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5, @@ -1609,8 +1603,8 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) /* P6 is the fast path, and P7 the slow path */ tcg_out_bundle(s, mLX, - tcg_opc_a4(TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R57, - 0, data_reg), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, + TCG_REG_R56, 0, TCG_AREG0), tcg_opc_l2 ((tcg_target_long) qemu_st_helpers[opc]), tcg_opc_x2 (TCG_REG_P7, OPC_MOVL_X2, TCG_REG_R2, (tcg_target_long) qemu_st_helpers[opc])); @@ -1618,31 +1612,42 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) tcg_opc_m3 (TCG_REG_P0, OPC_LD8_M3, TCG_REG_R3, TCG_REG_R2, 8), tcg_opc_a1 (TCG_REG_P6, OPC_ADD_A1, TCG_REG_R3, - TCG_REG_R3, TCG_REG_R56), + TCG_REG_R3, TCG_REG_R57), tcg_opc_i21(TCG_REG_P7, OPC_MOV_I21, TCG_REG_B6, TCG_REG_R3, 0)); if (!bswap || opc == 0) { - tcg_out_bundle(s, mII, + tcg_out_bundle(s, mii, + tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, + TCG_REG_R1, TCG_REG_R2), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R58, + 0, data_reg), + tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0)); + } else if (opc == 1) { + tcg_out_bundle(s, miI, tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), - tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0)); - } else if (opc == 1) { - tcg_out_bundle(s, mII, - tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, - TCG_REG_R1, TCG_REG_R2), tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12, - TCG_REG_R2, data_reg, 15, 15), + TCG_REG_R2, data_reg, 15, 15)); + tcg_out_bundle(s, miI, + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R58, + 0, data_reg), + tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3, TCG_REG_R2, TCG_REG_R2, 0xb)); data_reg = TCG_REG_R2; } else if (opc == 2) { - tcg_out_bundle(s, mII, + tcg_out_bundle(s, miI, tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), + tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_i12(TCG_REG_P6, OPC_DEP_Z_I12, - TCG_REG_R2, data_reg, 31, 31), + TCG_REG_R2, data_reg, 31, 31)); + tcg_out_bundle(s, miI, + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R58, + 0, data_reg), + tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3, TCG_REG_R2, TCG_REG_R2, 0xb)); data_reg = TCG_REG_R2; @@ -1650,25 +1655,18 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) tcg_out_bundle(s, miI, tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), - tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, TCG_REG_R58, + 0, data_reg), tcg_opc_i3 (TCG_REG_P6, OPC_MUX1_I3, TCG_REG_R2, data_reg, 0xb)); data_reg = TCG_REG_R2; } - /* XXX/FIXME: suboptimal */ - tcg_out_bundle(s, mII, - tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R59, - mem_index, TCG_REG_R0), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R58, 0, TCG_REG_R57), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R57, 0, TCG_REG_R56)); tcg_out_bundle(s, miB, tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc], data_reg, TCG_REG_R3), - tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, - TCG_REG_R56, 0, TCG_AREG0), + tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R59, + mem_index, TCG_REG_R0), tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5, TCG_REG_B0, TCG_REG_B6)); } From 63975ea7dfb3ec258433c782c2455bf64fab5e49 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 9 Oct 2012 21:53:55 +0200 Subject: [PATCH 030/160] tcg/ia64: slightly optimize TLB access code It is possible to slightly optimize the TLB access code, by replacing the movi + and instructions by a deposit instruction. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/ia64/tcg-target.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 16edc1b85a..6f018f4c67 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -230,6 +230,7 @@ enum { OPC_CMP4_LT_A6 = 0x18400000000ull, OPC_CMP4_LTU_A6 = 0x1a400000000ull, OPC_CMP4_EQ_A6 = 0x1c400000000ull, + OPC_DEP_I14 = 0x0ae00000000ull, OPC_DEP_Z_I12 = 0x0a600000000ull, OPC_EXTR_I11 = 0x0a400002000ull, OPC_EXTR_U_I11 = 0x0a400000000ull, @@ -501,6 +502,18 @@ static inline uint64_t tcg_opc_i12(int qp, uint64_t opc, int r1, | (qp & 0x3f); } +static inline uint64_t tcg_opc_i14(int qp, uint64_t opc, int r1, uint64_t imm, + int r3, uint64_t pos, uint64_t len) +{ + return opc + | ((imm & 0x01) << 36) + | ((len & 0x3f) << 27) + | ((r3 & 0x7f) << 20) + | ((pos & 0x3f) << 14) + | ((r1 & 0x7f) << 6) + | (qp & 0x3f); +} + static inline uint64_t tcg_opc_i18(int qp, uint64_t opc, uint64_t imm) { return opc @@ -1444,9 +1457,7 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, uint64_t offset_addend) { tcg_out_bundle(s, mII, - tcg_opc_a5 (TCG_REG_P0, OPC_ADDL_A5, TCG_REG_R3, - TARGET_PAGE_MASK | ((1 << s_bits) - 1), - TCG_REG_R0), + tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), tcg_opc_i11(TCG_REG_P0, OPC_EXTR_U_I11, TCG_REG_R2, addr_reg, TARGET_PAGE_BITS, CPU_TLB_BITS - 1), tcg_opc_i12(TCG_REG_P0, OPC_DEP_Z_I12, TCG_REG_R2, @@ -1468,8 +1479,9 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, (TARGET_LONG_BITS == 32 ? OPC_LD4_M3 : OPC_LD8_M3), TCG_REG_R56, TCG_REG_R2, offset_addend - offset_rw), - tcg_opc_a1 (TCG_REG_P0, OPC_AND_A1, TCG_REG_R3, - TCG_REG_R3, TCG_REG_R57), + tcg_opc_i14(TCG_REG_P0, OPC_DEP_I14, TCG_REG_R3, 0, + TCG_REG_R57, 63 - s_bits, + TARGET_PAGE_BITS - s_bits - 1), tcg_opc_a6 (TCG_REG_P0, OPC_CMP_EQ_A6, TCG_REG_P6, TCG_REG_P7, TCG_REG_R3, TCG_REG_R56)); } From c7d4475a701c61f964a593d6fe81a8ea7a33add7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 10 Oct 2012 16:01:35 -0700 Subject: [PATCH 031/160] tcg-ia64: Implement deposit Note that in the general reg=reg,reg case we're restricted to 16-bit insertions. This makes it easy to allow "any" constant as input, as post-truncation it will fit into the constant load insn for which we have room in the bundle. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/ia64/tcg-target.c | 53 +++++++++++++++++++++++++++++++++++++++++++ tcg/ia64/tcg-target.h | 7 ++++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index 6f018f4c67..06570bea38 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -231,6 +231,7 @@ enum { OPC_CMP4_LTU_A6 = 0x1a400000000ull, OPC_CMP4_EQ_A6 = 0x1c400000000ull, OPC_DEP_I14 = 0x0ae00000000ull, + OPC_DEP_I15 = 0x08000000000ull, OPC_DEP_Z_I12 = 0x0a600000000ull, OPC_EXTR_I11 = 0x0a400002000ull, OPC_EXTR_U_I11 = 0x0a400000000ull, @@ -514,6 +515,18 @@ static inline uint64_t tcg_opc_i14(int qp, uint64_t opc, int r1, uint64_t imm, | (qp & 0x3f); } +static inline uint64_t tcg_opc_i15(int qp, uint64_t opc, int r1, int r2, + int r3, uint64_t pos, uint64_t len) +{ + return opc + | ((pos & 0x3f) << 31) + | ((len & 0x0f) << 27) + | ((r3 & 0x7f) << 20) + | ((r2 & 0x7f) << 13) + | ((r1 & 0x7f) << 6) + | (qp & 0x3f); +} + static inline uint64_t tcg_opc_i18(int qp, uint64_t opc, uint64_t imm) { return opc @@ -1325,6 +1338,37 @@ static inline void tcg_out_bswap64(TCGContext *s, TCGArg ret, TCGArg arg) tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, arg, 0xb)); } +static inline void tcg_out_deposit(TCGContext *s, TCGArg ret, TCGArg a1, + TCGArg a2, int const_a2, int pos, int len) +{ + uint64_t i1 = 0, i2 = 0; + int cpos = 63 - pos, lm1 = len - 1; + + if (const_a2) { + /* Truncate the value of a constant a2 to the width of the field. */ + int mask = (1u << len) - 1; + a2 &= mask; + + if (a2 == 0 || a2 == mask) { + /* 1-bit signed constant inserted into register. */ + i2 = tcg_opc_i14(TCG_REG_P0, OPC_DEP_I14, ret, a2, a1, cpos, lm1); + } else { + /* Otherwise, load any constant into a temporary. Do this into + the first I slot to help out with cross-unit delays. */ + i1 = tcg_opc_a5(TCG_REG_P0, OPC_ADDL_A5, + TCG_REG_R2, a2, TCG_REG_R0); + a2 = TCG_REG_R2; + } + } + if (i2 == 0) { + i2 = tcg_opc_i15(TCG_REG_P0, OPC_DEP_I15, ret, a2, a1, cpos, lm1); + } + tcg_out_bundle(s, (i1 ? mII : miI), + tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), + i1 ? i1 : tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0), + i2); +} + static inline uint64_t tcg_opc_cmp_a(int qp, TCGCond cond, TCGArg arg1, TCGArg arg2, int cmp4) { @@ -2130,6 +2174,12 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_bswap64(s, args[0], args[1]); break; + case INDEX_op_deposit_i32: + case INDEX_op_deposit_i64: + tcg_out_deposit(s, args[0], args[1], args[2], const_args[2], + args[3], args[4]); + break; + case INDEX_op_brcond_i32: tcg_out_brcond(s, args[2], args[0], const_args[0], args[1], const_args[1], args[3], 1); @@ -2294,6 +2344,9 @@ static const TCGTargetOpDef ia64_op_defs[] = { { INDEX_op_setcond_i64, { "r", "rZ", "rZ" } }, { INDEX_op_movcond_i64, { "r", "rZ", "rZ", "rI", "rI" } }, + { INDEX_op_deposit_i32, { "r", "rZ", "ri" } }, + { INDEX_op_deposit_i64, { "r", "rZ", "ri" } }, + { INDEX_op_qemu_ld8u, { "r", "r" } }, { INDEX_op_qemu_ld8s, { "r", "r" } }, { INDEX_op_qemu_ld16u, { "r", "r" } }, diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index 5e7d970982..4255ca5225 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -133,8 +133,11 @@ typedef enum { #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_movcond_i32 1 #define TCG_TARGET_HAS_movcond_i64 1 -#define TCG_TARGET_HAS_deposit_i32 0 -#define TCG_TARGET_HAS_deposit_i64 0 +#define TCG_TARGET_HAS_deposit_i32 1 +#define TCG_TARGET_HAS_deposit_i64 1 + +#define TCG_TARGET_deposit_i32_valid(ofs, len) ((len) <= 16) +#define TCG_TARGET_deposit_i64_valid(ofs, len) ((len) <= 16) /* optional instructions automatically implemented */ #define TCG_TARGET_HAS_neg_i32 0 /* sub r1, r0, r3 */ From 81bad50ec40311797c38a7691844c7d2df9b3823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 12 Oct 2012 00:56:33 +0200 Subject: [PATCH 032/160] target-mips: Clean up other_cpu in helper_{d,e}vpe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Free the variable name "other_cpu" for later use for MIPSCPU. Fix off-by-one indentation while at it. Signed-off-by: Andreas Färber Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index ce5ddaf050..1051c44217 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1874,35 +1874,35 @@ target_ulong helper_emt(void) target_ulong helper_dvpe(CPUMIPSState *env) { - CPUMIPSState *other_cpu = first_cpu; + CPUMIPSState *other_cpu_env = first_cpu; target_ulong prev = env->mvp->CP0_MVPControl; do { /* Turn off all VPEs except the one executing the dvpe. */ - if (other_cpu != env) { - other_cpu->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP); - mips_vpe_sleep(other_cpu); + if (other_cpu_env != env) { + other_cpu_env->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP); + mips_vpe_sleep(other_cpu_env); } - other_cpu = other_cpu->next_cpu; - } while (other_cpu); + other_cpu_env = other_cpu_env->next_cpu; + } while (other_cpu_env); return prev; } target_ulong helper_evpe(CPUMIPSState *env) { - CPUMIPSState *other_cpu = first_cpu; + CPUMIPSState *other_cpu_env = first_cpu; target_ulong prev = env->mvp->CP0_MVPControl; do { - if (other_cpu != env - /* If the VPE is WFI, don't disturb its sleep. */ - && !mips_vpe_is_wfi(other_cpu)) { + if (other_cpu_env != env + /* If the VPE is WFI, don't disturb its sleep. */ + && !mips_vpe_is_wfi(other_cpu_env)) { /* Enable the VPE. */ - other_cpu->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); - mips_vpe_wake(other_cpu); /* And wake it up. */ + other_cpu_env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); + mips_vpe_wake(other_cpu_env); /* And wake it up. */ } - other_cpu = other_cpu->next_cpu; - } while (other_cpu); + other_cpu_env = other_cpu_env->next_cpu; + } while (other_cpu_env); return prev; } #endif /* !CONFIG_USER_ONLY */ From 135dd63a190a084fa5e9f1b4695397016bf0ce5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 12 Oct 2012 00:56:34 +0200 Subject: [PATCH 033/160] target-mips: Pass MIPSCPU to mips_tc_wake() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for changing mips_vpe_is_wfi() argument type to MIPSCPU. Signed-off-by: Andreas Färber Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 1051c44217..e721a4d659 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -737,8 +737,10 @@ static inline void mips_vpe_sleep(CPUMIPSState *c) cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE); } -static inline void mips_tc_wake(CPUMIPSState *c, int tc) +static inline void mips_tc_wake(MIPSCPU *cpu, int tc) { + CPUMIPSState *c = &cpu->env; + /* FIXME: TC reschedule. */ if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) { mips_vpe_wake(c); @@ -1342,13 +1344,15 @@ void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1) { + MIPSCPU *cpu = mips_env_get_cpu(env); + env->active_tc.CP0_TCHalt = arg1 & 0x1; // TODO: Halt TC / Restart (if allocated+active) TC. if (env->active_tc.CP0_TCHalt & 1) { mips_tc_sleep(env, env->current_tc); } else { - mips_tc_wake(env, env->current_tc); + mips_tc_wake(cpu, env->current_tc); } } @@ -1356,6 +1360,7 @@ void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + MIPSCPU *other_cpu = mips_env_get_cpu(other); // TODO: Halt TC / Restart (if allocated+active) TC. @@ -1367,7 +1372,7 @@ void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1) if (arg1 & 1) { mips_tc_sleep(other, other_tc); } else { - mips_tc_wake(other, other_tc); + mips_tc_wake(other_cpu, other_tc); } } From b35d77d73c0fc0b60c9937471a17d41c6fb32947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 12 Oct 2012 00:56:35 +0200 Subject: [PATCH 034/160] target-mips: Pass MIPSCPU to mips_vpe_is_wfi() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for moving halted field to CPUState. The variable name "c" is retained for MIPSCPU to leave "cpu" for CPUState. Also change return type to bool while at it. Signed-off-by: Andreas Färber Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index e721a4d659..9770741cd3 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -714,11 +714,13 @@ void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, #ifndef CONFIG_USER_ONLY /* SMP helpers. */ -static int mips_vpe_is_wfi(CPUMIPSState *c) +static bool mips_vpe_is_wfi(MIPSCPU *c) { + CPUMIPSState *env = &c->env; + /* If the VPE is halted but otherwise active, it means it's waiting for an interrupt. */ - return c->halted && mips_vpe_active(c); + return env->halted && mips_vpe_active(env); } static inline void mips_vpe_wake(CPUMIPSState *c) @@ -742,7 +744,7 @@ static inline void mips_tc_wake(MIPSCPU *cpu, int tc) CPUMIPSState *c = &cpu->env; /* FIXME: TC reschedule. */ - if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) { + if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) { mips_vpe_wake(c); } } @@ -1899,9 +1901,11 @@ target_ulong helper_evpe(CPUMIPSState *env) target_ulong prev = env->mvp->CP0_MVPControl; do { + MIPSCPU *other_cpu = mips_env_get_cpu(other_cpu_env); + if (other_cpu_env != env /* If the VPE is WFI, don't disturb its sleep. */ - && !mips_vpe_is_wfi(other_cpu_env)) { + && !mips_vpe_is_wfi(other_cpu)) { /* Enable the VPE. */ other_cpu_env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); mips_vpe_wake(other_cpu_env); /* And wake it up. */ From c6679e9038027e28b0360039d2bb7d3aa55b934e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 12 Oct 2012 00:56:36 +0200 Subject: [PATCH 035/160] target-mips: Pass MIPSCPU to mips_tc_sleep() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for changing mips_vpe_sleep() argument type to MIPSCPU. Signed-off-by: Andreas Färber Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9770741cd3..5710dd08df 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -749,8 +749,10 @@ static inline void mips_tc_wake(MIPSCPU *cpu, int tc) } } -static inline void mips_tc_sleep(CPUMIPSState *c, int tc) +static inline void mips_tc_sleep(MIPSCPU *cpu, int tc) { + CPUMIPSState *c = &cpu->env; + /* FIXME: TC reschedule. */ if (!mips_vpe_active(c)) { mips_vpe_sleep(c); @@ -1352,7 +1354,7 @@ void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1) // TODO: Halt TC / Restart (if allocated+active) TC. if (env->active_tc.CP0_TCHalt & 1) { - mips_tc_sleep(env, env->current_tc); + mips_tc_sleep(cpu, env->current_tc); } else { mips_tc_wake(cpu, env->current_tc); } @@ -1372,7 +1374,7 @@ void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1) other->tcs[other_tc].CP0_TCHalt = arg1; if (arg1 & 1) { - mips_tc_sleep(other, other_tc); + mips_tc_sleep(other_cpu, other_tc); } else { mips_tc_wake(other_cpu, other_tc); } From 6f4d6b09088ee161ff4be0e4db4e4c0962c79070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 12 Oct 2012 00:56:37 +0200 Subject: [PATCH 036/160] target-mips: Pass MIPSCPU to mips_vpe_sleep() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for moving halted field to CPUState. Signed-off-by: Andreas Färber Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 5710dd08df..05b7730987 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -731,8 +731,10 @@ static inline void mips_vpe_wake(CPUMIPSState *c) cpu_interrupt(c, CPU_INTERRUPT_WAKE); } -static inline void mips_vpe_sleep(CPUMIPSState *c) +static inline void mips_vpe_sleep(MIPSCPU *cpu) { + CPUMIPSState *c = &cpu->env; + /* The VPE was shut off, really go to bed. Reset any old _WAKE requests. */ c->halted = 1; @@ -755,7 +757,7 @@ static inline void mips_tc_sleep(MIPSCPU *cpu, int tc) /* FIXME: TC reschedule. */ if (!mips_vpe_active(c)) { - mips_vpe_sleep(c); + mips_vpe_sleep(cpu); } } @@ -1889,8 +1891,10 @@ target_ulong helper_dvpe(CPUMIPSState *env) do { /* Turn off all VPEs except the one executing the dvpe. */ if (other_cpu_env != env) { + MIPSCPU *other_cpu = mips_env_get_cpu(other_cpu_env); + other_cpu_env->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP); - mips_vpe_sleep(other_cpu_env); + mips_vpe_sleep(other_cpu); } other_cpu_env = other_cpu_env->next_cpu; } while (other_cpu_env); From 24c9ae4eba5eec59256d0d0ace4d868a19f87528 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:21 -0700 Subject: [PATCH 037/160] tcg: Split out swap_commutative as a subroutine Reduces code duplication and prefers movcond d, c1, c2, const, s to movcond d, c1, c2, s, const It also prefers add r, r, c over add r, c, r when both inputs are known constants. This doesn't matter for true add, as we will fully constant fold that. But it matters for a follow-on patch using this routine for add2 which may not be fully foldable. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 56 ++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index edb2b0ea90..ff4ddb2efc 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -388,6 +388,23 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, tcg_abort(); } +static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) +{ + TCGArg a1 = *p1, a2 = *p2; + int sum = 0; + sum += temps[a1].state == TCG_TEMP_CONST; + sum -= temps[a2].state == TCG_TEMP_CONST; + + /* Prefer the constant in second argument, and then the form + op a, a, b, which is better handled on non-RISC hosts. */ + if (sum > 0 || (sum == 0 && dest == a2)) { + *p1 = a2; + *p2 = a1; + return true; + } + return false; +} + /* Propagate constants and copies, fold constant expressions. */ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args, TCGOpDef *tcg_op_defs) @@ -397,7 +414,6 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, const TCGOpDef *def; TCGArg *gen_args; TCGArg tmp; - TCGCond cond; /* Array VALS has an element for each temp. If this temp holds a constant then its value is kept in VALS' element. @@ -440,52 +456,28 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, CASE_OP_32_64(eqv): CASE_OP_32_64(nand): CASE_OP_32_64(nor): - /* Prefer the constant in second argument, and then the form - op a, a, b, which is better handled on non-RISC hosts. */ - if (temps[args[1]].state == TCG_TEMP_CONST || (args[0] == args[2] - && temps[args[2]].state != TCG_TEMP_CONST)) { - tmp = args[1]; - args[1] = args[2]; - args[2] = tmp; - } + swap_commutative(args[0], &args[1], &args[2]); break; CASE_OP_32_64(brcond): - if (temps[args[0]].state == TCG_TEMP_CONST - && temps[args[1]].state != TCG_TEMP_CONST) { - tmp = args[0]; - args[0] = args[1]; - args[1] = tmp; + if (swap_commutative(-1, &args[0], &args[1])) { args[2] = tcg_swap_cond(args[2]); } break; CASE_OP_32_64(setcond): - if (temps[args[1]].state == TCG_TEMP_CONST - && temps[args[2]].state != TCG_TEMP_CONST) { - tmp = args[1]; - args[1] = args[2]; - args[2] = tmp; + if (swap_commutative(args[0], &args[1], &args[2])) { args[3] = tcg_swap_cond(args[3]); } break; CASE_OP_32_64(movcond): - cond = args[5]; - if (temps[args[1]].state == TCG_TEMP_CONST - && temps[args[2]].state != TCG_TEMP_CONST) { - tmp = args[1]; - args[1] = args[2]; - args[2] = tmp; - cond = tcg_swap_cond(cond); + if (swap_commutative(-1, &args[1], &args[2])) { + args[5] = tcg_swap_cond(args[5]); } /* For movcond, we canonicalize the "false" input reg to match the destination reg so that the tcg backend can implement a "move if true" operation. */ - if (args[0] == args[3]) { - tmp = args[3]; - args[3] = args[4]; - args[4] = tmp; - cond = tcg_invert_cond(cond); + if (swap_commutative(args[0], &args[4], &args[3])) { + args[5] = tcg_invert_cond(args[5]); } - args[5] = cond; default: break; } From 1e484e61e2d9387c18a40e9e239b304003f5d183 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:22 -0700 Subject: [PATCH 038/160] tcg: Canonicalize add2 operand ordering Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index ff4ddb2efc..8d74186ab3 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -478,6 +478,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, if (swap_commutative(args[0], &args[4], &args[3])) { args[5] = tcg_invert_cond(args[5]); } + break; + case INDEX_op_add2_i32: + swap_commutative(args[0], &args[2], &args[4]); + swap_commutative(args[1], &args[3], &args[5]); + break; default: break; } From 0bfcb86538d0bcffa3ef5434810f91aa861431ce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:23 -0700 Subject: [PATCH 039/160] tcg: Swap commutative double-word comparisons Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index 8d74186ab3..9ecea7085a 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -405,6 +405,22 @@ static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) return false; } +static bool swap_commutative2(TCGArg *p1, TCGArg *p2) +{ + int sum = 0; + sum += temps[p1[0]].state == TCG_TEMP_CONST; + sum += temps[p1[1]].state == TCG_TEMP_CONST; + sum -= temps[p2[0]].state == TCG_TEMP_CONST; + sum -= temps[p2[1]].state == TCG_TEMP_CONST; + if (sum > 0) { + TCGArg t; + t = p1[0], p1[0] = p2[0], p2[0] = t; + t = p1[1], p1[1] = p2[1], p2[1] = t; + return true; + } + return false; +} + /* Propagate constants and copies, fold constant expressions. */ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args, TCGOpDef *tcg_op_defs) @@ -483,6 +499,16 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, swap_commutative(args[0], &args[2], &args[4]); swap_commutative(args[1], &args[3], &args[5]); break; + case INDEX_op_brcond2_i32: + if (swap_commutative2(&args[0], &args[2])) { + args[4] = tcg_swap_cond(args[4]); + } + break; + case INDEX_op_setcond2_i32: + if (swap_commutative2(&args[1], &args[3])) { + args[5] = tcg_swap_cond(args[5]); + } + break; default: break; } From 6e14e91b6681dac9614b7b09b561351813046193 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:24 -0700 Subject: [PATCH 040/160] tcg: Use common code when failing to optimize This saves a whole lot of repetitive code sequences. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 91 ++++++++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 59 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 9ecea7085a..0fd7db3654 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -645,6 +645,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, gen_args += 2; args += 2; break; + CASE_OP_32_64(not): CASE_OP_32_64(neg): CASE_OP_32_64(ext8s): @@ -657,14 +658,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, gen_opc_buf[op_index] = op_to_movi(op); tmp = do_constant_folding(op, temps[args[1]].val, 0); tcg_opt_gen_movi(gen_args, args[0], tmp); - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; + gen_args += 2; + args += 2; + break; } - gen_args += 2; - args += 2; - break; + goto do_default; + CASE_OP_32_64(add): CASE_OP_32_64(sub): CASE_OP_32_64(mul): @@ -688,15 +687,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, temps[args[2]].val); tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args += 3; + args += 3; + break; } - args += 3; - break; + goto do_default; + CASE_OP_32_64(deposit): if (temps[args[1]].state == TCG_TEMP_CONST && temps[args[2]].state == TCG_TEMP_CONST) { @@ -706,33 +701,22 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, | ((temps[args[2]].val & tmp) << args[3]); tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args[3] = args[3]; - gen_args[4] = args[4]; - gen_args += 5; + args += 5; + break; } - args += 5; - break; + goto do_default; + CASE_OP_32_64(setcond): tmp = do_constant_folding_cond(op, args[1], args[2], args[3]); if (tmp != 2) { gen_opc_buf[op_index] = op_to_movi(op); tcg_opt_gen_movi(gen_args, args[0], tmp); gen_args += 2; - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args[3] = args[3]; - gen_args += 4; + args += 4; + break; } - args += 4; - break; + goto do_default; + CASE_OP_32_64(brcond): tmp = do_constant_folding_cond(op, args[0], args[1], args[2]); if (tmp != 2) { @@ -744,17 +728,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, } else { gen_opc_buf[op_index] = INDEX_op_nop; } - } else { - memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args[3] = args[3]; - gen_args += 4; + args += 4; + break; } - args += 4; - break; + goto do_default; + CASE_OP_32_64(movcond): tmp = do_constant_folding_cond(op, args[1], args[2], args[5]); if (tmp != 2) { @@ -769,18 +747,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]); gen_args += 2; } - } else { - reset_temp(args[0]); - gen_args[0] = args[0]; - gen_args[1] = args[1]; - gen_args[2] = args[2]; - gen_args[3] = args[3]; - gen_args[4] = args[4]; - gen_args[5] = args[5]; - gen_args += 6; + args += 6; + break; } - args += 6; - break; + goto do_default; + case INDEX_op_call: nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) { @@ -799,11 +770,13 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, i--; } break; + default: - /* Default case: we do know nothing about operation so no - propagation is done. We trash everything if the operation - is the end of a basic block, otherwise we only trash the - output args. */ + do_default: + /* Default case: we know nothing about operation (or were unable + to compute the operation result) so no propagation is done. + We trash everything if the operation is the end of a basic + block, otherwise we only trash the output args. */ if (def->flags & TCG_OPF_BB_END) { memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); } else { From bc1473eff4d9a3b62d669b7232383f85eb82b376 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:25 -0700 Subject: [PATCH 041/160] tcg: Optimize double-word comparisons against zero Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index 0fd7db3654..0a55352870 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -752,6 +752,45 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, } goto do_default; + case INDEX_op_brcond2_i32: + /* Simplify LT/GE comparisons vs zero to a single compare + vs the high word of the input. */ + if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) + && temps[args[2]].state == TCG_TEMP_CONST + && temps[args[3]].state == TCG_TEMP_CONST + && temps[args[2]].val == 0 + && temps[args[3]].val == 0) { + gen_opc_buf[op_index] = INDEX_op_brcond_i32; + gen_args[0] = args[1]; + gen_args[1] = args[3]; + gen_args[2] = args[4]; + gen_args[3] = args[5]; + gen_args += 4; + args += 6; + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + break; + } + goto do_default; + + case INDEX_op_setcond2_i32: + /* Simplify LT/GE comparisons vs zero to a single compare + vs the high word of the input. */ + if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) + && temps[args[3]].state == TCG_TEMP_CONST + && temps[args[4]].state == TCG_TEMP_CONST + && temps[args[3]].val == 0 + && temps[args[4]].val == 0) { + gen_opc_buf[op_index] = INDEX_op_setcond_i32; + gen_args[0] = args[0]; + gen_args[1] = args[2]; + gen_args[2] = args[4]; + gen_args[3] = args[5]; + gen_args += 4; + args += 6; + break; + } + goto do_default; + case INDEX_op_call: nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) { From 9519da7e39516c5cb5bd7146a849a5d8c0958105 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:26 -0700 Subject: [PATCH 042/160] tcg: Split out subroutines from do_constant_folding_cond We can re-use these for implementing double-word folding. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 152 ++++++++++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 71 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 0a55352870..38027dc5ad 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -292,6 +292,82 @@ static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y) return res; } +static bool do_constant_folding_cond_32(uint32_t x, uint32_t y, TCGCond c) +{ + switch (c) { + case TCG_COND_EQ: + return x == y; + case TCG_COND_NE: + return x != y; + case TCG_COND_LT: + return (int32_t)x < (int32_t)y; + case TCG_COND_GE: + return (int32_t)x >= (int32_t)y; + case TCG_COND_LE: + return (int32_t)x <= (int32_t)y; + case TCG_COND_GT: + return (int32_t)x > (int32_t)y; + case TCG_COND_LTU: + return x < y; + case TCG_COND_GEU: + return x >= y; + case TCG_COND_LEU: + return x <= y; + case TCG_COND_GTU: + return x > y; + default: + tcg_abort(); + } +} + +static bool do_constant_folding_cond_64(uint64_t x, uint64_t y, TCGCond c) +{ + switch (c) { + case TCG_COND_EQ: + return x == y; + case TCG_COND_NE: + return x != y; + case TCG_COND_LT: + return (int64_t)x < (int64_t)y; + case TCG_COND_GE: + return (int64_t)x >= (int64_t)y; + case TCG_COND_LE: + return (int64_t)x <= (int64_t)y; + case TCG_COND_GT: + return (int64_t)x > (int64_t)y; + case TCG_COND_LTU: + return x < y; + case TCG_COND_GEU: + return x >= y; + case TCG_COND_LEU: + return x <= y; + case TCG_COND_GTU: + return x > y; + default: + tcg_abort(); + } +} + +static bool do_constant_folding_cond_eq(TCGCond c) +{ + switch (c) { + case TCG_COND_GT: + case TCG_COND_LTU: + case TCG_COND_LT: + case TCG_COND_GTU: + case TCG_COND_NE: + return 0; + case TCG_COND_GE: + case TCG_COND_GEU: + case TCG_COND_LE: + case TCG_COND_LEU: + case TCG_COND_EQ: + return 1; + default: + tcg_abort(); + } +} + /* Return 2 if the condition can't be simplified, and the result of the condition (0 or 1) if it can */ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, @@ -300,75 +376,14 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, if (temps[x].state == TCG_TEMP_CONST && temps[y].state == TCG_TEMP_CONST) { switch (op_bits(op)) { case 32: - switch (c) { - case TCG_COND_EQ: - return (uint32_t)temps[x].val == (uint32_t)temps[y].val; - case TCG_COND_NE: - return (uint32_t)temps[x].val != (uint32_t)temps[y].val; - case TCG_COND_LT: - return (int32_t)temps[x].val < (int32_t)temps[y].val; - case TCG_COND_GE: - return (int32_t)temps[x].val >= (int32_t)temps[y].val; - case TCG_COND_LE: - return (int32_t)temps[x].val <= (int32_t)temps[y].val; - case TCG_COND_GT: - return (int32_t)temps[x].val > (int32_t)temps[y].val; - case TCG_COND_LTU: - return (uint32_t)temps[x].val < (uint32_t)temps[y].val; - case TCG_COND_GEU: - return (uint32_t)temps[x].val >= (uint32_t)temps[y].val; - case TCG_COND_LEU: - return (uint32_t)temps[x].val <= (uint32_t)temps[y].val; - case TCG_COND_GTU: - return (uint32_t)temps[x].val > (uint32_t)temps[y].val; - default: - break; - } - break; + return do_constant_folding_cond_32(temps[x].val, temps[y].val, c); case 64: - switch (c) { - case TCG_COND_EQ: - return (uint64_t)temps[x].val == (uint64_t)temps[y].val; - case TCG_COND_NE: - return (uint64_t)temps[x].val != (uint64_t)temps[y].val; - case TCG_COND_LT: - return (int64_t)temps[x].val < (int64_t)temps[y].val; - case TCG_COND_GE: - return (int64_t)temps[x].val >= (int64_t)temps[y].val; - case TCG_COND_LE: - return (int64_t)temps[x].val <= (int64_t)temps[y].val; - case TCG_COND_GT: - return (int64_t)temps[x].val > (int64_t)temps[y].val; - case TCG_COND_LTU: - return (uint64_t)temps[x].val < (uint64_t)temps[y].val; - case TCG_COND_GEU: - return (uint64_t)temps[x].val >= (uint64_t)temps[y].val; - case TCG_COND_LEU: - return (uint64_t)temps[x].val <= (uint64_t)temps[y].val; - case TCG_COND_GTU: - return (uint64_t)temps[x].val > (uint64_t)temps[y].val; - default: - break; - } - break; + return do_constant_folding_cond_64(temps[x].val, temps[y].val, c); + default: + tcg_abort(); } } else if (temps_are_copies(x, y)) { - switch (c) { - case TCG_COND_GT: - case TCG_COND_LTU: - case TCG_COND_LT: - case TCG_COND_GTU: - case TCG_COND_NE: - return 0; - case TCG_COND_GE: - case TCG_COND_GEU: - case TCG_COND_LE: - case TCG_COND_LEU: - case TCG_COND_EQ: - return 1; - default: - break; - } + return do_constant_folding_cond_eq(c); } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) { switch (c) { case TCG_COND_LTU: @@ -381,11 +396,6 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, } else { return 2; } - - fprintf(stderr, - "Unrecognized bitness %d or condition %d in " - "do_constant_folding_cond.\n", op_bits(op), c); - tcg_abort(); } static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) From 6c4382f8f47d12eec24c7c5335141a9c78104016 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:27 -0700 Subject: [PATCH 043/160] tcg: Do constant folding on double-word comparisons Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 93 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 38027dc5ad..d9251e4677 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -398,6 +398,40 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, } } +/* Return 2 if the condition can't be simplified, and the result + of the condition (0 or 1) if it can */ +static TCGArg do_constant_folding_cond2(TCGArg *p1, TCGArg *p2, TCGCond c) +{ + TCGArg al = p1[0], ah = p1[1]; + TCGArg bl = p2[0], bh = p2[1]; + + if (temps[bl].state == TCG_TEMP_CONST + && temps[bh].state == TCG_TEMP_CONST) { + uint64_t b = ((uint64_t)temps[bh].val << 32) | (uint32_t)temps[bl].val; + + if (temps[al].state == TCG_TEMP_CONST + && temps[ah].state == TCG_TEMP_CONST) { + uint64_t a; + a = ((uint64_t)temps[ah].val << 32) | (uint32_t)temps[al].val; + return do_constant_folding_cond_64(a, b, c); + } + if (b == 0) { + switch (c) { + case TCG_COND_LTU: + return 0; + case TCG_COND_GEU: + return 1; + default: + break; + } + } + } + if (temps_are_copies(al, bl) && temps_are_copies(ah, bh)) { + return do_constant_folding_cond_eq(c); + } + return 2; +} + static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) { TCGArg a1 = *p1, a2 = *p2; @@ -763,43 +797,60 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, goto do_default; case INDEX_op_brcond2_i32: - /* Simplify LT/GE comparisons vs zero to a single compare - vs the high word of the input. */ - if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) - && temps[args[2]].state == TCG_TEMP_CONST - && temps[args[3]].state == TCG_TEMP_CONST - && temps[args[2]].val == 0 - && temps[args[3]].val == 0) { + tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]); + if (tmp != 2) { + if (tmp) { + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + gen_opc_buf[op_index] = INDEX_op_br; + gen_args[0] = args[5]; + gen_args += 1; + } else { + gen_opc_buf[op_index] = INDEX_op_nop; + } + } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE) + && temps[args[2]].state == TCG_TEMP_CONST + && temps[args[3]].state == TCG_TEMP_CONST + && temps[args[2]].val == 0 + && temps[args[3]].val == 0) { + /* Simplify LT/GE comparisons vs zero to a single compare + vs the high word of the input. */ + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); gen_opc_buf[op_index] = INDEX_op_brcond_i32; gen_args[0] = args[1]; gen_args[1] = args[3]; gen_args[2] = args[4]; gen_args[3] = args[5]; gen_args += 4; - args += 6; - memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); - break; + } else { + goto do_default; } - goto do_default; + args += 6; + break; case INDEX_op_setcond2_i32: - /* Simplify LT/GE comparisons vs zero to a single compare - vs the high word of the input. */ - if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) - && temps[args[3]].state == TCG_TEMP_CONST - && temps[args[4]].state == TCG_TEMP_CONST - && temps[args[3]].val == 0 - && temps[args[4]].val == 0) { + tmp = do_constant_folding_cond2(&args[1], &args[3], args[5]); + if (tmp != 2) { + gen_opc_buf[op_index] = INDEX_op_movi_i32; + tcg_opt_gen_movi(gen_args, args[0], tmp); + gen_args += 2; + } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE) + && temps[args[3]].state == TCG_TEMP_CONST + && temps[args[4]].state == TCG_TEMP_CONST + && temps[args[3]].val == 0 + && temps[args[4]].val == 0) { + /* Simplify LT/GE comparisons vs zero to a single compare + vs the high word of the input. */ gen_opc_buf[op_index] = INDEX_op_setcond_i32; gen_args[0] = args[0]; gen_args[1] = args[2]; gen_args[2] = args[4]; gen_args[3] = args[5]; gen_args += 4; - args += 6; - break; + } else { + goto do_default; } - goto do_default; + args += 6; + break; case INDEX_op_call: nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); From 212c328d615f6750659d39c6fd544d05be314fa1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:28 -0700 Subject: [PATCH 044/160] tcg: Constant fold add2 and sub2 Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 35 +++++++++++++++++++++++++++++++++++ tcg/tcg-op.h | 9 +++++++++ 2 files changed, 44 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index d9251e4677..05891ef380 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -796,6 +796,41 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, } goto do_default; + case INDEX_op_add2_i32: + case INDEX_op_sub2_i32: + if (temps[args[2]].state == TCG_TEMP_CONST + && temps[args[3]].state == TCG_TEMP_CONST + && temps[args[4]].state == TCG_TEMP_CONST + && temps[args[5]].state == TCG_TEMP_CONST) { + uint32_t al = temps[args[2]].val; + uint32_t ah = temps[args[3]].val; + uint32_t bl = temps[args[4]].val; + uint32_t bh = temps[args[5]].val; + uint64_t a = ((uint64_t)ah << 32) | al; + uint64_t b = ((uint64_t)bh << 32) | bl; + TCGArg rl, rh; + + if (op == INDEX_op_add2_i32) { + a += b; + } else { + a -= b; + } + + /* We emit the extra nop when we emit the add2/sub2. */ + assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + + rl = args[0]; + rh = args[1]; + gen_opc_buf[op_index] = INDEX_op_movi_i32; + gen_opc_buf[++op_index] = INDEX_op_movi_i32; + tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)a); + tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(a >> 32)); + gen_args += 4; + args += 6; + break; + } + goto do_default; + case INDEX_op_brcond2_i32: tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]); if (tmp != 2) { diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 551845801d..a580cfea07 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -25,6 +25,11 @@ int gen_new_label(void); +static inline void tcg_gen_op0(TCGOpcode opc) +{ + *gen_opc_ptr++ = opc; +} + static inline void tcg_gen_op1_i32(TCGOpcode opc, TCGv_i32 arg1) { *gen_opc_ptr++ = opc; @@ -886,6 +891,8 @@ static inline void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op6_i32(INDEX_op_add2_i32, TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); + /* Allow the optimizer room to replace add2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); } static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) @@ -893,6 +900,8 @@ static inline void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op6_i32(INDEX_op_sub2_i32, TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); + /* Allow the optimizer room to replace sub2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); } static inline void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) From 1305c451e67e3def030720013415103f5e0f5e11 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:29 -0700 Subject: [PATCH 045/160] tcg: Optimize half-dead add2/sub2 When x86_64 guest is not in 64-bit mode, the high-part of the 64-bit add is dead. When the host is 32-bit, we can simplify to 32-bit arithmetic. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/tcg.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 32cd0c6b65..0eb407b723 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1307,8 +1307,39 @@ static void tcg_liveness_analysis(TCGContext *s) break; case INDEX_op_end: break; - /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ + + case INDEX_op_add2_i32: + case INDEX_op_sub2_i32: + args -= 6; + nb_iargs = 4; + nb_oargs = 2; + /* Test if the high part of the operation is dead, but not + the low part. The result can be optimized to a simple + add or sub. This happens often for x86_64 guest when the + cpu mode is set to 32 bit. */ + if (dead_temps[args[1]]) { + if (dead_temps[args[0]]) { + goto do_remove; + } + /* Create the single operation plus nop. */ + if (op == INDEX_op_add2_i32) { + op = INDEX_op_add_i32; + } else { + op = INDEX_op_sub_i32; + } + gen_opc_buf[op_index] = op; + args[1] = args[2]; + args[2] = args[4]; + assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + tcg_set_nop(s, gen_opc_buf + op_index + 1, args + 3, 3); + /* Fall through and mark the single-word operation live. */ + nb_iargs = 2; + nb_oargs = 1; + } + goto do_not_remove; + default: + /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ args -= def->nb_args; nb_iargs = def->nb_iargs; nb_oargs = def->nb_oargs; @@ -1322,6 +1353,7 @@ static void tcg_liveness_analysis(TCGContext *s) if (!dead_temps[arg]) goto do_not_remove; } + do_remove: tcg_set_nop(s, gen_opc_buf + op_index, args, def->nb_args); #ifdef CONFIG_PROFILER s->del_op_count++; From 1414968a6aecd23cb037bc9e718d6f05ead2afaf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 2 Oct 2012 11:32:30 -0700 Subject: [PATCH 046/160] tcg: Optimize mulu2 Like add2, do operand ordering, constant folding, and dead operand elimination. The latter happens about 15% of all mulu2 during an x86_64 bios boot. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- tcg/optimize.c | 26 ++++++++++++++++++++++++++ tcg/tcg-op.h | 2 ++ tcg/tcg.c | 19 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index 05891ef380..a06c8eb43e 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -543,6 +543,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, swap_commutative(args[0], &args[2], &args[4]); swap_commutative(args[1], &args[3], &args[5]); break; + case INDEX_op_mulu2_i32: + swap_commutative(args[0], &args[2], &args[3]); + break; case INDEX_op_brcond2_i32: if (swap_commutative2(&args[0], &args[2])) { args[4] = tcg_swap_cond(args[4]); @@ -831,6 +834,29 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, } goto do_default; + case INDEX_op_mulu2_i32: + if (temps[args[2]].state == TCG_TEMP_CONST + && temps[args[3]].state == TCG_TEMP_CONST) { + uint32_t a = temps[args[2]].val; + uint32_t b = temps[args[3]].val; + uint64_t r = (uint64_t)a * b; + TCGArg rl, rh; + + /* We emit the extra nop when we emit the mulu2. */ + assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + + rl = args[0]; + rh = args[1]; + gen_opc_buf[op_index] = INDEX_op_movi_i32; + gen_opc_buf[++op_index] = INDEX_op_movi_i32; + tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)r); + tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(r >> 32)); + gen_args += 4; + args += 4; + break; + } + goto do_default; + case INDEX_op_brcond2_i32: tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]); if (tmp != 2) { diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index a580cfea07..8100a5a2e0 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -1027,6 +1027,8 @@ static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op4_i32(INDEX_op_mulu2_i32, TCGV_LOW(t0), TCGV_HIGH(t0), TCGV_LOW(arg1), TCGV_LOW(arg2)); + /* Allow the optimizer room to replace mulu2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); tcg_gen_mul_i32(t1, TCGV_LOW(arg1), TCGV_HIGH(arg2)); tcg_gen_add_i32(TCGV_HIGH(t0), TCGV_HIGH(t0), t1); diff --git a/tcg/tcg.c b/tcg/tcg.c index 0eb407b723..f0deea25b2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1338,6 +1338,25 @@ static void tcg_liveness_analysis(TCGContext *s) } goto do_not_remove; + case INDEX_op_mulu2_i32: + args -= 4; + nb_iargs = 2; + nb_oargs = 2; + /* Likewise, test for the high part of the operation dead. */ + if (dead_temps[args[1]]) { + if (dead_temps[args[0]]) { + goto do_remove; + } + gen_opc_buf[op_index] = op = INDEX_op_mul_i32; + args[1] = args[2]; + args[2] = args[3]; + assert(gen_opc_buf[op_index + 1] == INDEX_op_nop); + tcg_set_nop(s, gen_opc_buf + op_index + 1, args + 3, 1); + /* Fall through and mark the single-word operation live. */ + nb_oargs = 1; + } + goto do_not_remove; + default: /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ args -= def->nb_args; From 05e72dc5812a9f461fc2c606dff2572909eafc39 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 24 Jul 2012 14:14:32 +0200 Subject: [PATCH 047/160] buffered_file: g_realloc() can't fail Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini Reviewed-by: Orit Wasserman --- buffered_file.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index f170aa046f..4148abbee0 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -50,20 +50,12 @@ static void buffered_append(QEMUFileBuffered *s, const uint8_t *buf, size_t size) { if (size > (s->buffer_capacity - s->buffer_size)) { - void *tmp; - DPRINTF("increasing buffer capacity from %zu by %zu\n", s->buffer_capacity, size + 1024); s->buffer_capacity += size + 1024; - tmp = g_realloc(s->buffer, s->buffer_capacity); - if (tmp == NULL) { - fprintf(stderr, "qemu file buffer expansion failed\n"); - exit(1); - } - - s->buffer = tmp; + s->buffer = g_realloc(s->buffer, s->buffer_capacity); } memcpy(s->buffer + s->buffer_size, buf, size); From 79536f4f16934d6759a1d67f0342b4e7ceb66671 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 3 Aug 2012 12:58:16 +0200 Subject: [PATCH 048/160] fix migration sync Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- arch_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch_init.c b/arch_init.c index 9904f95478..671d3545cc 100644 --- a/arch_init.c +++ b/arch_init.c @@ -517,6 +517,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) } memory_global_dirty_log_start(); + memory_global_sync_dirty_bitmap(get_system_memory()); qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE); From 97d4d961d98c1ad54eee657d81e2e50911a92acf Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 10 Aug 2012 21:53:08 +0200 Subject: [PATCH 049/160] migration: store end_time in a local variable Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini Reviewed-by: Orit Wasserman --- migration.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/migration.c b/migration.c index 22a05c437d..7a110264ee 100644 --- a/migration.c +++ b/migration.c @@ -329,6 +329,7 @@ static void migrate_fd_put_ready(void *opaque) migrate_fd_error(s); } else if (ret == 1) { int old_vm_running = runstate_is_running(); + int64_t end_time; DPRINTF("done iterating\n"); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); @@ -339,7 +340,8 @@ static void migrate_fd_put_ready(void *opaque) } else { migrate_fd_completed(s); } - s->total_time = qemu_get_clock_ms(rt_clock) - s->total_time; + end_time = qemu_get_clock_ms(rt_clock); + s->total_time = end_time - s->total_time; if (s->state != MIG_STATE_COMPLETED) { if (old_vm_running) { vm_start(); From 9c5a9fcf5399450a873e7460b397a89447c7ef11 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 13 Aug 2012 09:35:16 +0200 Subject: [PATCH 050/160] migration: print total downtime for final phase of migration Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini Reviewed-by: Orit Wasserman --- hmp.c | 4 ++++ migration.c | 6 +++++- migration.h | 1 + qapi-schema.json | 7 ++++++- qmp-commands.hx | 3 +++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/hmp.c b/hmp.c index 70bdec2433..a8e5aea7c3 100644 --- a/hmp.c +++ b/hmp.c @@ -152,6 +152,10 @@ void hmp_info_migrate(Monitor *mon) monitor_printf(mon, "Migration status: %s\n", info->status); monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n", info->total_time); + if (info->has_downtime) { + monitor_printf(mon, "downtime: %" PRIu64 " milliseconds\n", + info->downtime); + } } if (info->has_ram) { diff --git a/migration.c b/migration.c index 7a110264ee..1375e7e184 100644 --- a/migration.c +++ b/migration.c @@ -195,6 +195,8 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->has_status = true; info->status = g_strdup("completed"); info->total_time = s->total_time; + info->has_downtime = true; + info->downtime = s->downtime; info->has_ram = true; info->ram = g_malloc0(sizeof(*info->ram)); @@ -329,9 +331,10 @@ static void migrate_fd_put_ready(void *opaque) migrate_fd_error(s); } else if (ret == 1) { int old_vm_running = runstate_is_running(); - int64_t end_time; + int64_t start_time, end_time; DPRINTF("done iterating\n"); + start_time = qemu_get_clock_ms(rt_clock); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); @@ -342,6 +345,7 @@ static void migrate_fd_put_ready(void *opaque) } end_time = qemu_get_clock_ms(rt_clock); s->total_time = end_time - s->total_time; + s->downtime = end_time - start_time; if (s->state != MIG_STATE_COMPLETED) { if (old_vm_running) { vm_start(); diff --git a/migration.h b/migration.h index a9852fcae0..3462917425 100644 --- a/migration.h +++ b/migration.h @@ -40,6 +40,7 @@ struct MigrationState void *opaque; MigrationParams params; int64_t total_time; + int64_t downtime; bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; }; diff --git a/qapi-schema.json b/qapi-schema.json index f9dbdae699..720068706a 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -438,13 +438,18 @@ # If migration has ended, it returns the total migration # time. (since 1.2) # +# @downtime: #optional only present when migration finishes correctly +# total downtime in milliseconds for the guest. +# (since 1.3) +# # Since: 0.14.0 ## { 'type': 'MigrationInfo', 'data': {'*status': 'str', '*ram': 'MigrationStats', '*disk': 'MigrationStats', '*xbzrle-cache': 'XBZRLECacheStats', - '*total-time': 'int'} } + '*total-time': 'int', + '*downtime': 'int'} } ## # @query-migrate diff --git a/qmp-commands.hx b/qmp-commands.hx index 2f8477e2a8..4686057050 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2304,6 +2304,8 @@ The main json-object contains the following: - "total-time": total amount of ms since migration started. If migration has ended, it returns the total migration time (json-int) +- "downtime": only present when migration has finished correctly + total amount in ms for downtime that happened (json-int) - "ram": only present if "status" is "active", it is a json-object with the following RAM information (in bytes): - "transferred": amount transferred (json-int) @@ -2341,6 +2343,7 @@ Examples: "remaining":123, "total":246, "total-time":12345, + "downtime":12345, "duplicate":123, "normal":123, "normal-bytes":123456 From c00012f68b736c0ad9d0ff245373c7005ea0721a Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 13 Aug 2012 09:36:36 +0200 Subject: [PATCH 051/160] migration: rename expected_time to expected_downtime Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini Reviewed-by: Orit Wasserman --- arch_init.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch_init.c b/arch_init.c index 671d3545cc..1d6dda8449 100644 --- a/arch_init.c +++ b/arch_init.c @@ -538,7 +538,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) double bwidth = 0; int ret; int i; - uint64_t expected_time; + uint64_t expected_downtime; bytes_transferred_last = bytes_transferred; bwidth = qemu_get_clock_ns(rt_clock); @@ -577,24 +577,24 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) bwidth = qemu_get_clock_ns(rt_clock) - bwidth; bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; - /* if we haven't transferred anything this round, force expected_time to a - * a very high value, but without crashing */ + /* if we haven't transferred anything this round, force + * expected_downtime to a very high value, but without + * crashing */ if (bwidth == 0) { bwidth = 0.000001; } qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + expected_downtime = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + DPRINTF("ram_save_live: expected(%" PRIu64 ") <= max(" PRIu64 ")?\n", + expected_downtime, migrate_max_downtime()); - DPRINTF("ram_save_live: expected(%" PRIu64 ") <= max(%" PRIu64 ")?\n", - expected_time, migrate_max_downtime()); - - if (expected_time <= migrate_max_downtime()) { + if (expected_downtime <= migrate_max_downtime()) { memory_global_sync_dirty_bitmap(get_system_memory()); - expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + expected_downtime = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; - return expected_time <= migrate_max_downtime(); + return expected_downtime <= migrate_max_downtime(); } return 0; } From 859bc7569a2d244ee6183a99b71186462049ca86 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 13 Aug 2012 09:42:49 +0200 Subject: [PATCH 052/160] migration: export migrate_get_current() Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- migration.c | 2 +- migration.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/migration.c b/migration.c index 1375e7e184..fc615c8096 100644 --- a/migration.c +++ b/migration.c @@ -53,7 +53,7 @@ static NotifierList migration_state_notifiers = migrations at once. For now we don't need to add dynamic creation of migration */ -static MigrationState *migrate_get_current(void) +MigrationState *migrate_get_current(void) { static MigrationState current_migration = { .state = MIG_STATE_SETUP, diff --git a/migration.h b/migration.h index 3462917425..dabc333f5b 100644 --- a/migration.h +++ b/migration.h @@ -81,6 +81,7 @@ void remove_migration_state_change_notifier(Notifier *notify); bool migration_is_active(MigrationState *); bool migration_has_finished(MigrationState *); bool migration_has_failed(MigrationState *); +MigrationState *migrate_get_current(void); uint64_t ram_bytes_remaining(void); uint64_t ram_bytes_transferred(void); From 2c52ddf1cb3057bc2c6ae256857077627f6da43a Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 13 Aug 2012 09:53:12 +0200 Subject: [PATCH 053/160] migration: print expected downtime in info migrate Signed-off-by: Juan Quintela --- arch_init.c | 2 ++ hmp.c | 4 ++++ migration.c | 2 ++ migration.h | 1 + qapi-schema.json | 5 +++++ qmp-commands.hx | 6 ++++++ 6 files changed, 20 insertions(+) diff --git a/arch_init.c b/arch_init.c index 1d6dda8449..3fddb38179 100644 --- a/arch_init.c +++ b/arch_init.c @@ -539,6 +539,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) int ret; int i; uint64_t expected_downtime; + MigrationState *s = migrate_get_current(); bytes_transferred_last = bytes_transferred; bwidth = qemu_get_clock_ns(rt_clock); @@ -593,6 +594,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) if (expected_downtime <= migrate_max_downtime()) { memory_global_sync_dirty_bitmap(get_system_memory()); expected_downtime = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + s->expected_downtime = expected_downtime / 1000000; /* ns -> ms */ return expected_downtime <= migrate_max_downtime(); } diff --git a/hmp.c b/hmp.c index a8e5aea7c3..96e21742ec 100644 --- a/hmp.c +++ b/hmp.c @@ -152,6 +152,10 @@ void hmp_info_migrate(Monitor *mon) monitor_printf(mon, "Migration status: %s\n", info->status); monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n", info->total_time); + if (info->has_expected_downtime) { + monitor_printf(mon, "expected downtime: %" PRIu64 " milliseconds\n", + info->expected_downtime); + } if (info->has_downtime) { monitor_printf(mon, "downtime: %" PRIu64 " milliseconds\n", info->downtime); diff --git a/migration.c b/migration.c index fc615c8096..8d3e018dc0 100644 --- a/migration.c +++ b/migration.c @@ -169,6 +169,8 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->has_total_time = true; info->total_time = qemu_get_clock_ms(rt_clock) - s->total_time; + info->has_expected_downtime = true; + info->expected_downtime = s->expected_downtime; info->has_ram = true; info->ram = g_malloc0(sizeof(*info->ram)); diff --git a/migration.h b/migration.h index dabc333f5b..552200c348 100644 --- a/migration.h +++ b/migration.h @@ -41,6 +41,7 @@ struct MigrationState MigrationParams params; int64_t total_time; int64_t downtime; + int64_t expected_downtime; bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; }; diff --git a/qapi-schema.json b/qapi-schema.json index 720068706a..bcb5edb89d 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -442,6 +442,10 @@ # total downtime in milliseconds for the guest. # (since 1.3) # +# @expected-downtime: #optional only present while migration is active +# expected downtime in milliseconds for the guest in last walk +# of the dirty bitmap. (since 1.3) +# # Since: 0.14.0 ## { 'type': 'MigrationInfo', @@ -449,6 +453,7 @@ '*disk': 'MigrationStats', '*xbzrle-cache': 'XBZRLECacheStats', '*total-time': 'int', + '*expected-downtime': 'int', '*downtime': 'int'} } ## diff --git a/qmp-commands.hx b/qmp-commands.hx index 4686057050..5ba8c48cb4 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2306,6 +2306,9 @@ The main json-object contains the following: time (json-int) - "downtime": only present when migration has finished correctly total amount in ms for downtime that happened (json-int) +- "expected-downtime": only present while migration is active + total amount in ms for downtime that was calculated on + the last bitmap round (json-int) - "ram": only present if "status" is "active", it is a json-object with the following RAM information (in bytes): - "transferred": amount transferred (json-int) @@ -2367,6 +2370,7 @@ Examples: "remaining":123, "total":246, "total-time":12345, + "expected-downtime":12345, "duplicate":123, "normal":123, "normal-bytes":123456 @@ -2385,6 +2389,7 @@ Examples: "remaining":1053304, "transferred":3720, "total-time":12345, + "expected-downtime":12345, "duplicate":123, "normal":123, "normal-bytes":123456 @@ -2409,6 +2414,7 @@ Examples: "remaining":1053304, "transferred":3720, "total-time":12345, + "expected-downtime":12345, "duplicate":10, "normal":3333, "normal-bytes":3412992 From 5a17077529f7feec559e1881792e89554c2ae5b6 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 17 Jul 2012 17:02:24 +0200 Subject: [PATCH 054/160] savevm: Factorize ram globals reset in its own function Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini Reviewed-by: Orit Wasserman --- arch_init.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch_init.c b/arch_init.c index 3fddb38179..6b9f949db3 100644 --- a/arch_init.c +++ b/arch_init.c @@ -481,6 +481,14 @@ static void ram_migration_cancel(void *opaque) migration_end(); } + +static void reset_ram_globals(void) +{ + last_block = NULL; + last_offset = 0; + sort_ram_list(); +} + #define MAX_WAIT 50 /* ms, half buffered_file limit */ static int ram_save_setup(QEMUFile *f, void *opaque) @@ -489,9 +497,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) RAMBlock *block; bytes_transferred = 0; - last_block = NULL; - last_offset = 0; - sort_ram_list(); + reset_ram_globals(); if (migrate_use_xbzrle()) { XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() / From e44d26c8f3894a220f29ff5b27abf87f570d2c07 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 10:16:08 +0200 Subject: [PATCH 055/160] ram: introduce migration_bitmap_set_dirty() It just marks a region of memory as dirty. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini Reviewed-by: Orit Wasserman --- arch_init.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/arch_init.c b/arch_init.c index 6b9f949db3..fa470515db 100644 --- a/arch_init.c +++ b/arch_init.c @@ -331,6 +331,18 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, static RAMBlock *last_block; static ram_addr_t last_offset; +static inline void migration_bitmap_set_dirty(MemoryRegion *mr, int length) +{ + ram_addr_t addr; + + for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) { + if (!memory_region_get_dirty(mr, addr, TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION)) { + memory_region_set_dirty(mr, addr, TARGET_PAGE_SIZE); + } + } +} + /* * ram_save_block: Writes a page of memory to the stream f * @@ -493,7 +505,6 @@ static void reset_ram_globals(void) static int ram_save_setup(QEMUFile *f, void *opaque) { - ram_addr_t addr; RAMBlock *block; bytes_transferred = 0; @@ -514,12 +525,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) /* Make sure all dirty bits are set */ QLIST_FOREACH(block, &ram_list.blocks, next) { - for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) { - if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION)) { - memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE); - } - } + migration_bitmap_set_dirty(block->mr, block->length); } memory_global_dirty_log_start(); From 69268cde142d169e2e47836bcf0a26341e30218a Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 10:36:12 +0200 Subject: [PATCH 056/160] ram: Introduce migration_bitmap_test_and_reset_dirty() It just test if the dirty bit is set, and clears it. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini Reviewed-by: Orit Wasserman --- arch_init.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/arch_init.c b/arch_init.c index fa470515db..90a722e6c9 100644 --- a/arch_init.c +++ b/arch_init.c @@ -331,6 +331,19 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, static RAMBlock *last_block; static ram_addr_t last_offset; +static inline bool migration_bitmap_test_and_reset_dirty(MemoryRegion *mr, + ram_addr_t offset) +{ + bool ret = memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION); + + if (ret) { + memory_region_reset_dirty(mr, offset, TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION); + } + return ret; +} + static inline void migration_bitmap_set_dirty(MemoryRegion *mr, int length) { ram_addr_t addr; @@ -364,14 +377,10 @@ static int ram_save_block(QEMUFile *f, bool last_stage) do { mr = block->mr; - if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION)) { + if (migration_bitmap_test_and_reset_dirty(mr, offset)) { uint8_t *p; int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0; - memory_region_reset_dirty(mr, offset, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION); - p = memory_region_get_ram_ptr(mr) + offset; if (is_dup_page(p)) { From 652d7ec291d1726ad01587e13331d7277fa402ec Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 10:37:54 +0200 Subject: [PATCH 057/160] ram: Export last_ram_offset() Is the only way of knowing the RAM size. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- cpu-all.h | 1 + exec.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cpu-all.h b/cpu-all.h index 2b99682677..287b0003ea 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -518,6 +518,7 @@ extern int mem_prealloc; #define TLB_MMIO (1 << 5) void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); +ram_addr_t last_ram_offset(void); #endif /* !CONFIG_USER_ONLY */ int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr, diff --git a/exec.c b/exec.c index 7899042ce9..e63ad0da3d 100644 --- a/exec.c +++ b/exec.c @@ -2454,7 +2454,7 @@ static ram_addr_t find_ram_offset(ram_addr_t size) return offset; } -static ram_addr_t last_ram_offset(void) +ram_addr_t last_ram_offset(void) { RAMBlock *block; ram_addr_t last = 0; From dd2df737ef3930f6d88116520d6ca7ff3cf0c41f Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 10:52:51 +0200 Subject: [PATCH 058/160] ram: introduce migration_bitmap_sync() Helper that we use each time that we need to syncronize the migration bitmap with the other dirty bitmaps. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- arch_init.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch_init.c b/arch_init.c index 90a722e6c9..3a5fecccc7 100644 --- a/arch_init.c +++ b/arch_init.c @@ -356,6 +356,12 @@ static inline void migration_bitmap_set_dirty(MemoryRegion *mr, int length) } } +static void migration_bitmap_sync(void) +{ + memory_global_sync_dirty_bitmap(get_system_memory()); +} + + /* * ram_save_block: Writes a page of memory to the stream f * @@ -613,7 +619,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) expected_downtime, migrate_max_downtime()); if (expected_downtime <= migrate_max_downtime()) { - memory_global_sync_dirty_bitmap(get_system_memory()); + migration_bitmap_sync(); expected_downtime = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; s->expected_downtime = expected_downtime / 1000000; /* ns -> ms */ @@ -624,7 +630,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) static int ram_save_complete(QEMUFile *f, void *opaque) { - memory_global_sync_dirty_bitmap(get_system_memory()); + migration_bitmap_sync(); /* try transferring iterative blocks of memory */ From 3c12193d998249bcbe5099edf85039bcd25c3a80 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 4 Sep 2012 13:08:57 +0200 Subject: [PATCH 059/160] ram: create trace event for migration sync bitmap Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- arch_init.c | 6 ++++++ trace-events | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/arch_init.c b/arch_init.c index 3a5fecccc7..cec3ead8de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -45,6 +45,7 @@ #include "hw/pcspk.h" #include "qemu/page_cache.h" #include "qmp-commands.h" +#include "trace.h" #ifdef DEBUG_ARCH_INIT #define DPRINTF(fmt, ...) \ @@ -358,7 +359,12 @@ static inline void migration_bitmap_set_dirty(MemoryRegion *mr, int length) static void migration_bitmap_sync(void) { + uint64_t num_dirty_pages_init = ram_list.dirty_pages; + + trace_migration_bitmap_sync_start(); memory_global_sync_dirty_bitmap(get_system_memory()); + trace_migration_bitmap_sync_end(ram_list.dirty_pages + - num_dirty_pages_init); } diff --git a/trace-events b/trace-events index 42b66f19f4..e2d4580d4c 100644 --- a/trace-events +++ b/trace-events @@ -921,6 +921,10 @@ ppm_save(const char *filename, void *display_surface) "%s surface=%p" savevm_section_start(void) "" savevm_section_end(unsigned int section_id) "section_id %u" +# arch_init.c +migration_bitmap_sync_start(void) "" +migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64"" + # hw/qxl.c disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d" disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u" From c6bf8e0e0cf04b40a8a22426e00ebbd727331d8b Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 12:33:00 +0200 Subject: [PATCH 060/160] Separate migration bitmap This patch creates a migration bitmap, which is periodically kept in sync with the qemu bitmap. A separate copy of the dirty bitmap for the migration limits the amount of concurrent access to the qemu bitmap from iothread and migration thread (which requires taking the big lock). We use the qemu bitmap type. We have to "undo" the dirty_pages counting optimization on the general dirty bitmap and do the counting optimization with the migration local bitmap. Signed-off-by: Umesh Deshpande Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- arch_init.c | 63 +++++++++++++++++++++++++++++++++---------------- cpu-all.h | 1 - exec-obsolete.h | 10 -------- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/arch_init.c b/arch_init.c index cec3ead8de..d918844028 100644 --- a/arch_init.c +++ b/arch_init.c @@ -31,6 +31,8 @@ #include "config.h" #include "monitor.h" #include "sysemu.h" +#include "bitops.h" +#include "bitmap.h" #include "arch_init.h" #include "audio/audio.h" #include "hw/pc.h" @@ -331,39 +333,57 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, static RAMBlock *last_block; static ram_addr_t last_offset; +static unsigned long *migration_bitmap; +static uint64_t migration_dirty_pages; static inline bool migration_bitmap_test_and_reset_dirty(MemoryRegion *mr, ram_addr_t offset) { - bool ret = memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION); + bool ret; + int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS; + + ret = test_and_clear_bit(nr, migration_bitmap); if (ret) { - memory_region_reset_dirty(mr, offset, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION); + migration_dirty_pages--; } return ret; } -static inline void migration_bitmap_set_dirty(MemoryRegion *mr, int length) +static inline bool migration_bitmap_set_dirty(MemoryRegion *mr, + ram_addr_t offset) { - ram_addr_t addr; + bool ret; + int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS; - for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) { - if (!memory_region_get_dirty(mr, addr, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION)) { - memory_region_set_dirty(mr, addr, TARGET_PAGE_SIZE); - } + ret = test_and_set_bit(nr, migration_bitmap); + + if (!ret) { + migration_dirty_pages++; } + return ret; } static void migration_bitmap_sync(void) { - uint64_t num_dirty_pages_init = ram_list.dirty_pages; + RAMBlock *block; + ram_addr_t addr; + uint64_t num_dirty_pages_init = migration_dirty_pages; trace_migration_bitmap_sync_start(); memory_global_sync_dirty_bitmap(get_system_memory()); - trace_migration_bitmap_sync_end(ram_list.dirty_pages + + QLIST_FOREACH(block, &ram_list.blocks, next) { + for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) { + if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION)) { + migration_bitmap_set_dirty(block->mr, addr); + } + } + memory_region_reset_dirty(block->mr, 0, block->length, + DIRTY_MEMORY_MIGRATION); + } + trace_migration_bitmap_sync_end(migration_dirty_pages - num_dirty_pages_init); } @@ -442,7 +462,7 @@ static uint64_t bytes_transferred; static ram_addr_t ram_save_remaining(void) { - return ram_list.dirty_pages; + return migration_dirty_pages; } uint64_t ram_bytes_remaining(void) @@ -527,6 +547,11 @@ static void reset_ram_globals(void) static int ram_save_setup(QEMUFile *f, void *opaque) { RAMBlock *block; + int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS; + + migration_bitmap = bitmap_new(ram_pages); + bitmap_set(migration_bitmap, 1, ram_pages); + migration_dirty_pages = ram_pages; bytes_transferred = 0; reset_ram_globals(); @@ -544,13 +569,8 @@ static int ram_save_setup(QEMUFile *f, void *opaque) acct_clear(); } - /* Make sure all dirty bits are set */ - QLIST_FOREACH(block, &ram_list.blocks, next) { - migration_bitmap_set_dirty(block->mr, block->length); - } - memory_global_dirty_log_start(); - memory_global_sync_dirty_bitmap(get_system_memory()); + migration_bitmap_sync(); qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE); @@ -655,6 +675,9 @@ static int ram_save_complete(QEMUFile *f, void *opaque) qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + g_free(migration_bitmap); + migration_bitmap = NULL; + return 0; } diff --git a/cpu-all.h b/cpu-all.h index 287b0003ea..6aa7e58cb1 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -500,7 +500,6 @@ typedef struct RAMBlock { typedef struct RAMList { uint8_t *phys_dirty; QLIST_HEAD(, RAMBlock) blocks; - uint64_t dirty_pages; } RAMList; extern RAMList ram_list; diff --git a/exec-obsolete.h b/exec-obsolete.h index 286e2f75e1..6d35d4b83e 100644 --- a/exec-obsolete.h +++ b/exec-obsolete.h @@ -75,11 +75,6 @@ static inline int cpu_physical_memory_get_dirty(ram_addr_t start, static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr, int dirty_flags) { - if ((dirty_flags & MIGRATION_DIRTY_FLAG) && - !cpu_physical_memory_get_dirty(addr, TARGET_PAGE_SIZE, - MIGRATION_DIRTY_FLAG)) { - ram_list.dirty_pages++; - } return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags; } @@ -93,11 +88,6 @@ static inline int cpu_physical_memory_clear_dirty_flags(ram_addr_t addr, { int mask = ~dirty_flags; - if ((dirty_flags & MIGRATION_DIRTY_FLAG) && - cpu_physical_memory_get_dirty(addr, TARGET_PAGE_SIZE, - MIGRATION_DIRTY_FLAG)) { - ram_list.dirty_pages--; - } return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] &= mask; } From 8d017193e2b66a65adf53e46a6372e55470fe7fd Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 13 Aug 2012 12:31:25 +0200 Subject: [PATCH 061/160] migration: Add dirty_pages_rate to query migrate output It indicates how many pages were dirtied during the last second. Signed-off-by: Juan Quintela --- arch_init.c | 18 ++++++++++++++++++ hmp.c | 4 ++++ migration.c | 2 ++ migration.h | 1 + qapi-schema.json | 8 ++++++-- 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/arch_init.c b/arch_init.c index d918844028..e6effe809a 100644 --- a/arch_init.c +++ b/arch_init.c @@ -369,6 +369,14 @@ static void migration_bitmap_sync(void) RAMBlock *block; ram_addr_t addr; uint64_t num_dirty_pages_init = migration_dirty_pages; + MigrationState *s = migrate_get_current(); + static int64_t start_time; + static int64_t num_dirty_pages_period; + int64_t end_time; + + if (!start_time) { + start_time = qemu_get_clock_ms(rt_clock); + } trace_migration_bitmap_sync_start(); memory_global_sync_dirty_bitmap(get_system_memory()); @@ -385,6 +393,16 @@ static void migration_bitmap_sync(void) } trace_migration_bitmap_sync_end(migration_dirty_pages - num_dirty_pages_init); + num_dirty_pages_period += migration_dirty_pages - num_dirty_pages_init; + end_time = qemu_get_clock_ms(rt_clock); + + /* more than 1 second = 1000 millisecons */ + if (end_time > start_time + 1000) { + s->dirty_pages_rate = num_dirty_pages_period * 1000 + / (end_time - start_time); + start_time = end_time; + num_dirty_pages_period = 0; + } } diff --git a/hmp.c b/hmp.c index 96e21742ec..2b979826ee 100644 --- a/hmp.c +++ b/hmp.c @@ -175,6 +175,10 @@ void hmp_info_migrate(Monitor *mon) info->ram->normal); monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n", info->ram->normal_bytes >> 10); + if (info->ram->dirty_pages_rate) { + monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n", + info->ram->dirty_pages_rate); + } } if (info->has_disk) { diff --git a/migration.c b/migration.c index 8d3e018dc0..330c16a97f 100644 --- a/migration.c +++ b/migration.c @@ -180,6 +180,8 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->ram->duplicate = dup_mig_pages_transferred(); info->ram->normal = norm_mig_pages_transferred(); info->ram->normal_bytes = norm_mig_bytes_transferred(); + info->ram->dirty_pages_rate = s->dirty_pages_rate; + if (blk_mig_active()) { info->has_disk = true; diff --git a/migration.h b/migration.h index 552200c348..66d7f68bb8 100644 --- a/migration.h +++ b/migration.h @@ -42,6 +42,7 @@ struct MigrationState int64_t total_time; int64_t downtime; int64_t expected_downtime; + int64_t dirty_pages_rate; bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; }; diff --git a/qapi-schema.json b/qapi-schema.json index bcb5edb89d..c615ee212d 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -383,13 +383,17 @@ # # @normal : number of normal pages (since 1.2) # -# @normal-bytes : number of normal bytes sent (since 1.2) +# @normal-bytes: number of normal bytes sent (since 1.2) +# +# @dirty-pages-rate: number of pages dirtied by second by the +# guest (since 1.3) # # Since: 0.14.0 ## { 'type': 'MigrationStats', 'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' , - 'duplicate': 'int', 'normal': 'int', 'normal-bytes': 'int' } } + 'duplicate': 'int', 'normal': 'int', 'normal-bytes': 'int', + 'dirty-pages-rate' : 'int' } } ## # @XBZRLECacheStats From 2dddf6f4133975af62e64cb6406ec1239491fa89 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 16 Aug 2011 16:43:24 -0700 Subject: [PATCH 062/160] BufferedFile: append, then flush Simplify the logic for pushing data from the buffer to the output pipe/socket. This also matches more closely what will be the operation of the migration thread. Signed-off-by: Paolo Bonzini Reviewed-by: Paolo Bonzini Reviewed-by: Orit Wasserman --- buffered_file.c | 50 +++++++++++-------------------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 4148abbee0..71558009bd 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -75,7 +75,7 @@ static void buffered_flush(QEMUFileBuffered *s) DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); - while (offset < s->buffer_size) { + while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { ssize_t ret; ret = s->put_buffer(s->opaque, s->buffer + offset, @@ -93,6 +93,7 @@ static void buffered_flush(QEMUFileBuffered *s) } else { DPRINTF("flushed %zd byte(s)\n", ret); offset += ret; + s->bytes_xfer += ret; } } @@ -104,8 +105,7 @@ static void buffered_flush(QEMUFileBuffered *s) static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { QEMUFileBuffered *s = opaque; - int offset = 0, error; - ssize_t ret; + int error; DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); @@ -118,48 +118,22 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in DPRINTF("unfreezing output\n"); s->freeze_output = 0; - buffered_flush(s); - - while (!s->freeze_output && offset < size) { - if (s->bytes_xfer > s->xfer_limit) { - DPRINTF("transfer limit exceeded when putting\n"); - break; - } - - ret = s->put_buffer(s->opaque, buf + offset, size - offset); - if (ret == -EAGAIN) { - DPRINTF("backend not ready, freezing\n"); - s->freeze_output = 1; - break; - } - - if (ret <= 0) { - DPRINTF("error putting\n"); - qemu_file_set_error(s->file, ret); - offset = -EINVAL; - break; - } - - DPRINTF("put %zd byte(s)\n", ret); - offset += ret; - s->bytes_xfer += ret; - } - - if (offset >= 0) { + if (size > 0) { DPRINTF("buffering %d bytes\n", size - offset); - buffered_append(s, buf + offset, size - offset); - offset = size; + buffered_append(s, buf, size); } + buffered_flush(s); + if (pos == 0 && size == 0) { DPRINTF("file is ready\n"); - if (s->bytes_xfer <= s->xfer_limit) { + if (!s->freeze_output && s->bytes_xfer < s->xfer_limit) { DPRINTF("notifying client\n"); s->put_ready(s->opaque); } } - return offset; + return size; } static int buffered_close(void *opaque) @@ -169,6 +143,7 @@ static int buffered_close(void *opaque) DPRINTF("closing\n"); + s->xfer_limit = INT_MAX; while (!qemu_file_get_error(s->file) && s->buffer_size) { buffered_flush(s); if (s->freeze_output) @@ -248,10 +223,7 @@ static void buffered_rate_tick(void *opaque) s->bytes_xfer = 0; - buffered_flush(s); - - /* Add some checks around this */ - s->put_ready(s->opaque); + buffered_put_buffer(s, NULL, 0, 0); } QEMUFile *qemu_fopen_ops_buffered(void *opaque, From 8e92c9e24f8c4edd7976aca82abf90e9a12667b4 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 13:04:42 +0200 Subject: [PATCH 063/160] buffered_file: rename opaque to migration_state Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- buffered_file.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 71558009bd..33b700be50 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -27,7 +27,7 @@ typedef struct QEMUFileBuffered BufferedPutReadyFunc *put_ready; BufferedWaitForUnfreezeFunc *wait_for_unfreeze; BufferedCloseFunc *close; - void *opaque; + void *migration_state; QEMUFile *file; int freeze_output; size_t bytes_xfer; @@ -78,7 +78,7 @@ static void buffered_flush(QEMUFileBuffered *s) while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { ssize_t ret; - ret = s->put_buffer(s->opaque, s->buffer + offset, + ret = s->put_buffer(s->migration_state, s->buffer + offset, s->buffer_size - offset); if (ret == -EAGAIN) { DPRINTF("backend not ready, freezing\n"); @@ -129,7 +129,7 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in DPRINTF("file is ready\n"); if (!s->freeze_output && s->bytes_xfer < s->xfer_limit) { DPRINTF("notifying client\n"); - s->put_ready(s->opaque); + s->put_ready(s->migration_state); } } @@ -147,10 +147,10 @@ static int buffered_close(void *opaque) while (!qemu_file_get_error(s->file) && s->buffer_size) { buffered_flush(s); if (s->freeze_output) - s->wait_for_unfreeze(s->opaque); + s->wait_for_unfreeze(s->migration_state); } - ret = s->close(s->opaque); + ret = s->close(s->migration_state); qemu_del_timer(s->timer); qemu_free_timer(s->timer); @@ -237,7 +237,7 @@ QEMUFile *qemu_fopen_ops_buffered(void *opaque, s = g_malloc0(sizeof(*s)); - s->opaque = opaque; + s->migration_state = opaque; s->xfer_limit = bytes_per_sec / 10; s->put_buffer = put_buffer; s->put_ready = put_ready; From c7a8f0cdd25ed552e6dba124877bd3364054c55c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 13:07:17 +0200 Subject: [PATCH 064/160] buffered_file: opaque is MigrationState It always have that type, just change it. We will remove buffered file later on the migration thread series. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- buffered_file.c | 6 +++--- buffered_file.h | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 33b700be50..59d952df0a 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -27,7 +27,7 @@ typedef struct QEMUFileBuffered BufferedPutReadyFunc *put_ready; BufferedWaitForUnfreezeFunc *wait_for_unfreeze; BufferedCloseFunc *close; - void *migration_state; + MigrationState *migration_state; QEMUFile *file; int freeze_output; size_t bytes_xfer; @@ -226,7 +226,7 @@ static void buffered_rate_tick(void *opaque) buffered_put_buffer(s, NULL, 0, 0); } -QEMUFile *qemu_fopen_ops_buffered(void *opaque, +QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, size_t bytes_per_sec, BufferedPutFunc *put_buffer, BufferedPutReadyFunc *put_ready, @@ -237,7 +237,7 @@ QEMUFile *qemu_fopen_ops_buffered(void *opaque, s = g_malloc0(sizeof(*s)); - s->migration_state = opaque; + s->migration_state = migration_state; s->xfer_limit = bytes_per_sec / 10; s->put_buffer = put_buffer; s->put_ready = put_ready; diff --git a/buffered_file.h b/buffered_file.h index 98d358baea..39f7fa005d 100644 --- a/buffered_file.h +++ b/buffered_file.h @@ -15,13 +15,15 @@ #define QEMU_BUFFERED_FILE_H #include "hw/hw.h" +#include "migration.h" typedef ssize_t (BufferedPutFunc)(void *opaque, const void *data, size_t size); typedef void (BufferedPutReadyFunc)(void *opaque); typedef void (BufferedWaitForUnfreezeFunc)(void *opaque); typedef int (BufferedCloseFunc)(void *opaque); -QEMUFile *qemu_fopen_ops_buffered(void *opaque, size_t xfer_limit, +QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, + size_t xfer_limit, BufferedPutFunc *put_buffer, BufferedPutReadyFunc *put_ready, BufferedWaitForUnfreezeFunc *wait_for_unfreeze, From c87b015bc71734db74f5bdffeda122a224c75bbb Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 13:10:54 +0200 Subject: [PATCH 065/160] buffered_file: unfold migrate_fd_put_buffer We only used it once, just remove the callback indirection Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- buffered_file.c | 7 ++----- buffered_file.h | 2 -- migration.c | 6 ++---- migration.h | 3 +++ 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 59d952df0a..702a7266b6 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -23,7 +23,6 @@ typedef struct QEMUFileBuffered { - BufferedPutFunc *put_buffer; BufferedPutReadyFunc *put_ready; BufferedWaitForUnfreezeFunc *wait_for_unfreeze; BufferedCloseFunc *close; @@ -78,8 +77,8 @@ static void buffered_flush(QEMUFileBuffered *s) while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { ssize_t ret; - ret = s->put_buffer(s->migration_state, s->buffer + offset, - s->buffer_size - offset); + ret = migrate_fd_put_buffer(s->migration_state, s->buffer + offset, + s->buffer_size - offset); if (ret == -EAGAIN) { DPRINTF("backend not ready, freezing\n"); s->freeze_output = 1; @@ -228,7 +227,6 @@ static void buffered_rate_tick(void *opaque) QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, size_t bytes_per_sec, - BufferedPutFunc *put_buffer, BufferedPutReadyFunc *put_ready, BufferedWaitForUnfreezeFunc *wait_for_unfreeze, BufferedCloseFunc *close) @@ -239,7 +237,6 @@ QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, s->migration_state = migration_state; s->xfer_limit = bytes_per_sec / 10; - s->put_buffer = put_buffer; s->put_ready = put_ready; s->wait_for_unfreeze = wait_for_unfreeze; s->close = close; diff --git a/buffered_file.h b/buffered_file.h index 39f7fa005d..ca7e62d4b3 100644 --- a/buffered_file.h +++ b/buffered_file.h @@ -17,14 +17,12 @@ #include "hw/hw.h" #include "migration.h" -typedef ssize_t (BufferedPutFunc)(void *opaque, const void *data, size_t size); typedef void (BufferedPutReadyFunc)(void *opaque); typedef void (BufferedWaitForUnfreezeFunc)(void *opaque); typedef int (BufferedCloseFunc)(void *opaque); QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, size_t xfer_limit, - BufferedPutFunc *put_buffer, BufferedPutReadyFunc *put_ready, BufferedWaitForUnfreezeFunc *wait_for_unfreeze, BufferedCloseFunc *close); diff --git a/migration.c b/migration.c index 330c16a97f..f6ee7cdb6a 100644 --- a/migration.c +++ b/migration.c @@ -295,10 +295,9 @@ static void migrate_fd_put_notify(void *opaque) } } -static ssize_t migrate_fd_put_buffer(void *opaque, const void *data, - size_t size) +ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, + size_t size) { - MigrationState *s = opaque; ssize_t ret; if (s->state != MIG_STATE_ACTIVE) { @@ -436,7 +435,6 @@ void migrate_fd_connect(MigrationState *s) s->state = MIG_STATE_ACTIVE; s->file = qemu_fopen_ops_buffered(s, s->bandwidth_limit, - migrate_fd_put_buffer, migrate_fd_put_ready, migrate_fd_wait_for_unfreeze, migrate_fd_close); diff --git a/migration.h b/migration.h index 66d7f68bb8..02d0219e86 100644 --- a/migration.h +++ b/migration.h @@ -78,6 +78,9 @@ void migrate_fd_error(MigrationState *s); void migrate_fd_connect(MigrationState *s); +ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, + size_t size); + void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); bool migration_is_active(MigrationState *); From 2c9adcb850bba7a24caec4d666dc01deca9f7649 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 13:13:59 +0200 Subject: [PATCH 066/160] buffered_file: unfold migrate_fd_put_ready We only use it once, just remove the callback indirection. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- buffered_file.c | 5 +---- buffered_file.h | 2 -- migration.c | 4 +--- migration.h | 1 + 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 702a7266b6..4c6a7976b1 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -23,7 +23,6 @@ typedef struct QEMUFileBuffered { - BufferedPutReadyFunc *put_ready; BufferedWaitForUnfreezeFunc *wait_for_unfreeze; BufferedCloseFunc *close; MigrationState *migration_state; @@ -128,7 +127,7 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in DPRINTF("file is ready\n"); if (!s->freeze_output && s->bytes_xfer < s->xfer_limit) { DPRINTF("notifying client\n"); - s->put_ready(s->migration_state); + migrate_fd_put_ready(s->migration_state); } } @@ -227,7 +226,6 @@ static void buffered_rate_tick(void *opaque) QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, size_t bytes_per_sec, - BufferedPutReadyFunc *put_ready, BufferedWaitForUnfreezeFunc *wait_for_unfreeze, BufferedCloseFunc *close) { @@ -237,7 +235,6 @@ QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, s->migration_state = migration_state; s->xfer_limit = bytes_per_sec / 10; - s->put_ready = put_ready; s->wait_for_unfreeze = wait_for_unfreeze; s->close = close; diff --git a/buffered_file.h b/buffered_file.h index ca7e62d4b3..dd239b3d02 100644 --- a/buffered_file.h +++ b/buffered_file.h @@ -17,13 +17,11 @@ #include "hw/hw.h" #include "migration.h" -typedef void (BufferedPutReadyFunc)(void *opaque); typedef void (BufferedWaitForUnfreezeFunc)(void *opaque); typedef int (BufferedCloseFunc)(void *opaque); QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, size_t xfer_limit, - BufferedPutReadyFunc *put_ready, BufferedWaitForUnfreezeFunc *wait_for_unfreeze, BufferedCloseFunc *close); diff --git a/migration.c b/migration.c index f6ee7cdb6a..051b1b56aa 100644 --- a/migration.c +++ b/migration.c @@ -318,9 +318,8 @@ ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, return ret; } -static void migrate_fd_put_ready(void *opaque) +void migrate_fd_put_ready(MigrationState *s) { - MigrationState *s = opaque; int ret; if (s->state != MIG_STATE_ACTIVE) { @@ -435,7 +434,6 @@ void migrate_fd_connect(MigrationState *s) s->state = MIG_STATE_ACTIVE; s->file = qemu_fopen_ops_buffered(s, s->bandwidth_limit, - migrate_fd_put_ready, migrate_fd_wait_for_unfreeze, migrate_fd_close); diff --git a/migration.h b/migration.h index 02d0219e86..031c2ab2ed 100644 --- a/migration.h +++ b/migration.h @@ -80,6 +80,7 @@ void migrate_fd_connect(MigrationState *s); ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, size_t size); +void migrate_fd_put_ready(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); From 749f7909d942f5c7425d0895242ce720cd663e92 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 13:16:28 +0200 Subject: [PATCH 067/160] buffered_file: unfold migrate_fd_wait_for_unfreeze We only used it once, just remove the callback indirection. Signed-off-by: Juan Quintela --- buffered_file.c | 5 +---- buffered_file.h | 2 -- migration.c | 4 +--- migration.h | 1 + 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 4c6a7976b1..d257496b7e 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -23,7 +23,6 @@ typedef struct QEMUFileBuffered { - BufferedWaitForUnfreezeFunc *wait_for_unfreeze; BufferedCloseFunc *close; MigrationState *migration_state; QEMUFile *file; @@ -145,7 +144,7 @@ static int buffered_close(void *opaque) while (!qemu_file_get_error(s->file) && s->buffer_size) { buffered_flush(s); if (s->freeze_output) - s->wait_for_unfreeze(s->migration_state); + migrate_fd_wait_for_unfreeze(s->migration_state); } ret = s->close(s->migration_state); @@ -226,7 +225,6 @@ static void buffered_rate_tick(void *opaque) QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, size_t bytes_per_sec, - BufferedWaitForUnfreezeFunc *wait_for_unfreeze, BufferedCloseFunc *close) { QEMUFileBuffered *s; @@ -235,7 +233,6 @@ QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, s->migration_state = migration_state; s->xfer_limit = bytes_per_sec / 10; - s->wait_for_unfreeze = wait_for_unfreeze; s->close = close; s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL, diff --git a/buffered_file.h b/buffered_file.h index dd239b3d02..926e5c6fc5 100644 --- a/buffered_file.h +++ b/buffered_file.h @@ -17,12 +17,10 @@ #include "hw/hw.h" #include "migration.h" -typedef void (BufferedWaitForUnfreezeFunc)(void *opaque); typedef int (BufferedCloseFunc)(void *opaque); QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, size_t xfer_limit, - BufferedWaitForUnfreezeFunc *wait_for_unfreeze, BufferedCloseFunc *close); #endif diff --git a/migration.c b/migration.c index 051b1b56aa..30def68f1d 100644 --- a/migration.c +++ b/migration.c @@ -370,9 +370,8 @@ static void migrate_fd_cancel(MigrationState *s) migrate_fd_cleanup(s); } -static void migrate_fd_wait_for_unfreeze(void *opaque) +void migrate_fd_wait_for_unfreeze(MigrationState *s) { - MigrationState *s = opaque; int ret; DPRINTF("wait for unfreeze\n"); @@ -434,7 +433,6 @@ void migrate_fd_connect(MigrationState *s) s->state = MIG_STATE_ACTIVE; s->file = qemu_fopen_ops_buffered(s, s->bandwidth_limit, - migrate_fd_wait_for_unfreeze, migrate_fd_close); DPRINTF("beginning savevm\n"); diff --git a/migration.h b/migration.h index 031c2ab2ed..d6341d66a3 100644 --- a/migration.h +++ b/migration.h @@ -81,6 +81,7 @@ void migrate_fd_connect(MigrationState *s); ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, size_t size); void migrate_fd_put_ready(MigrationState *s); +void migrate_fd_wait_for_unfreeze(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); From 11c7674129a81b5b69e00ad252a63186e15bf6b6 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 13:19:36 +0200 Subject: [PATCH 068/160] buffered_file: unfold migrate_fd_close We only used it once, just remove the callback indirection. Signed-off-by: Juan Quintela --- buffered_file.c | 7 ++----- buffered_file.h | 5 +---- migration.c | 8 ++------ migration.h | 1 + 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index d257496b7e..4fca774dd8 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -23,7 +23,6 @@ typedef struct QEMUFileBuffered { - BufferedCloseFunc *close; MigrationState *migration_state; QEMUFile *file; int freeze_output; @@ -147,7 +146,7 @@ static int buffered_close(void *opaque) migrate_fd_wait_for_unfreeze(s->migration_state); } - ret = s->close(s->migration_state); + ret = migrate_fd_close(s->migration_state); qemu_del_timer(s->timer); qemu_free_timer(s->timer); @@ -224,8 +223,7 @@ static void buffered_rate_tick(void *opaque) } QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, - size_t bytes_per_sec, - BufferedCloseFunc *close) + size_t bytes_per_sec) { QEMUFileBuffered *s; @@ -233,7 +231,6 @@ QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, s->migration_state = migration_state; s->xfer_limit = bytes_per_sec / 10; - s->close = close; s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL, buffered_close, buffered_rate_limit, diff --git a/buffered_file.h b/buffered_file.h index 926e5c6fc5..8a38754146 100644 --- a/buffered_file.h +++ b/buffered_file.h @@ -17,10 +17,7 @@ #include "hw/hw.h" #include "migration.h" -typedef int (BufferedCloseFunc)(void *opaque); - QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, - size_t xfer_limit, - BufferedCloseFunc *close); + size_t xfer_limit); #endif diff --git a/migration.c b/migration.c index 30def68f1d..f647a3fccb 100644 --- a/migration.c +++ b/migration.c @@ -392,10 +392,8 @@ void migrate_fd_wait_for_unfreeze(MigrationState *s) } } -static int migrate_fd_close(void *opaque) +int migrate_fd_close(MigrationState *s) { - MigrationState *s = opaque; - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); return s->close(s); } @@ -431,9 +429,7 @@ void migrate_fd_connect(MigrationState *s) int ret; s->state = MIG_STATE_ACTIVE; - s->file = qemu_fopen_ops_buffered(s, - s->bandwidth_limit, - migrate_fd_close); + s->file = qemu_fopen_ops_buffered(s, s->bandwidth_limit); DPRINTF("beginning savevm\n"); ret = qemu_savevm_state_begin(s->file, &s->params); diff --git a/migration.h b/migration.h index d6341d66a3..ec022d604f 100644 --- a/migration.h +++ b/migration.h @@ -82,6 +82,7 @@ ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, size_t size); void migrate_fd_put_ready(MigrationState *s); void migrate_fd_wait_for_unfreeze(MigrationState *s); +int migrate_fd_close(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); From 796b4b0f5011e30cffbc57ed5a4ab93c6f5eaab7 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 20 Jul 2012 13:33:53 +0200 Subject: [PATCH 069/160] buffered_file: We can access directly to bandwidth_limit Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- buffered_file.c | 5 ++--- buffered_file.h | 3 +-- migration.c | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 4fca774dd8..43e68b6515 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -222,15 +222,14 @@ static void buffered_rate_tick(void *opaque) buffered_put_buffer(s, NULL, 0, 0); } -QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, - size_t bytes_per_sec) +QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state) { QEMUFileBuffered *s; s = g_malloc0(sizeof(*s)); s->migration_state = migration_state; - s->xfer_limit = bytes_per_sec / 10; + s->xfer_limit = migration_state->bandwidth_limit / 10; s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL, buffered_close, buffered_rate_limit, diff --git a/buffered_file.h b/buffered_file.h index 8a38754146..ef010febfe 100644 --- a/buffered_file.h +++ b/buffered_file.h @@ -17,7 +17,6 @@ #include "hw/hw.h" #include "migration.h" -QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state, - size_t xfer_limit); +QEMUFile *qemu_fopen_ops_buffered(MigrationState *migration_state); #endif diff --git a/migration.c b/migration.c index f647a3fccb..ea21dc40e1 100644 --- a/migration.c +++ b/migration.c @@ -429,7 +429,7 @@ void migrate_fd_connect(MigrationState *s) int ret; s->state = MIG_STATE_ACTIVE; - s->file = qemu_fopen_ops_buffered(s, s->bandwidth_limit); + s->file = qemu_fopen_ops_buffered(s); DPRINTF("beginning savevm\n"); ret = qemu_savevm_state_begin(s->file, &s->params); From 3d6dff316f20137a87e099c30136358df029c0f6 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 24 Aug 2012 11:45:31 +0200 Subject: [PATCH 070/160] buffered_file: callers of buffered_flush() already check for errors Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- buffered_file.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 43e68b6515..747d672b43 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -61,13 +61,6 @@ static void buffered_append(QEMUFileBuffered *s, static void buffered_flush(QEMUFileBuffered *s) { size_t offset = 0; - int error; - - error = qemu_file_get_error(s->file); - if (error != 0) { - DPRINTF("flush when error, bailing: %s\n", strerror(-error)); - return; - } DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); From d2dbc8e6a95a9f66f886c35db42786efc906c777 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 24 Aug 2012 12:43:04 +0200 Subject: [PATCH 071/160] buffered_file: make buffered_flush return the error code Or the amount of data written if there is no error. Adjust all callers. Signed-off-by: Juan Quintela --- buffered_file.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 747d672b43..d3bc160835 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -58,26 +58,26 @@ static void buffered_append(QEMUFileBuffered *s, s->buffer_size += size; } -static void buffered_flush(QEMUFileBuffered *s) +static ssize_t buffered_flush(QEMUFileBuffered *s) { size_t offset = 0; + ssize_t ret = 0; DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { - ssize_t ret; ret = migrate_fd_put_buffer(s->migration_state, s->buffer + offset, s->buffer_size - offset); if (ret == -EAGAIN) { DPRINTF("backend not ready, freezing\n"); + ret = 0; s->freeze_output = 1; break; } if (ret <= 0) { DPRINTF("error flushing data, %zd\n", ret); - qemu_file_set_error(s->file, ret); break; } else { DPRINTF("flushed %zd byte(s)\n", ret); @@ -89,12 +89,17 @@ static void buffered_flush(QEMUFileBuffered *s) DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size); memmove(s->buffer, s->buffer + offset, s->buffer_size - offset); s->buffer_size -= offset; + + if (ret < 0) { + return ret; + } + return offset; } static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { QEMUFileBuffered *s = opaque; - int error; + ssize_t error; DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); @@ -112,7 +117,13 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in buffered_append(s, buf, size); } - buffered_flush(s); + error = buffered_flush(s); + if (error < 0) { + DPRINTF("buffered flush error. bailing: %s\n", strerror(-error)); + qemu_file_set_error(s->file, error); + + return error; + } if (pos == 0 && size == 0) { DPRINTF("file is ready\n"); @@ -128,19 +139,25 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in static int buffered_close(void *opaque) { QEMUFileBuffered *s = opaque; - int ret; + ssize_t ret = 0; + int ret2; DPRINTF("closing\n"); s->xfer_limit = INT_MAX; while (!qemu_file_get_error(s->file) && s->buffer_size) { - buffered_flush(s); + ret = buffered_flush(s); + if (ret < 0) { + break; + } if (s->freeze_output) migrate_fd_wait_for_unfreeze(s->migration_state); } - ret = migrate_fd_close(s->migration_state); - + ret2 = migrate_fd_close(s->migration_state); + if (ret >= 0) { + ret = ret2; + } qemu_del_timer(s->timer); qemu_free_timer(s->timer); g_free(s->buffer); From 9499743f36169cf7d974640f123bc29836f75a2d Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 24 Aug 2012 12:51:48 +0200 Subject: [PATCH 072/160] migration: make migrate_fd_wait_for_unfreeze() return errors Adjust all callers Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- buffered_file.c | 8 ++++++-- migration.c | 7 ++++--- migration.h | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index d3bc160835..77928f02c1 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -150,8 +150,12 @@ static int buffered_close(void *opaque) if (ret < 0) { break; } - if (s->freeze_output) - migrate_fd_wait_for_unfreeze(s->migration_state); + if (s->freeze_output) { + ret = migrate_fd_wait_for_unfreeze(s->migration_state); + if (ret < 0) { + break; + } + } } ret2 = migrate_fd_close(s->migration_state); diff --git a/migration.c b/migration.c index ea21dc40e1..2c93951423 100644 --- a/migration.c +++ b/migration.c @@ -370,13 +370,13 @@ static void migrate_fd_cancel(MigrationState *s) migrate_fd_cleanup(s); } -void migrate_fd_wait_for_unfreeze(MigrationState *s) +int migrate_fd_wait_for_unfreeze(MigrationState *s) { int ret; DPRINTF("wait for unfreeze\n"); if (s->state != MIG_STATE_ACTIVE) - return; + return -EINVAL; do { fd_set wfds; @@ -388,8 +388,9 @@ void migrate_fd_wait_for_unfreeze(MigrationState *s) } while (ret == -1 && (s->get_error(s)) == EINTR); if (ret == -1) { - qemu_file_set_error(s->file, -s->get_error(s)); + return -s->get_error(s); } + return 0; } int migrate_fd_close(MigrationState *s) diff --git a/migration.h b/migration.h index ec022d604f..1c3e9b750e 100644 --- a/migration.h +++ b/migration.h @@ -81,7 +81,7 @@ void migrate_fd_connect(MigrationState *s); ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, size_t size); void migrate_fd_put_ready(MigrationState *s); -void migrate_fd_wait_for_unfreeze(MigrationState *s); +int migrate_fd_wait_for_unfreeze(MigrationState *s); int migrate_fd_close(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); From ffbfc74d1eb822ed086503a6c24413617c19d31a Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 28 Aug 2012 13:54:06 +0200 Subject: [PATCH 073/160] savevm: unexport qemu_fflush It is not used outside of savevm.c Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- qemu-file.h | 1 - savevm.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/qemu-file.h b/qemu-file.h index 31b83f6bb3..d8487cd881 100644 --- a/qemu-file.h +++ b/qemu-file.h @@ -71,7 +71,6 @@ QEMUFile *qemu_fopen_socket(int fd); QEMUFile *qemu_popen(FILE *popen_file, const char *mode); QEMUFile *qemu_popen_cmd(const char *command, const char *mode); int qemu_stdio_fd(QEMUFile *f); -void qemu_fflush(QEMUFile *f); int qemu_fclose(QEMUFile *f); void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); void qemu_put_byte(QEMUFile *f, int v); diff --git a/savevm.c b/savevm.c index 31fd2e0ad3..cf5f9477df 100644 --- a/savevm.c +++ b/savevm.c @@ -461,7 +461,7 @@ static void qemu_file_set_if_error(QEMUFile *f, int ret) * * In case of error, last_error is set. */ -void qemu_fflush(QEMUFile *f) +static void qemu_fflush(QEMUFile *f) { if (!f->put_buffer) return; From e398d61b4777125f32a99fa49519c5edbb00809b Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 19:03:09 +0200 Subject: [PATCH 074/160] virtio-net: use qemu_get_buffer() in a temp buffer qemu_fseek() is known to be wrong. Would be removed on the next commit. This code should never been used (value has been MAC_TABLE_ENTRIES since 2009). Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- hw/virtio-net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 8342391d90..50ba728c02 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -921,7 +921,9 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); } else if (n->mac_table.in_use) { - qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR); + uint8_t *buf = g_malloc0(n->mac_table.in_use); + qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN); + g_free(buf); n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; n->mac_table.in_use = 0; } From e5ae97cee4c0ecd252991aa868c6e233ef8c8f35 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 19:04:47 +0200 Subject: [PATCH 075/160] savevm: Remove qemu_fseek() It has no users, and is only half implemented. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- qemu-file.h | 1 - savevm.c | 21 --------------------- 2 files changed, 22 deletions(-) diff --git a/qemu-file.h b/qemu-file.h index d8487cd881..7fe7274d1f 100644 --- a/qemu-file.h +++ b/qemu-file.h @@ -232,6 +232,5 @@ static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv) } int64_t qemu_ftell(QEMUFile *f); -int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); #endif diff --git a/savevm.c b/savevm.c index cf5f9477df..8a785fc783 100644 --- a/savevm.c +++ b/savevm.c @@ -676,27 +676,6 @@ int64_t qemu_ftell(QEMUFile *f) return f->buf_offset - f->buf_size + f->buf_index; } -int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence) -{ - if (whence == SEEK_SET) { - /* nothing to do */ - } else if (whence == SEEK_CUR) { - pos += qemu_ftell(f); - } else { - /* SEEK_END not supported */ - return -1; - } - if (f->put_buffer) { - qemu_fflush(f); - f->buf_offset = pos; - } else { - f->buf_offset = pos; - f->buf_index = 0; - f->buf_size = 0; - } - return pos; -} - int qemu_file_rate_limit(QEMUFile *f) { if (f->rate_limit) From 7311bea33fab3bed02e9fca8b36fd6234a3a7cb9 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 19:08:59 +0200 Subject: [PATCH 076/160] savevm: make qemu_fflush() return an error code Adjust all the callers. We moved the set of last_error from inside qemu_fflush() to all the callers. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- savevm.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/savevm.c b/savevm.c index 8a785fc783..0705cd73bc 100644 --- a/savevm.c +++ b/savevm.c @@ -459,23 +459,22 @@ static void qemu_file_set_if_error(QEMUFile *f, int ret) /** Flushes QEMUFile buffer * - * In case of error, last_error is set. */ -static void qemu_fflush(QEMUFile *f) +static int qemu_fflush(QEMUFile *f) { + int ret = 0; + if (!f->put_buffer) - return; + return 0; if (f->is_write && f->buf_index > 0) { - int len; - - len = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); - if (len > 0) + ret = f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); + if (ret >= 0) { f->buf_offset += f->buf_index; - else - qemu_file_set_error(f, -EINVAL); + } f->buf_index = 0; } + return ret; } static void qemu_fill_buffer(QEMUFile *f) @@ -533,9 +532,13 @@ static int qemu_fclose_internal(QEMUFile *f) */ int qemu_fclose(QEMUFile *f) { - int ret; - qemu_fflush(f); - ret = qemu_fclose_internal(f); + int ret, ret2; + ret = qemu_fflush(f); + ret2 = qemu_fclose_internal(f); + + if (ret >= 0) { + ret = ret2; + } /* If any error was spotted before closing, we should report it * instead of the close() return value. */ @@ -570,8 +573,10 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) f->buf_index += l; buf += l; size -= l; - if (f->buf_index >= IO_BUF_SIZE) - qemu_fflush(f); + if (f->buf_index >= IO_BUF_SIZE) { + int ret = qemu_fflush(f); + qemu_file_set_if_error(f, ret); + } } } @@ -585,8 +590,10 @@ void qemu_put_byte(QEMUFile *f, int v) f->buf[f->buf_index++] = v; f->is_write = 1; - if (f->buf_index >= IO_BUF_SIZE) - qemu_fflush(f); + if (f->buf_index >= IO_BUF_SIZE) { + int ret = qemu_fflush(f); + qemu_file_set_if_error(f, ret); + } } static void qemu_file_skip(QEMUFile *f, int size) From 29eee86f312a7351b0e694e48b435084355630f7 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 19:14:54 +0200 Subject: [PATCH 077/160] savevm: unfold qemu_fclose_internal() It was used only one, and was only one if. It makes error handling saner. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- savevm.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/savevm.c b/savevm.c index 0705cd73bc..ba69b44c8b 100644 --- a/savevm.c +++ b/savevm.c @@ -506,22 +506,6 @@ static void qemu_fill_buffer(QEMUFile *f) qemu_file_set_error(f, len); } -/** Calls close function and set last_error if needed - * - * Internal function. qemu_fflush() must be called before this. - * - * Returns f->close() return value, or 0 if close function is not set. - */ -static int qemu_fclose_internal(QEMUFile *f) -{ - int ret = 0; - if (f->close) { - ret = f->close(f->opaque); - qemu_file_set_if_error(f, ret); - } - return ret; -} - /** Closes the file * * Returns negative error value if any error happened on previous operations or @@ -532,12 +516,14 @@ static int qemu_fclose_internal(QEMUFile *f) */ int qemu_fclose(QEMUFile *f) { - int ret, ret2; + int ret; ret = qemu_fflush(f); - ret2 = qemu_fclose_internal(f); - if (ret >= 0) { - ret = ret2; + if (f->close) { + int ret2 = f->close(f->opaque); + if (ret >= 0) { + ret = ret2; + } } /* If any error was spotted before closing, we should report it * instead of the close() return value. From 3aee4be1de440de08ef68b936e51e028a9f6f6ab Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 19:16:56 +0200 Subject: [PATCH 078/160] savevm: unexport qemu_ftell() It was unused out of savevm.c. Signed-off-by: Juan Quintela --- qemu-file.h | 3 --- savevm.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/qemu-file.h b/qemu-file.h index 7fe7274d1f..289849a789 100644 --- a/qemu-file.h +++ b/qemu-file.h @@ -230,7 +230,4 @@ static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv) { qemu_get_be64s(f, (uint64_t *)pv); } - -int64_t qemu_ftell(QEMUFile *f); - #endif diff --git a/savevm.c b/savevm.c index ba69b44c8b..32fe7a2067 100644 --- a/savevm.c +++ b/savevm.c @@ -664,7 +664,7 @@ int qemu_get_byte(QEMUFile *f) return result; } -int64_t qemu_ftell(QEMUFile *f) +static int64_t qemu_ftell(QEMUFile *f) { return f->buf_offset - f->buf_size + f->buf_index; } From 02c4a0511bc58b005511c94055a55b1e19c6be71 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 19:36:26 +0200 Subject: [PATCH 079/160] savevm: make qemu_fill_buffer() be consistent It was setting last_error directly once, and with the helper the other time. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- savevm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/savevm.c b/savevm.c index 32fe7a2067..943d100e18 100644 --- a/savevm.c +++ b/savevm.c @@ -501,7 +501,7 @@ static void qemu_fill_buffer(QEMUFile *f) f->buf_size += len; f->buf_offset += len; } else if (len == 0) { - f->last_error = -EIO; + qemu_file_set_error(f, -EIO); } else if (len != -EAGAIN) qemu_file_set_error(f, len); } From c10682cb031525a8bdf3999ef6a033777929d304 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 19:43:39 +0200 Subject: [PATCH 080/160] savevm: Only qemu_fflush() can generate errors Move the error check to the beggining of the callers. Once this is fixed qemu_file_set_if_error() is not used anymore, so remove it. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- savevm.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/savevm.c b/savevm.c index 943d100e18..e44bede55f 100644 --- a/savevm.c +++ b/savevm.c @@ -445,18 +445,6 @@ void qemu_file_set_error(QEMUFile *f, int ret) f->last_error = ret; } -/** Sets last_error conditionally - * - * Sets last_error only if ret is negative _and_ no error - * was set before. - */ -static void qemu_file_set_if_error(QEMUFile *f, int ret) -{ - if (ret < 0 && !f->last_error) { - qemu_file_set_error(f, ret); - } -} - /** Flushes QEMUFile buffer * */ @@ -544,13 +532,17 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) { int l; - if (!f->last_error && f->is_write == 0 && f->buf_index > 0) { + if (f->last_error) { + return; + } + + if (f->is_write == 0 && f->buf_index > 0) { fprintf(stderr, "Attempted to write to buffer while read buffer is not empty\n"); abort(); } - while (!f->last_error && size > 0) { + while (size > 0) { l = IO_BUF_SIZE - f->buf_index; if (l > size) l = size; @@ -561,14 +553,21 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) size -= l; if (f->buf_index >= IO_BUF_SIZE) { int ret = qemu_fflush(f); - qemu_file_set_if_error(f, ret); + if (ret < 0) { + qemu_file_set_error(f, ret); + break; + } } } } void qemu_put_byte(QEMUFile *f, int v) { - if (!f->last_error && f->is_write == 0 && f->buf_index > 0) { + if (f->last_error) { + return; + } + + if (f->is_write == 0 && f->buf_index > 0) { fprintf(stderr, "Attempted to write to buffer while read buffer is not empty\n"); abort(); @@ -578,7 +577,9 @@ void qemu_put_byte(QEMUFile *f, int v) f->is_write = 1; if (f->buf_index >= IO_BUF_SIZE) { int ret = qemu_fflush(f); - qemu_file_set_if_error(f, ret); + if (ret < 0) { + qemu_file_set_error(f, ret); + } } } From 81fdf640e4b479df75fcedf03fb300018f054bfa Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 19:52:16 +0200 Subject: [PATCH 081/160] buffered_file: buffered_put_buffer() don't need to set last_error Callers on savevm.c:qemu_fflush() will set it. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- buffered_file.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 77928f02c1..ed92df1053 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -120,8 +120,6 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in error = buffered_flush(s); if (error < 0) { DPRINTF("buffered flush error. bailing: %s\n", strerror(-error)); - qemu_file_set_error(s->file, error); - return error; } From 59feec424723c0cacf503670a42d76e7c47167c1 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 20:17:13 +0200 Subject: [PATCH 082/160] block-migration: make flush_blks() return errors This means we don't need to pass through qemu_file to get the errors. Adjust all callers. Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- block-migration.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/block-migration.c b/block-migration.c index ed933017f9..f5ce386450 100644 --- a/block-migration.c +++ b/block-migration.c @@ -444,9 +444,10 @@ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async) return ret; } -static void flush_blks(QEMUFile* f) +static int flush_blks(QEMUFile *f) { BlkMigBlock *blk; + int ret = 0; DPRINTF("%s Enter submitted %d read_done %d transferred %d\n", __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done, @@ -457,7 +458,7 @@ static void flush_blks(QEMUFile* f) break; } if (blk->ret < 0) { - qemu_file_set_error(f, blk->ret); + ret = blk->ret; break; } blk_send(f, blk); @@ -474,6 +475,7 @@ static void flush_blks(QEMUFile* f) DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done, block_mig_state.transferred); + return ret; } static int64_t get_remaining_dirty(void) @@ -555,9 +557,7 @@ static int block_save_setup(QEMUFile *f, void *opaque) /* start track dirty blocks */ set_dirty_tracking(1); - flush_blks(f); - - ret = qemu_file_get_error(f); + ret = flush_blks(f); if (ret) { blk_mig_cleanup(); return ret; @@ -577,9 +577,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque) DPRINTF("Enter save live iterate submitted %d transferred %d\n", block_mig_state.submitted, block_mig_state.transferred); - flush_blks(f); - - ret = qemu_file_get_error(f); + ret = flush_blks(f); if (ret) { blk_mig_cleanup(); return ret; @@ -605,9 +603,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque) } } - flush_blks(f); - - ret = qemu_file_get_error(f); + ret = flush_blks(f); if (ret) { blk_mig_cleanup(); return ret; @@ -625,9 +621,7 @@ static int block_save_complete(QEMUFile *f, void *opaque) DPRINTF("Enter save live complete submitted %d transferred %d\n", block_mig_state.submitted, block_mig_state.transferred); - flush_blks(f); - - ret = qemu_file_get_error(f); + ret = flush_blks(f); if (ret) { blk_mig_cleanup(); return ret; From ceb2bd09a13ea71d06353bf826524df3cf584735 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 21:37:14 +0200 Subject: [PATCH 083/160] block-migration: Switch meaning of return value Make consistent the result of blk_mig_save_dirty_block() and mig_save_device_dirty() Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- block-migration.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/block-migration.c b/block-migration.c index f5ce386450..b47a063834 100644 --- a/block-migration.c +++ b/block-migration.c @@ -429,14 +429,18 @@ error: return 0; } +/* return value: + * 0: too much data for max_downtime + * 1: few enough data for max_downtime +*/ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async) { BlkMigDevState *bmds; - int ret = 0; + int ret = 1; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { - if (mig_save_device_dirty(f, bmds, is_async) == 0) { - ret = 1; + ret = mig_save_device_dirty(f, bmds, is_async); + if (ret == 0) { break; } } @@ -596,7 +600,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque) block_mig_state.bulk_completed = 1; } } else { - if (blk_mig_save_dirty_block(f, 1) == 0) { + if (blk_mig_save_dirty_block(f, 1) != 0) { /* no more dirty blocks */ break; } @@ -633,7 +637,7 @@ static int block_save_complete(QEMUFile *f, void *opaque) all async read completed */ assert(block_mig_state.submitted == 0); - while (blk_mig_save_dirty_block(f, 0) != 0) { + while (blk_mig_save_dirty_block(f, 0) == 0) { /* Do nothing */ } blk_mig_cleanup(); From 43be3a25c931a7f61a76fbfc9d35584cbfc5fb58 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 29 Aug 2012 21:59:22 +0200 Subject: [PATCH 084/160] block-migration: handle errors with the return codes correctly Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- block-migration.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/block-migration.c b/block-migration.c index b47a063834..71b9601e00 100644 --- a/block-migration.c +++ b/block-migration.c @@ -423,10 +423,9 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, error: DPRINTF("Error reading sector %" PRId64 "\n", sector); - qemu_file_set_error(f, ret); g_free(blk->buf); g_free(blk); - return 0; + return ret; } /* return value: @@ -440,7 +439,7 @@ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async) QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { ret = mig_save_device_dirty(f, bmds, is_async); - if (ret == 0) { + if (ret <= 0) { break; } } @@ -600,12 +599,17 @@ static int block_save_iterate(QEMUFile *f, void *opaque) block_mig_state.bulk_completed = 1; } } else { - if (blk_mig_save_dirty_block(f, 1) != 0) { + ret = blk_mig_save_dirty_block(f, 1); + if (ret != 0) { /* no more dirty blocks */ break; } } } + if (ret) { + blk_mig_cleanup(); + return ret; + } ret = flush_blks(f); if (ret) { @@ -637,18 +641,16 @@ static int block_save_complete(QEMUFile *f, void *opaque) all async read completed */ assert(block_mig_state.submitted == 0); - while (blk_mig_save_dirty_block(f, 0) == 0) { - /* Do nothing */ - } + do { + ret = blk_mig_save_dirty_block(f, 0); + } while (ret == 0); + blk_mig_cleanup(); - - /* report completion */ - qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS); - - ret = qemu_file_get_error(f); if (ret) { return ret; } + /* report completion */ + qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS); DPRINTF("Block migration completed\n"); From 6f121ff575e1601d652f3eecf4f9ab1205c12df1 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Thu, 30 Aug 2012 13:37:56 +0200 Subject: [PATCH 085/160] savevm: un-export qemu_file_set_error() Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- qemu-file.h | 1 - savevm.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/qemu-file.h b/qemu-file.h index 289849a789..8dd920790c 100644 --- a/qemu-file.h +++ b/qemu-file.h @@ -103,7 +103,6 @@ int qemu_file_rate_limit(QEMUFile *f); int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); int qemu_file_get_error(QEMUFile *f); -void qemu_file_set_error(QEMUFile *f, int error); /* Try to send any outstanding data. This function is useful when output is * halted due to rate limiting or EAGAIN errors occur as it can be used to diff --git a/savevm.c b/savevm.c index e44bede55f..dee689998b 100644 --- a/savevm.c +++ b/savevm.c @@ -440,7 +440,7 @@ int qemu_file_get_error(QEMUFile *f) return f->last_error; } -void qemu_file_set_error(QEMUFile *f, int ret) +static void qemu_file_set_error(QEMUFile *f, int ret) { f->last_error = ret; } From a2b413512443e67cd58285b8d98b84792a66c710 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 4 Sep 2012 12:45:42 +0200 Subject: [PATCH 086/160] savevm: make qemu_file_put_notify() return errors Signed-off-by: Juan Quintela Reviewed-by: Paolo Bonzini --- migration.c | 5 +++-- qemu-file.h | 2 +- savevm.c | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/migration.c b/migration.c index 2c93951423..62e030487d 100644 --- a/migration.c +++ b/migration.c @@ -287,10 +287,11 @@ static void migrate_fd_completed(MigrationState *s) static void migrate_fd_put_notify(void *opaque) { MigrationState *s = opaque; + int ret; qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); - qemu_file_put_notify(s->file); - if (s->file && qemu_file_get_error(s->file)) { + ret = qemu_file_put_notify(s->file); + if (ret) { migrate_fd_error(s); } } diff --git a/qemu-file.h b/qemu-file.h index 8dd920790c..9c8985b610 100644 --- a/qemu-file.h +++ b/qemu-file.h @@ -107,7 +107,7 @@ int qemu_file_get_error(QEMUFile *f); /* Try to send any outstanding data. This function is useful when output is * halted due to rate limiting or EAGAIN errors occur as it can be used to * resume output. */ -void qemu_file_put_notify(QEMUFile *f); +int qemu_file_put_notify(QEMUFile *f); static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) { diff --git a/savevm.c b/savevm.c index dee689998b..b080d37258 100644 --- a/savevm.c +++ b/savevm.c @@ -523,9 +523,9 @@ int qemu_fclose(QEMUFile *f) return ret; } -void qemu_file_put_notify(QEMUFile *f) +int qemu_file_put_notify(QEMUFile *f) { - f->put_buffer(f->opaque, NULL, 0, 0); + return f->put_buffer(f->opaque, NULL, 0, 0); } void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) From aa723c23147e93fef8475bd80fd29e633378c34d Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Tue, 18 Sep 2012 16:30:11 +0200 Subject: [PATCH 087/160] cpus: create qemu_in_vcpu_thread() Old code used !io_thread to know if a thread was an vcpu or not. That fails when we introduce the iothread. Signed-off-by: Juan Quintela --- cpus.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cpus.c b/cpus.c index 750a76fbc8..191cbf5f6d 100644 --- a/cpus.c +++ b/cpus.c @@ -898,6 +898,11 @@ int qemu_cpu_is_self(void *_env) return qemu_thread_is_self(cpu->thread); } +static bool qemu_in_vcpu_thread(void) +{ + return cpu_single_env && qemu_cpu_is_self(cpu_single_env); +} + void qemu_mutex_lock_iothread(void) { if (!tcg_enabled()) { @@ -943,7 +948,7 @@ void pause_all_vcpus(void) penv = penv->next_cpu; } - if (!qemu_thread_is_self(&io_thread)) { + if (qemu_in_vcpu_thread()) { cpu_stop_current(); if (!kvm_enabled()) { while (penv) { @@ -1060,7 +1065,7 @@ void cpu_stop_current(void) void vm_stop(RunState state) { - if (!qemu_thread_is_self(&io_thread)) { + if (qemu_in_vcpu_thread()) { qemu_system_vmstop_request(state); /* * FIXME: should not return to device code in case From b6348f29d033d5a8a26f633d2ee94362595f32a4 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Tue, 16 Oct 2012 19:15:50 +1000 Subject: [PATCH 088/160] target-arm/translate: Fix RRX operands Instructions that both use the RRX second operand and update CS were incorrect, as the Carry flag was updated too early. An example of such an instruction would be: ands r12,r13,RRX Ands, because of the "s" flag will update the carry flag. But the RRX second operand rotates through the C flag which should happen before the update. Fixed the ordering of the two, the old carry is read by "r13,RRX" before being updated. Signed-off-by: Peter Crosthwaite Reported-by: Vinesh Peringat Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- target-arm/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index c6840b7832..daccb15c23 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -516,10 +516,10 @@ static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags) tcg_gen_rotri_i32(var, var, shift); break; } else { TCGv tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_CF, 31); if (flags) shifter_out_im(var, 0); tcg_gen_shri_i32(var, var, 1); - tcg_gen_shli_i32(tmp, cpu_CF, 31); tcg_gen_or_i32(var, var, tmp); tcg_temp_free_i32(tmp); } From fe3e7f2dc05225cdd2ba40defcd4e2581bebc5e0 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 16 May 2012 12:54:25 +0000 Subject: [PATCH 089/160] ui/vnc: Only report/use TIGHT_PNG encoding if enabled. If TIGHT_PNG is not enabled by the --enable-vnc-png configure flag then do not report to the client that it is supported. Also, since TIGHT_PNG is the same as the TIGHT encoding but with the filter/copy replaced with PNG data, adding it to the supported encodings list when it is disabled will cause the TIGHT encoding to be used even though the client requested TIGHT_PNG. Signed-off-by: Joel Martin Signed-off-by: Stefan Hajnoczi --- ui/vnc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/vnc.c b/ui/vnc.c index 33e6386a6e..66ae93010f 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1806,10 +1806,12 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) vs->features |= VNC_FEATURE_TIGHT_MASK; vs->vnc_encoding = enc; break; +#ifdef CONFIG_VNC_PNG case VNC_ENCODING_TIGHT_PNG: vs->features |= VNC_FEATURE_TIGHT_PNG_MASK; vs->vnc_encoding = enc; break; +#endif case VNC_ENCODING_ZLIB: vs->features |= VNC_FEATURE_ZLIB_MASK; vs->vnc_encoding = enc; From 301592ea6f9c23d233fadc73124301d1305af13c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 12 Oct 2012 18:59:44 +0100 Subject: [PATCH 090/160] targphys.h: Don't define target_phys_addr_t for user-mode emulators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 4be403c accidentally defined the target_phys_addr_t type when building user-mode emulators. Since the type doesn't really make any sense except for system emulators, avoid defining it when building in user mode. Signed-off-by: Peter Maydell Acked-by: Andreas Färber Signed-off-by: Stefan Hajnoczi --- targphys.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/targphys.h b/targphys.h index 08cade9096..50911fd12f 100644 --- a/targphys.h +++ b/targphys.h @@ -3,6 +3,8 @@ #ifndef TARGPHYS_H #define TARGPHYS_H +#ifndef CONFIG_USER_ONLY + #define TARGET_PHYS_ADDR_BITS 64 /* target_phys_addr_t is the type of a physical address (its size can be different from 'target_ulong'). */ @@ -18,3 +20,5 @@ typedef uint64_t target_phys_addr_t; #define TARGET_PRIXPHYS PRIX64 #endif + +#endif From 02c7ac0c0f00ce7fb259a0d68c2590a09adb73f4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 12 Oct 2012 19:07:23 +0100 Subject: [PATCH 091/160] target-arm/neon_helper: Remove obsolete FIXME comment Commit 33ebc29 fixed the bugs in the implementation of VQRSHL, but forgot to remove the FIXME comment... Signed-off-by: Peter Maydell Signed-off-by: Stefan Hajnoczi --- target-arm/neon_helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 8bb5129d6a..9aa920d2ac 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -788,7 +788,6 @@ uint64_t HELPER(neon_qshlu_s64)(CPUARMState *env, uint64_t valop, uint64_t shift return helper_neon_qshl_u64(env, valop, shiftop); } -/* FIXME: This is wrong. */ #define NEON_FN(dest, src1, src2) do { \ int8_t tmp; \ tmp = (int8_t)src2; \ From abab1a0f32e44cb4e6c317e24d1705f182b88cd0 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 15 Oct 2012 07:45:40 +0200 Subject: [PATCH 092/160] configure: Remove unused parameters from main function This modification is required if compiler option -Wunused-parameter is activated. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 353d7889f7..499ad811a0 100755 --- a/configure +++ b/configure @@ -1323,7 +1323,7 @@ if test -z "$cross_prefix" ; then # big/little endian test cat > $TMPC << EOF #include -int main(int argc, char ** argv){ +int main(void) { volatile uint32_t i=0x01234567; return (*((uint8_t*)(&i))) == 0x67; } @@ -2896,7 +2896,7 @@ static int sfaa(int *ptr) return __sync_fetch_and_and(ptr, 0); } -int main(int argc, char **argv) +int main(void) { int val = 42; sfaa(&val); From 08778b398328c4978e6e6bed023e37a3141dba84 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 17 Oct 2012 19:53:50 +0200 Subject: [PATCH 093/160] net/tap-win32: Fix compiler warning caused by missing include statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The include file for net_init_tap was missing: net/tap-win32.c:703: warning: no previous prototype for ‘net_init_tap’ Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- net/tap-win32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/tap-win32.c b/net/tap-win32.c index f1801e22d2..22dad3f8fb 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -29,6 +29,7 @@ #include "tap.h" #include "qemu-common.h" +#include "clients.h" /* net_init_tap */ #include "net.h" #include "sysemu.h" #include "qemu-error.h" From 11f66978618b542986172a62fcd6acfa36c0d178 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 17:40:53 +0100 Subject: [PATCH 094/160] ui/vnc-jobs.c: Fix minor typos in comments Fix some minor typos/grammar errors in comments. Signed-off-by: Peter Maydell Reviewed-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- ui/vnc-jobs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index 087b84d319..3c592b3f3d 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -33,21 +33,21 @@ /* * Locking: * - * There is three levels of locking: + * There are three levels of locking: * - jobs queue lock: for each operation on the queue (push, pop, isEmpty?) * - VncDisplay global lock: mainly used for framebuffer updates to avoid * screen corruption if the framebuffer is updated - * while the worker is doing something. + * while the worker is doing something. * - VncState::output lock: used to make sure the output buffer is not corrupted - * if two threads try to write on it at the same time + * if two threads try to write on it at the same time * - * While the VNC worker thread is working, the VncDisplay global lock is hold - * to avoid screen corruptions (this does not block vnc_refresh() because it - * uses trylock()) but the output lock is not hold because the thread work on + * While the VNC worker thread is working, the VncDisplay global lock is held + * to avoid screen corruption (this does not block vnc_refresh() because it + * uses trylock()) but the output lock is not held because the thread works on * its own output buffer. * When the encoding job is done, the worker thread will hold the output lock * and copy its output buffer in vs->output. -*/ + */ struct VncJobQueue { QemuCond cond; @@ -62,7 +62,7 @@ typedef struct VncJobQueue VncJobQueue; /* * We use a single global queue, but most of the functions are - * already reetrant, so we can easilly add more than one encoding thread + * already reentrant, so we can easily add more than one encoding thread */ static VncJobQueue *queue; From a5b3bdcba8a105439ad3a44121526306c449e100 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 26 Apr 2012 14:17:41 +0200 Subject: [PATCH 095/160] microblaze: Support setting of TLS ptr Signed-off-by: Edgar E. Iglesias --- linux-user/syscall.c | 2 ++ target-microblaze/cpu.h | 1 + 2 files changed, 3 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 471d0605f7..c6a6337426 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6888,6 +6888,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, 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) + ret = get_errno(do_fork(cpu_env, arg1, arg2, arg4, arg6, arg5)); #elif defined(TARGET_S390X) ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg5, arg4)); #else diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 4968c244e8..88430b5057 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -345,6 +345,7 @@ static inline void cpu_clone_regs(CPUMBState *env, target_ulong newsp) static inline void cpu_set_tls(CPUMBState *env, target_ulong newtls) { + env->regs[21] = newtls; } static inline int cpu_interrupts_enabled(CPUMBState *env) From d7dce494769e47c9a1eec6f55578d3acdfab888b Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 26 Apr 2012 14:18:25 +0200 Subject: [PATCH 096/160] microblaze: Update PC before simulating syscall Fixes a clone() emulation bug were the new thread starts at the point of the syscall and thus clones in a loop. Signed-off-by: Edgar E. Iglesias --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index f4bbe697f7..5827ee6a27 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2527,6 +2527,7 @@ void cpu_loop(CPUMBState *env) case EXCP_BREAK: /* Return address is 4 bytes after the call. */ env->regs[14] += 4; + env->sregs[SR_PC] = env->regs[14]; ret = do_syscall(env, env->regs[12], env->regs[5], @@ -2537,7 +2538,6 @@ void cpu_loop(CPUMBState *env) env->regs[10], 0, 0); env->regs[3] = ret; - env->sregs[SR_PC] = env->regs[14]; break; case EXCP_HW_EXCP: env->regs[17] = env->sregs[SR_PC] + 4; From 585f60368f23e6603cf86cfdaeceb89d1169f4b8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 4 Oct 2012 16:22:01 +0100 Subject: [PATCH 097/160] qemu-options.hx: Change from recommending '?' to 'help' Update the -help output and documentation so that it recommends 'help' rather than '?' for the various "list valid values for this option" cases. '?' is deprecated (as it can fail confusingly if not quoted), so it's better to steer users towards 'help'. ('?' still works, for backwards compatibility.) This is the -help option part of the change otherwise done in commit c8057f9, since we are now past release 1.2 and free to change our help text without worrying about breaking libvirt. Signed-off-by: Peter Maydell Reviewed-by: Eric Blake Signed-off-by: Aurelien Jarno --- qemu-options.hx | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 7d97f96928..46f0539182 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -6,10 +6,6 @@ HXCOMM construct option structures, enums and help message for specified HXCOMM architectures. HXCOMM HXCOMM can be used for comments, discarded from both texi and C -HXCOMM TODO : when we are able to change -help output without breaking -HXCOMM libvirt we should update the help options which refer to -cpu ?, -HXCOMM -driver ?, etc to use the preferred -cpu help etc instead. - DEFHEADING(Standard options:) STEXI @table @option @@ -33,7 +29,7 @@ ETEXI DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "-machine [type=]name[,prop[=value][,...]]\n" - " selects emulated machine (-machine ? for list)\n" + " selects emulated machine ('-machine help' for list)\n" " property accel=accel1[:accel2[:...]] selects accelerator\n" " supported accelerators are kvm, xen, tcg (default: tcg)\n" " kernel_irqchip=on|off controls accelerated irqchip support\n" @@ -44,7 +40,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ STEXI @item -machine [type=]@var{name}[,prop=@var{value}[,...]] @findex -machine -Select the emulated machine by @var{name}. Use @code{-machine ?} to list +Select the emulated machine by @var{name}. Use @code{-machine help} to list available machines. Supported machine properties are: @table @option @item accel=@var{accels1}[:@var{accels2}[:...]] @@ -69,11 +65,11 @@ HXCOMM Deprecated by -machine DEF("M", HAS_ARG, QEMU_OPTION_M, "", QEMU_ARCH_ALL) DEF("cpu", HAS_ARG, QEMU_OPTION_cpu, - "-cpu cpu select CPU (-cpu ? for list)\n", QEMU_ARCH_ALL) + "-cpu cpu select CPU ('-cpu help' for list)\n", QEMU_ARCH_ALL) STEXI @item -cpu @var{model} @findex -cpu -Select CPU model (-cpu ? for list and additional feature selection) +Select CPU model (@code{-cpu help} for list and additional feature selection) ETEXI DEF("smp", HAS_ARG, QEMU_OPTION_smp, @@ -463,12 +459,12 @@ ETEXI DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw, "-soundhw c1,... enable audio support\n" " and only specified sound cards (comma separated list)\n" - " use -soundhw ? to get the list of supported cards\n" - " use -soundhw all to enable all of them\n", QEMU_ARCH_ALL) + " use '-soundhw help' to get the list of supported cards\n" + " use '-soundhw all' to enable all of them\n", QEMU_ARCH_ALL) STEXI @item -soundhw @var{card1}[,@var{card2},...] or -soundhw all @findex -soundhw -Enable audio and selected sound hardware. Use ? to print all +Enable audio and selected sound hardware. Use 'help' to print all available sound hardware. @example @@ -477,7 +473,7 @@ qemu-system-i386 -soundhw es1370 disk.img qemu-system-i386 -soundhw ac97 disk.img qemu-system-i386 -soundhw hda disk.img qemu-system-i386 -soundhw all disk.img -qemu-system-i386 -soundhw ? +qemu-system-i386 -soundhw help @end example Note that Linux's i810_audio OSS kernel (for AC97) module might @@ -566,16 +562,16 @@ DEF("device", HAS_ARG, QEMU_OPTION_device, "-device driver[,prop[=value][,...]]\n" " add device (based on driver)\n" " prop=value,... sets driver properties\n" - " use -device ? to print all possible drivers\n" - " use -device driver,? to print all possible properties\n", + " use '-device help' to print all possible drivers\n" + " use '-device driver,help' to print all possible properties\n", QEMU_ARCH_ALL) STEXI @item -device @var{driver}[,@var{prop}[=@var{value}][,...]] @findex -device Add device @var{driver}. @var{prop}=@var{value} sets driver properties. Valid properties depend on the driver. To get help on -possible drivers and properties, use @code{-device ?} and -@code{-device @var{driver},?}. +possible drivers and properties, use @code{-device help} and +@code{-device @var{driver},help}. ETEXI DEFHEADING() @@ -1365,7 +1361,7 @@ Valid values for @var{type} are @code{virtio}, @code{i82551}, @code{i82557b}, @code{i82559er}, @code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139}, @code{e1000}, @code{smc91c111}, @code{lance} and @code{mcf_fec}. -Not all devices are supported on all targets. Use -net nic,model=? +Not all devices are supported on all targets. Use @code{-net nic,model=help} for a list of available devices for your target. @item -netdev user,id=@var{id}[,@var{option}][,@var{option}][,...] @@ -2398,7 +2394,7 @@ Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234 ETEXI DEF("d", HAS_ARG, QEMU_OPTION_d, \ - "-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items)\n", + "-d item1,... output log to /tmp/qemu.log (use '-d help' for a list of log items)\n", QEMU_ARCH_ALL) STEXI @item -d @@ -2533,13 +2529,13 @@ ETEXI DEF("clock", HAS_ARG, QEMU_OPTION_clock, \ "-clock force the use of the given methods for timer alarm.\n" \ - " To see what timers are available use -clock ?\n", + " To see what timers are available use '-clock help'\n", QEMU_ARCH_ALL) STEXI @item -clock @var{method} @findex -clock Force the use of the given methods for timer alarm. To see what timers -are available use -clock ?. +are available use @code{-clock help}. ETEXI HXCOMM Options deprecated by -rtc @@ -2608,7 +2604,7 @@ watchdog with a single timer, or @code{i6300esb} (Intel 6300ESB I/O controller hub) which is a much more featureful PCI-based dual-timer watchdog. Choose a model for which your guest has drivers. -Use @code{-watchdog ?} to list available hardware models. Only one +Use @code{-watchdog help} to list available hardware models. Only one watchdog can be enabled for a guest. ETEXI From 38f419f35225decdbaea9fe1fd00218f8924ce84 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 17 Oct 2012 19:09:25 +0200 Subject: [PATCH 098/160] configure: Fix CONFIG_QEMU_HELPERDIR generation We need to evaluate $libexecdir in configure, otherwise we literally end up with "${prefix}/libexec" instead of the absolute path as CONFIG_QEMU_HELPERDIR. Signed-off-by: Jan Kiszka Signed-off-by: Aurelien Jarno --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index f9c31f4195..9f33c7d723 100755 --- a/configure +++ b/configure @@ -3200,7 +3200,7 @@ echo "qemu_confdir=$qemu_confdir" >> $config_host_mak echo "qemu_datadir=$qemu_datadir" >> $config_host_mak echo "qemu_docdir=$qemu_docdir" >> $config_host_mak echo "qemu_localstatedir=$local_statedir" >> $config_host_mak -echo "CONFIG_QEMU_HELPERDIR=\"$libexecdir\"" >> $config_host_mak +echo "CONFIG_QEMU_HELPERDIR=\"`eval echo $libexecdir`\"" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak if test "$debug_tcg" = "yes" ; then From 1cd0f8ce731574afbf219b7ae2b938f305b77e86 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 7 Oct 2012 18:08:49 +0200 Subject: [PATCH 099/160] MAINTAINERS: Update email address for Stefan Hajnoczi Switch to my new work email address from which I am contributing. Signed-off-by: Stefan Hajnoczi Signed-off-by: Aurelien Jarno --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index f1f925007e..8f5681fd64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -641,7 +641,7 @@ F: monitor.c Network device layer M: Anthony Liguori -M: Stefan Hajnoczi +M: Stefan Hajnoczi S: Maintained F: net/ T: git git://github.com/stefanha/qemu.git net @@ -661,7 +661,7 @@ F: slirp/ T: git git://git.kiszka.org/qemu.git queues/slirp Tracing -M: Stefan Hajnoczi +M: Stefan Hajnoczi S: Maintained F: trace/ F: scripts/tracetool.py From 42a159284570b6fbb0b097e18c7590c094a5188c Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Mon, 8 Oct 2012 15:45:49 -0500 Subject: [PATCH 100/160] tci: fix build breakage for target-sparc commit c28ae41 introduced GETPC() usage for sparc, which is currently not defined when building with --enable-tcg-interpreter. Add sparc to the list of targets we selectively define GETPC() for. Signed-off-by: Michael Roth Reviewed-by: Stefan Weil Signed-off-by: Aurelien Jarno --- exec-all.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exec-all.h b/exec-all.h index 6516da071d..f7f649ee61 100644 --- a/exec-all.h +++ b/exec-all.h @@ -296,7 +296,8 @@ extern int tb_invalidated_flag; #if defined(CONFIG_TCG_INTERPRETER) /* Alpha and SH4 user mode emulations and Softmmu call GETPC(). For all others, GETPC remains undefined (which makes TCI a little faster. */ -# if defined(CONFIG_SOFTMMU) || defined(TARGET_ALPHA) || defined(TARGET_SH4) +# if defined(CONFIG_SOFTMMU) || defined(TARGET_ALPHA) || defined(TARGET_SH4) \ + || defined(TARGET_SPARC) extern uintptr_t tci_tb_ptr; # define GETPC() tci_tb_ptr # endif From 7748b8cb1d100105753a80976d2d02ab107d8107 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 16 Sep 2012 16:07:13 -0400 Subject: [PATCH 101/160] allow make {dist, }clean work w/out configure There's no reason to require configure to run before running a clean target, so check MAKECMDGOALS before. Signed-off-by: Mike Frysinger Signed-off-by: Aurelien Jarno --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index a9c22bf1d9..88285a474b 100644 --- a/Makefile +++ b/Makefile @@ -14,9 +14,11 @@ config-host.mak: $(SRC_PATH)/configure @sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh else config-host.mak: +ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail)) @echo "Please call configure before running make!" @exit 1 endif +endif GENERATED_HEADERS = config-host.h trace.h qemu-options.def ifeq ($(TRACE_BACKEND),dtrace) @@ -403,7 +405,9 @@ qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \ # Add a dependency on the generated files, so that they are always # rebuilt before other object files +ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail)) Makefile: $(GENERATED_HEADERS) +endif # Include automatically generated dependency files # Dependencies in Makefile.objs files come from our recursive subdir rules From f62cb1b6ddc2c82694abac23ab5eeddd85800074 Mon Sep 17 00:00:00 2001 From: Catalin Patulea Date: Tue, 16 Oct 2012 16:00:23 -0400 Subject: [PATCH 102/160] tests/tcg: fix build This broke when the tests were moved from tests/ to tests/tcg/. On x86_64 host/i386-linux-user non-kvm guest, test-i386 and test-mmap are broken, but at least they build. To build/run the tests: $ cd $BUILD_PATH/tests/tcg $ SRC_PATH=path/to/qemu make Signed-off-by: Catalin Patulea Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- tests/tcg/Makefile | 18 +++++++++++------- tests/tcg/linux-test.c | 2 ++ tests/tcg/test-i386.c | 3 ++- tests/tcg/test_path.c | 13 +++++++------ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/tests/tcg/Makefile b/tests/tcg/Makefile index 15e36a208c..80b1a4b529 100644 --- a/tests/tcg/Makefile +++ b/tests/tcg/Makefile @@ -1,13 +1,13 @@ --include ../config-host.mak +-include ../../config-host.mak -include $(SRC_PATH)/rules.mak -$(call set-vpath, $(SRC_PATH)/tests) +$(call set-vpath, $(SRC_PATH)/tests/tcg) -QEMU=../i386-linux-user/qemu-i386 -QEMU_X86_64=../x86_64-linux-user/qemu-x86_64 +QEMU=../../i386-linux-user/qemu-i386 +QEMU_X86_64=../../x86_64-linux-user/qemu-x86_64 CC_X86_64=$(CC_I386) -m64 -QEMU_INCLUDES += -I.. +QEMU_INCLUDES += -I../.. CFLAGS=-Wall -O2 -g -fno-strict-aliasing #CFLAGS+=-msse2 LDFLAGS= @@ -36,6 +36,7 @@ TESTS += $(I386_TESTS) endif all: $(patsubst %,run-%,$(TESTS)) +test: all # rules to run tests @@ -74,7 +75,10 @@ run-test_path: test_path # rules to compile tests test_path: test_path.o + $(CC_I386) $(LDFLAGS) -o $@ $^ $(LIBS) + test_path.o: test_path.c + $(CC_I386) $(QEMU_INCLUDES) $(GLIB_CFLAGS) $(CFLAGS) -c -o $@ $^ hello-i386: hello-i386.c $(CC_I386) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $< @@ -86,12 +90,12 @@ testthread: testthread.c # i386/x86_64 emulation test (test various opcodes) */ test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \ test-i386.h test-i386-shift.h test-i386-muldiv.h - $(CC_I386) $(CFLAGS) $(LDFLAGS) -o $@ \ + $(CC_I386) $(QEMU_INCLUDES) $(CFLAGS) $(LDFLAGS) -o $@ \ $(. */ +#define _GNU_SOURCE #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #define TESTPATH "/tmp/linux-test.tmp" #define TESTPORT 7654 diff --git a/tests/tcg/test-i386.c b/tests/tcg/test-i386.c index 8e64bbaf38..64d929e482 100644 --- a/tests/tcg/test-i386.c +++ b/tests/tcg/test-i386.c @@ -17,6 +17,7 @@ * along with this program; if not, see . */ #define _GNU_SOURCE +#include "compiler.h" #include #include #include @@ -1827,7 +1828,7 @@ void test_exceptions(void) printf("lock nop exception:\n"); if (setjmp(jmp_env) == 0) { /* now execute an invalid instruction */ - asm volatile("lock nop"); + asm volatile(".byte 0xf0, 0x90"); /* lock nop */ } printf("INT exception:\n"); diff --git a/tests/tcg/test_path.c b/tests/tcg/test_path.c index 7265a9445d..a064eea8fb 100644 --- a/tests/tcg/test_path.c +++ b/tests/tcg/test_path.c @@ -1,11 +1,12 @@ /* Test path override code */ -#include "../config-host.h" -#include "../qemu-malloc.c" -#include "../cutils.c" -#include "../path.c" -#include "../trace.c" +#define _GNU_SOURCE +#include "config-host.h" +#include "iov.c" +#include "cutils.c" +#include "path.c" +#include "trace.c" #ifdef CONFIG_TRACE_SIMPLE -#include "../simpletrace.c" +#include "../trace/simple.c" #endif #include From 0d0302e2033087ebcd0bcaa2ac1a79452f86d2a7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 15 Oct 2012 08:02:54 +0200 Subject: [PATCH 103/160] vga: fix indention Signed-off-by: Gerd Hoffmann Signed-off-by: Blue Swirl --- hw/vga-pci.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 996d47f23a..5f55f361a2 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -48,25 +48,25 @@ static const VMStateDescription vmstate_vga_pci = { static int pci_std_vga_initfn(PCIDevice *dev) { - PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); - VGACommonState *s = &d->vga; + PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); + VGACommonState *s = &d->vga; - // vga + console init - vga_common_init(s); - vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true); + /* vga + console init */ + vga_common_init(s); + vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true); - s->ds = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, s); + s->ds = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, s); - /* XXX: VGA_RAM_SIZE must be a power of two */ - pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); + /* XXX: VGA_RAM_SIZE must be a power of two */ + pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); - if (!dev->rom_bar) { - /* compatibility with pc-0.13 and older */ - vga_init_vbe(s, pci_address_space(dev)); - } + if (!dev->rom_bar) { + /* compatibility with pc-0.13 and older */ + vga_init_vbe(s, pci_address_space(dev)); + } - return 0; + return 0; } static Property vga_pci_properties[] = { From 803ff052b69c888df3d21e199626a5ef6e3ccf12 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 15 Oct 2012 08:02:55 +0200 Subject: [PATCH 104/160] vga: add mmio bar to standard vga This patch adds a mmio bar to the qemu standard vga which allows to access the standard vga registers and bochs dispi interface registers via mmio. Cc: Benjamin Herrenschmidt Signed-off-by: Gerd Hoffmann Signed-off-by: Blue Swirl --- hw/pc_piix.c | 4 ++ hw/vga-pci.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/vga.c | 6 +-- hw/vga_int.h | 6 +++ 4 files changed, 121 insertions(+), 3 deletions(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 82364ab0d5..5bd4572d47 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -379,6 +379,10 @@ static QEMUMachine pc_machine_v1_3 = { .driver = "qxl-vga",\ .property = "revision",\ .value = stringify(3),\ + },{\ + .driver = "VGA",\ + .property = "mmio",\ + .value = "off",\ } static QEMUMachine pc_machine_v1_2 = { diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 5f55f361a2..f7d0256e87 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -29,9 +29,23 @@ #include "qemu-timer.h" #include "loader.h" +#define PCI_VGA_IOPORT_OFFSET 0x400 +#define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0) +#define PCI_VGA_BOCHS_OFFSET 0x500 +#define PCI_VGA_BOCHS_SIZE (0x0b * 2) +#define PCI_VGA_MMIO_SIZE 0x1000 + +enum vga_pci_flags { + PCI_VGA_FLAG_ENABLE_MMIO = 1, +}; + typedef struct PCIVGAState { PCIDevice dev; VGACommonState vga; + uint32_t flags; + MemoryRegion mmio; + MemoryRegion ioport; + MemoryRegion bochs; } PCIVGAState; static const VMStateDescription vmstate_vga_pci = { @@ -46,6 +60,84 @@ static const VMStateDescription vmstate_vga_pci = { } }; +static uint64_t pci_vga_ioport_read(void *ptr, target_phys_addr_t addr, + unsigned size) +{ + PCIVGAState *d = ptr; + uint64_t ret = 0; + + switch (size) { + case 1: + ret = vga_ioport_read(&d->vga, addr); + break; + case 2: + ret = vga_ioport_read(&d->vga, addr); + ret |= vga_ioport_read(&d->vga, addr+1) << 8; + break; + } + return ret; +} + +static void pci_vga_ioport_write(void *ptr, target_phys_addr_t addr, + uint64_t val, unsigned size) +{ + PCIVGAState *d = ptr; + switch (size) { + case 1: + vga_ioport_write(&d->vga, addr, val); + break; + case 2: + /* + * Update bytes in little endian order. Allows to update + * indexed registers with a single word write because the + * index byte is updated first. + */ + vga_ioport_write(&d->vga, addr, val & 0xff); + vga_ioport_write(&d->vga, addr+1, (val >> 8) & 0xff); + break; + } +} + +static const MemoryRegionOps pci_vga_ioport_ops = { + .read = pci_vga_ioport_read, + .write = pci_vga_ioport_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t pci_vga_bochs_read(void *ptr, target_phys_addr_t addr, + unsigned size) +{ + PCIVGAState *d = ptr; + int index = addr >> 1; + + vbe_ioport_write_index(&d->vga, 0, index); + return vbe_ioport_read_data(&d->vga, 0); +} + +static void pci_vga_bochs_write(void *ptr, target_phys_addr_t addr, + uint64_t val, unsigned size) +{ + PCIVGAState *d = ptr; + int index = addr >> 1; + + vbe_ioport_write_index(&d->vga, 0, index); + vbe_ioport_write_data(&d->vga, 0, val); +} + +static const MemoryRegionOps pci_vga_bochs_ops = { + .read = pci_vga_bochs_read, + .write = pci_vga_bochs_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 2, + .impl.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static int pci_std_vga_initfn(PCIDevice *dev) { PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev); @@ -61,6 +153,21 @@ static int pci_std_vga_initfn(PCIDevice *dev) /* XXX: VGA_RAM_SIZE must be a power of two */ pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); + /* mmio bar for vga register access */ + if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) { + memory_region_init(&d->mmio, "vga.mmio", 4096); + memory_region_init_io(&d->ioport, &pci_vga_ioport_ops, d, + "vga ioports remapped", PCI_VGA_IOPORT_SIZE); + memory_region_init_io(&d->bochs, &pci_vga_bochs_ops, d, + "bochs dispi interface", PCI_VGA_BOCHS_SIZE); + + memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET, + &d->ioport); + memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET, + &d->bochs); + pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); + } + if (!dev->rom_bar) { /* compatibility with pc-0.13 and older */ vga_init_vbe(s, pci_address_space(dev)); @@ -71,6 +178,7 @@ static int pci_std_vga_initfn(PCIDevice *dev) static Property vga_pci_properties[] = { DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16), + DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/vga.c b/hw/vga.c index afaef0d711..6afe48ce58 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -591,7 +591,7 @@ static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) return val; } -static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) +uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) { VGACommonState *s = opaque; uint32_t val; @@ -627,13 +627,13 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) return val; } -static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) +void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) { VGACommonState *s = opaque; s->vbe_index = val; } -static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) +void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) { VGACommonState *s = opaque; diff --git a/hw/vga_int.h b/hw/vga_int.h index 330a32f77d..5b68490301 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -208,7 +208,13 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2); void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp); int vga_ioport_invalid(VGACommonState *s, uint32_t addr); + +#ifdef CONFIG_BOCHS_VBE void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space); +uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr); +void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val); +void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val); +#endif extern const uint8_t sr_mask[8]; extern const uint8_t gr_mask[16]; From cc22824860a18e9e073496396b1cfc860d010a26 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 15 Oct 2012 08:02:56 +0200 Subject: [PATCH 105/160] vga: add specs for standard vga Signed-off-by: Gerd Hoffmann Signed-off-by: Blue Swirl --- docs/specs/standard-vga.txt | 64 +++++++++++++++++++++++++++++++++++++ hw/vga-isa.c | 2 ++ hw/vga-pci.c | 2 ++ 3 files changed, 68 insertions(+) create mode 100644 docs/specs/standard-vga.txt diff --git a/docs/specs/standard-vga.txt b/docs/specs/standard-vga.txt new file mode 100644 index 0000000000..1cecccd469 --- /dev/null +++ b/docs/specs/standard-vga.txt @@ -0,0 +1,64 @@ + +QEMU Standard VGA +================= + +Exists in two variants, for isa and pci. + +command line switches: + -vga std [ picks isa for -M isapc, otherwise pci ] + -device VGA [ pci variant ] + -device isa-vga [ isa variant ] + + +PCI spec +-------- + +Applies to the pci variant only for obvious reasons. + +PCI ID: 1234:1111 + +PCI Region 0: + Framebuffer memory, 16 MB in size (by default). + Size is tunable via vga_mem_mb property. + +PCI Region 1: + Reserved (so we have the option to make the framebuffer bar 64bit). + +PCI Region 2: + MMIO bar, 4096 bytes in size (qemu 1.3+) + +PCI ROM Region: + Holds the vgabios (qemu 0.14+). + + +IO ports used +------------- + +03c0 - 03df : standard vga ports +01ce : bochs vbe interface index port +01cf : bochs vbe interface data port + + +Memory regions used +------------------- + +0xe0000000 : Framebuffer memory, isa variant only. + +The pci variant used to mirror the framebuffer bar here, qemu 0.14+ +stops doing that (except when in -M pc-$old compat mode). + + +MMIO area spec +-------------- + +Likewise applies to the pci variant only for obvious reasons. + +0000 - 03ff : reserved, for possible virtio extension. +0400 - 041f : vga ioports (0x3c0 -> 0x3df), remapped 1:1. + word access is supported, bytes are written + in little endia order (aka index port first), + so indexed registers can be updated with a + single mmio write (and thus only one vmexit). +0500 - 0515 : bochs dispi interface registers, mapped flat + without index/data ports. Use (index << 1) + as offset for (16bit) register access. diff --git a/hw/vga-isa.c b/hw/vga-isa.c index d2904737bc..046602b3d2 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -1,6 +1,8 @@ /* * QEMU ISA VGA Emulator. * + * see docs/specs/standard-vga.txt for virtual hardware specs. + * * Copyright (c) 2003 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/hw/vga-pci.c b/hw/vga-pci.c index f7d0256e87..5c4daee397 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -1,6 +1,8 @@ /* * QEMU PCI VGA Emulator. * + * see docs/specs/standard-vga.txt for virtual hardware specs. + * * Copyright (c) 2003 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy From a96d8bea8e23473bd5b4b4111ba9187fcb976865 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 15 Oct 2012 08:02:57 +0200 Subject: [PATCH 106/160] vga: remove CONFIG_BOCHS_VBE Signed-off-by: Gerd Hoffmann Signed-off-by: Blue Swirl --- hw/vga.c | 34 +++++----------------------------- hw/vga_int.h | 28 +++++++--------------------- 2 files changed, 12 insertions(+), 50 deletions(-) diff --git a/hw/vga.c b/hw/vga.c index 6afe48ce58..a07a6fb1ca 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -582,7 +582,6 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -#ifdef CONFIG_BOCHS_VBE static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) { VGACommonState *s = opaque; @@ -784,7 +783,6 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) } } } -#endif /* called for accesses between 0xa0000 and 0xc0000 */ uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr) @@ -1129,14 +1127,12 @@ static void vga_get_offsets(VGACommonState *s, uint32_t *pline_compare) { uint32_t start_addr, line_offset, line_compare; -#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { line_offset = s->vbe_line_offset; start_addr = s->vbe_start_addr; line_compare = 65535; - } else -#endif - { + } else { /* compute line_offset in bytes */ line_offset = s->cr[VGA_CRTC_OFFSET]; line_offset <<= 3; @@ -1572,12 +1568,10 @@ static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_ static int vga_get_bpp(VGACommonState *s) { int ret; -#ifdef CONFIG_BOCHS_VBE + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; - } else -#endif - { + } else { ret = 0; } return ret; @@ -1587,13 +1581,10 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight) { int width, height; -#ifdef CONFIG_BOCHS_VBE if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; - } else -#endif - { + } else { width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8; height = s->cr[VGA_CRTC_V_DISP_END] | ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) | @@ -1948,14 +1939,12 @@ void vga_common_reset(VGACommonState *s) s->dac_8bit = 0; memset(s->palette, '\0', sizeof(s->palette)); s->bank_offset = 0; -#ifdef CONFIG_BOCHS_VBE s->vbe_index = 0; memset(s->vbe_regs, '\0', sizeof(s->vbe_regs)); s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5; s->vbe_start_addr = 0; s->vbe_line_offset = 0; s->vbe_bank_mask = (s->vram_size >> 16) - 1; -#endif memset(s->font_offsets, '\0', sizeof(s->font_offsets)); s->graphic_mode = -1; /* force full update */ s->shift_control = 0; @@ -2229,13 +2218,11 @@ const VMStateDescription vmstate_vga_common = { VMSTATE_INT32(bank_offset, VGACommonState), VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState), -#ifdef CONFIG_BOCHS_VBE VMSTATE_UINT16(vbe_index, VGACommonState), VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB), VMSTATE_UINT32(vbe_start_addr, VGACommonState), VMSTATE_UINT32(vbe_line_offset, VGACommonState), VMSTATE_UINT32(vbe_bank_mask, VGACommonState), -#endif VMSTATE_END_OF_LIST() } }; @@ -2275,11 +2262,7 @@ void vga_common_init(VGACommonState *s) } s->vram_size_mb = s->vram_size >> 20; -#ifdef CONFIG_BOCHS_VBE s->is_vbe_vmstate = 1; -#else - s->is_vbe_vmstate = 0; -#endif memory_region_init_ram(&s->vram, "vga.vram", s->vram_size); vmstate_register_ram_global(&s->vram); xen_register_framebuffer(&s->vram); @@ -2314,7 +2297,6 @@ static const MemoryRegionPortio vga_portio_list[] = { PORTIO_END_OF_LIST(), }; -#ifdef CONFIG_BOCHS_VBE static const MemoryRegionPortio vbe_portio_list[] = { { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index }, # ifdef TARGET_I386 @@ -2324,7 +2306,6 @@ static const MemoryRegionPortio vbe_portio_list[] = { # endif PORTIO_END_OF_LIST(), }; -#endif /* CONFIG_BOCHS_VBE */ /* Used by both ISA and PCI */ MemoryRegion *vga_init_io(VGACommonState *s, @@ -2334,10 +2315,7 @@ MemoryRegion *vga_init_io(VGACommonState *s, MemoryRegion *vga_mem; *vga_ports = vga_portio_list; - *vbe_ports = NULL; -#ifdef CONFIG_BOCHS_VBE *vbe_ports = vbe_portio_list; -#endif vga_mem = g_malloc(sizeof(*vga_mem)); memory_region_init_io(vga_mem, &vga_mem_ops, s, @@ -2379,7 +2357,6 @@ void vga_init(VGACommonState *s, MemoryRegion *address_space, void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory) { -#ifdef CONFIG_BOCHS_VBE /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region, * so use an alias to avoid double-mapping the same region. */ @@ -2390,7 +2367,6 @@ void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory) VBE_DISPI_LFB_PHYSICAL_ADDRESS, &s->vram_vbe); s->vbe_mapped = 1; -#endif } /********************************************************/ /* vga screen dump */ diff --git a/hw/vga_int.h b/hw/vga_int.h index 5b68490301..144e7d3c35 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -29,9 +29,6 @@ #define ST01_V_RETRACE 0x08 #define ST01_DISP_ENABLE 0x01 -/* bochs VBE support */ -#define CONFIG_BOCHS_VBE - #define VBE_DISPI_MAX_XRES 16000 #define VBE_DISPI_MAX_YRES 12000 #define VBE_DISPI_MAX_BPP 32 @@ -65,21 +62,6 @@ #define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 -#ifdef CONFIG_BOCHS_VBE - -#define VGA_STATE_COMMON_BOCHS_VBE \ - uint16_t vbe_index; \ - uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; \ - uint32_t vbe_start_addr; \ - uint32_t vbe_line_offset; \ - uint32_t vbe_bank_mask; \ - int vbe_mapped; -#else - -#define VGA_STATE_COMMON_BOCHS_VBE - -#endif /* !CONFIG_BOCHS_VBE */ - #define CH_ATTR_SIZE (160 * 100) #define VGA_MAX_HEIGHT 2048 @@ -140,7 +122,13 @@ typedef struct VGACommonState { void (*get_resolution)(struct VGACommonState *s, int *pwidth, int *pheight); - VGA_STATE_COMMON_BOCHS_VBE + /* bochs vbe state */ + uint16_t vbe_index; + uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; + uint32_t vbe_start_addr; + uint32_t vbe_line_offset; + uint32_t vbe_bank_mask; + int vbe_mapped; /* display refresh support */ DisplayState *ds; uint32_t font_offsets[2]; @@ -209,12 +197,10 @@ void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp); int vga_ioport_invalid(VGACommonState *s, uint32_t addr); -#ifdef CONFIG_BOCHS_VBE void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space); uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr); void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val); void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val); -#endif extern const uint8_t sr_mask[8]; extern const uint8_t gr_mask[16]; From 5f072e1f3075bd869e0ace9f2545a85992ac0084 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 15 Oct 2012 17:22:02 -0300 Subject: [PATCH 107/160] create struct for machine initialization arguments This should help us to: - More easily add or remove machine initialization arguments without having to change every single machine init function; - More easily make mechanical changes involving the machine init functions in the future; - Let machine initialization forward the init arguments to other functions more easily. This change was half-mechanical process: first the struct was added with the local ram_size, boot_device, kernel_*, initrd_*, and cpu_model local variable initialization to all functions. Then the compiler helped me locate the local variables that are unused, so they could be removed. Signed-off-by: Blue Swirl --- hw/alpha_dp264.c | 12 +-- hw/an5206.c | 8 +- hw/axis_dev88.c | 9 ++- hw/boards.h | 16 ++-- hw/collie.c | 9 ++- hw/dummy_m68k.c | 8 +- hw/exynos4_boards.c | 16 ++-- hw/gumstix.c | 11 +-- hw/highbank.c | 10 ++- hw/integratorcp.c | 10 ++- hw/kzm.c | 10 ++- hw/leon3.c | 10 +-- hw/lm32_boards.c | 18 ++--- hw/mainstone.c | 10 ++- hw/mcf5208.c | 8 +- hw/milkymist.c | 10 +-- hw/mips_fulong2e.c | 9 ++- hw/mips_jazz.c | 14 ++-- hw/mips_malta.c | 10 ++- hw/mips_mipssim.c | 10 ++- hw/mips_r4k.c | 10 ++- hw/musicpal.c | 9 ++- hw/nseries.c | 22 ++++-- hw/null-machine.c | 7 +- hw/omap_sx1.c | 22 ++++-- hw/openrisc_sim.c | 10 +-- hw/palm.c | 9 ++- hw/pc_piix.c | 50 ++++++------- hw/petalogix_ml605_mmu.c | 8 +- hw/petalogix_s3adsp1800_mmu.c | 8 +- hw/ppc/e500plat.c | 13 ++-- hw/ppc/mpc8544ds.c | 13 ++-- hw/ppc405_boards.c | 25 +++---- hw/ppc440_bamboo.c | 12 +-- hw/ppc_newworld.c | 13 ++-- hw/ppc_oldworld.c | 13 ++-- hw/ppc_prep.c | 13 ++-- hw/puv3.c | 8 +- hw/r2d.c | 9 ++- hw/realview.c | 44 +++++++---- hw/s390-virtio.c | 13 ++-- hw/shix.c | 6 +- hw/spapr.c | 13 ++-- hw/spitz.c | 40 ++++++---- hw/stellaris.c | 14 ++-- hw/sun4m.c | 133 +++++++++++++++++++++------------- hw/sun4u.c | 33 ++++++--- hw/tosa.c | 9 ++- hw/versatilepb.c | 22 ++++-- hw/vexpress.c | 26 ++++--- hw/virtex_ml507.c | 10 +-- hw/xen_machine_pv.c | 11 ++- hw/xilinx_zynq.c | 9 ++- hw/xtensa_lx60.c | 22 ++++-- hw/xtensa_sim.c | 11 ++- hw/z2.c | 9 ++- vl.c | 9 ++- 57 files changed, 515 insertions(+), 411 deletions(-) diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 5ea04c75ac..8f082a6656 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -42,13 +42,13 @@ static int clipper_pci_map_irq(PCIDevice *d, int irq_num) return (slot + 1) * 4 + irq_num; } -static void clipper_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void clipper_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; CPUAlphaState *cpus[4]; PCIBus *pci_bus; ISABus *isa_bus; diff --git a/hw/an5206.c b/hw/an5206.c index 25407c0f50..042c5fcd14 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -19,11 +19,11 @@ /* Board init. */ -static void an5206_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void an5206_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; CPUM68KState *env; int kernel_size; uint64_t elf_entry; diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index eab6327bed..2fd7356fce 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -242,11 +242,12 @@ static const MemoryRegionOps gpio_ops = { static struct cris_load_info li; static -void axisdev88_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void axisdev88_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; CRISCPU *cpu; CPUCRISState *env; DeviceState *dev; diff --git a/hw/boards.h b/hw/boards.h index a2e0a54497..813d0e5109 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -5,12 +5,16 @@ #include "qdev.h" -typedef void QEMUMachineInitFunc(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model); +typedef struct QEMUMachineInitArgs { + ram_addr_t ram_size; + const char *boot_device; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; + const char *cpu_model; +} QEMUMachineInitArgs; + +typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args); typedef void QEMUMachineResetFunc(void); diff --git a/hw/collie.c b/hw/collie.c index 56f89a9f2e..695982a99f 100644 --- a/hw/collie.c +++ b/hw/collie.c @@ -23,11 +23,12 @@ static struct arm_boot_info collie_binfo = { .ram_size = 0x20000000, }; -static void collie_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void collie_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; StrongARMState *s; DriveInfo *dinfo; MemoryRegion *sysmem = get_system_memory(); diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 7cc7a99bfb..f436a0cbc6 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -16,11 +16,11 @@ /* Board init. */ -static void dummy_m68k_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void dummy_m68k_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; CPUM68KState *env; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index 4bb0a60cb1..4951064c3f 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -130,22 +130,22 @@ static Exynos4210State *exynos4_boards_init_common( exynos4_board_ram_size[board_type]); } -static void nuri_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void nuri_init(QEMUMachineInitArgs *args) { + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; exynos4_boards_init_common(kernel_filename, kernel_cmdline, initrd_filename, EXYNOS4_BOARD_NURI); arm_load_kernel(arm_env_get_cpu(first_cpu), &exynos4_board_binfo); } -static void smdkc210_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void smdkc210_init(QEMUMachineInitArgs *args) { + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; Exynos4210State *s = exynos4_boards_init_common(kernel_filename, kernel_cmdline, initrd_filename, EXYNOS4_BOARD_SMDKC210); diff --git a/hw/gumstix.c b/hw/gumstix.c index 13a36ea5c5..4103a88b80 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -45,10 +45,7 @@ static const int sector_len = 128 * 1024; -static void connex_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void connex_init(QEMUMachineInitArgs *args) { PXA2xxState *cpu; DriveInfo *dinfo; @@ -84,11 +81,9 @@ static void connex_init(ram_addr_t ram_size, qdev_get_gpio_in(cpu->gpio, 36)); } -static void verdex_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void verdex_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; PXA2xxState *cpu; DriveInfo *dinfo; int be; diff --git a/hw/highbank.c b/hw/highbank.c index 11aa1312c0..15036b6390 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -187,11 +187,13 @@ static struct arm_boot_info highbank_binfo; * 32-bit host, set the reg value of memory to 0xf7ff00000 in the * device tree and pass -m 2047 to QEMU. */ -static void highbank_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void highbank_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; DeviceState *dev; SysBusDevice *busdev; qemu_irq *irqp; diff --git a/hw/integratorcp.c b/hw/integratorcp.c index d0e2e9068e..ac0ea83492 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -438,11 +438,13 @@ static struct arm_boot_info integrator_binfo = { .board_id = 0x113, }; -static void integratorcp_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void integratorcp_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/kzm.c b/hw/kzm.c index 68cd1b48b9..d1266d9305 100644 --- a/hw/kzm.c +++ b/hw/kzm.c @@ -70,11 +70,13 @@ static struct arm_boot_info kzm_binfo = { .board_id = 1722, }; -static void kzm_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void kzm_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/leon3.c b/hw/leon3.c index 7a9729dc28..774273828f 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -94,13 +94,11 @@ static void leon3_set_pil_in(void *opaque, uint32_t pil_in) } } -static void leon3_generic_hw_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void leon3_generic_hw_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; SPARCCPU *cpu; CPUSPARCState *env; MemoryRegion *address_space_mem = get_system_memory(); diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c index b76d8008be..c5a62c8264 100644 --- a/hw/lm32_boards.c +++ b/hw/lm32_boards.c @@ -69,12 +69,10 @@ static void main_cpu_reset(void *opaque) env->deba = reset_info->flash_base; } -static void lm32_evr_init(ram_addr_t ram_size_not_used, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lm32_evr_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; LM32CPU *cpu; CPULM32State *env; DriveInfo *dinfo; @@ -159,12 +157,12 @@ static void lm32_evr_init(ram_addr_t ram_size_not_used, qemu_register_reset(main_cpu_reset, reset_info); } -static void lm32_uclinux_init(ram_addr_t ram_size_not_used, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lm32_uclinux_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; LM32CPU *cpu; CPULM32State *env; DriveInfo *dinfo; diff --git a/hw/mainstone.c b/hw/mainstone.c index 97687b6eeb..c0d6034147 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -171,11 +171,13 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, arm_load_kernel(mpu->cpu, &mainstone_binfo); } -static void mainstone_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void mainstone_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; mainstone_common_init(get_system_memory(), ram_size, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, mainstone, 0x196); } diff --git a/hw/mcf5208.c b/hw/mcf5208.c index ee25b1b387..688bc3c1a6 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -187,11 +187,11 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic) } } -static void mcf5208evb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void mcf5208evb_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; CPUM68KState *env; int kernel_size; uint64_t elf_entry; diff --git a/hw/milkymist.c b/hw/milkymist.c index 2e7235b4b3..ca9ed43d99 100644 --- a/hw/milkymist.c +++ b/hw/milkymist.c @@ -73,12 +73,12 @@ static void main_cpu_reset(void *opaque) } static void -milkymist_init(ram_addr_t ram_size_not_used, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +milkymist_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; LM32CPU *cpu; CPULM32State *env; int kernel_size; diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index d4a8672f23..fb50a1f67b 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -256,10 +256,13 @@ static void cpu_request_exit(void *opaque, int irq, int level) } } -static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void mips_fulong2e_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index db927f14d0..14df4d7745 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -302,21 +302,19 @@ static void mips_jazz_init(MemoryRegion *address_space, } static -void mips_magnum_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void mips_magnum_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; mips_jazz_init(get_system_memory(), get_system_io(), ram_size, cpu_model, JAZZ_MAGNUM); } static -void mips_pica61_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void mips_pica61_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; mips_jazz_init(get_system_memory(), get_system_io(), ram_size, cpu_model, JAZZ_PICA61); } diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 632b466e32..ad4910ff66 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -775,11 +775,13 @@ static void cpu_request_exit(void *opaque, int irq, int level) } static -void mips_malta_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void mips_malta_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; pflash_t *fl; MemoryRegion *system_memory = get_system_memory(); diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 830f635597..a1d3945cbb 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -131,11 +131,13 @@ static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) } static void -mips_mipssim_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +mips_mipssim_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 967a76e533..b73cdc38ec 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -151,11 +151,13 @@ static void main_cpu_reset(void *opaque) static const int sector_len = 32 * 1024; static -void mips_r4k_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +void mips_r4k_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/musicpal.c b/hw/musicpal.c index f305e21038..f06814c83b 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1508,11 +1508,12 @@ static struct arm_boot_info musicpal_binfo = { .board_id = 0x20e, }; -static void musicpal_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void musicpal_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; qemu_irq *cpu_pic; qemu_irq pic[32]; diff --git a/hw/nseries.c b/hw/nseries.c index 6df71ebb48..7ada90d280 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -1397,21 +1397,27 @@ static struct arm_boot_info n810_binfo = { .atag_board = n810_atag_setup, }; -static void n800_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void n800_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; return n8x0_init(ram_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, &n800_binfo, 800); } -static void n810_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void n810_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; return n8x0_init(ram_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, &n810_binfo, 810); diff --git a/hw/null-machine.c b/hw/null-machine.c index 69910d399c..d813c089e7 100644 --- a/hw/null-machine.c +++ b/hw/null-machine.c @@ -15,12 +15,7 @@ #include "hw/hw.h" #include "hw/boards.h" -static void machine_none_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void machine_none_init(QEMUMachineInitArgs *args) { } diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index abca341926..ad17487fd2 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -209,20 +209,26 @@ static void sx1_init(ram_addr_t ram_size, //~ qemu_console_resize(ds, 640, 480); } -static void sx1_init_v1(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sx1_init_v1(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sx1_init(ram_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 1); } -static void sx1_init_v2(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sx1_init_v2(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sx1_init(ram_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 2); } diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c index 55e97f0959..e96a94492b 100644 --- a/hw/openrisc_sim.c +++ b/hw/openrisc_sim.c @@ -90,13 +90,11 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size, cpu->env.pc = entry; } -static void openrisc_sim_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void openrisc_sim_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; OpenRISCCPU *cpu = NULL; MemoryRegion *ram; int n; diff --git a/hw/palm.c b/hw/palm.c index bacdc90d4a..032b8d6510 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -190,11 +190,12 @@ static struct arm_boot_info palmte_binfo = { .board_id = 0x331, }; -static void palmte_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void palmte_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); struct omap_mpu_state_s *mpu; int flash_size = 0x00800000; diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 5bd4572d47..bf04a42da5 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -287,13 +287,14 @@ static void pc_init1(MemoryRegion *system_memory, } } -static void pc_init_pci(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void pc_init_pci(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -301,13 +302,14 @@ static void pc_init_pci(ram_addr_t ram_size, initrd_filename, cpu_model, 1, 1); } -static void pc_init_pci_no_kvmclock(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -315,13 +317,14 @@ static void pc_init_pci_no_kvmclock(ram_addr_t ram_size, initrd_filename, cpu_model, 1, 0); } -static void pc_init_isa(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void pc_init_isa(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; if (cpu_model == NULL) cpu_model = "486"; pc_init1(get_system_memory(), @@ -332,19 +335,12 @@ static void pc_init_isa(ram_addr_t ram_size, } #ifdef CONFIG_XEN -static void pc_xen_hvm_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void pc_xen_hvm_init(QEMUMachineInitArgs *args) { if (xen_hvm_init() != 0) { hw_error("xen hardware virtual machine initialisation failed"); } - pc_init_pci_no_kvmclock(ram_size, boot_device, - kernel_filename, kernel_cmdline, - initrd_filename, cpu_model); + pc_init_pci_no_kvmclock(args); xen_vcpu_init(); } #endif diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index b9bfbed4c4..39df25175b 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -73,12 +73,10 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu) } static void -petalogix_ml605_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +petalogix_ml605_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev, *dma, *eth0; MicroBlazeCPU *cpu; diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c index 2cf68828ed..71c32ce889 100644 --- a/hw/petalogix_s3adsp1800_mmu.c +++ b/hw/petalogix_s3adsp1800_mmu.c @@ -57,12 +57,10 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu) } static void -petalogix_s3adsp1800_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +petalogix_s3adsp1800_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; DeviceState *dev; MicroBlazeCPU *cpu; CPUMBState *env; diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 60a5cb3bd0..4cfb94061a 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -25,13 +25,14 @@ static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) sizeof(compatible)); } -static void e500plat_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void e500plat_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *boot_device = args->boot_device; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; PPCE500Params params = { .ram_size = ram_size, .boot_device = boot_device, diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index 984d21cbf5..e651661941 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -25,13 +25,14 @@ static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) sizeof(compatible)); } -static void mpc8544ds_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void mpc8544ds_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *boot_device = args->boot_device; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; PPCE500Params params = { .ram_size = ram_size, .boot_device = boot_device, diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 476775d05b..e848cb0b5c 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -158,7 +158,7 @@ static void ref405ep_fpga_reset (void *opaque) fpga->reg1 = 0x0F; } -static void ref405ep_fpga_init (MemoryRegion *sysmem, uint32_t base) +static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base) { ref405ep_fpga_t *fpga; MemoryRegion *fpga_memory = g_new(MemoryRegion, 1); @@ -170,13 +170,12 @@ static void ref405ep_fpga_init (MemoryRegion *sysmem, uint32_t base) qemu_register_reset(&ref405ep_fpga_reset, fpga); } -static void ref405ep_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ref405ep_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; char *filename; ppc4xx_bd_info_t bd; CPUPPCState *env; @@ -484,7 +483,7 @@ static void taihu_cpld_reset (void *opaque) cpld->reg1 = 0x80; } -static void taihu_cpld_init (MemoryRegion *sysmem, uint32_t base) +static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base) { taihu_cpld_t *cpld; MemoryRegion *cpld_memory = g_new(MemoryRegion, 1); @@ -495,13 +494,11 @@ static void taihu_cpld_init (MemoryRegion *sysmem, uint32_t base) qemu_register_reset(&taihu_cpld_reset, cpld); } -static void taihu_405ep_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void taihu_405ep_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *kernel_filename = args->kernel_filename; + const char *initrd_filename = args->initrd_filename; char *filename; qemu_irq *pic; MemoryRegion *sysmem = get_system_memory(); diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index c198071170..78e7985305 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -157,13 +157,13 @@ static void main_cpu_reset(void *opaque) mmubooke_create_initial_mapping(env, 0, 0); } -static void bamboo_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void bamboo_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ram_memories diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index b8d3c9c988..a265445b70 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -128,13 +128,14 @@ static void ppc_core99_reset(void *opaque) } /* PowerPC Mac99 hardware initialisation */ -static void ppc_core99_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ppc_core99_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; char *filename; diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 2c4a47813f..de334080ff 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -71,13 +71,14 @@ static void ppc_heathrow_reset(void *opaque) cpu_reset(CPU(cpu)); } -static void ppc_heathrow_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ppc_heathrow_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; MemoryRegion *sysmem = get_system_memory(); PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 15444303e4..b426891e29 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -447,13 +447,14 @@ static void ppc_prep_reset(void *opaque) } /* PowerPC PREP hardware initialisation */ -static void ppc_prep_init (ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ppc_prep_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; MemoryRegion *sysmem = get_system_memory(); PowerPCCPU *cpu = NULL; CPUPPCState *env = NULL; diff --git a/hw/puv3.c b/hw/puv3.c index 43f7216e4e..764799cff4 100644 --- a/hw/puv3.c +++ b/hw/puv3.c @@ -91,10 +91,12 @@ static void puv3_load_kernel(const char *kernel_filename) graphic_console_init(NULL, NULL, NULL, NULL, NULL); } -static void puv3_init(ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void puv3_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *initrd_filename = args->initrd_filename; CPUUniCore32State *env; if (initrd_filename) { diff --git a/hw/r2d.c b/hw/r2d.c index 1bc191ff3e..3cb6942056 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -219,11 +219,12 @@ static struct QEMU_PACKED char kernel_cmdline[256]; } boot_params; -static void r2d_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void r2d_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; SuperHCPU *cpu; CPUSH4State *env; ResetData *reset_info; diff --git a/hw/realview.c b/hw/realview.c index 19db4d026b..8dc4be6ae0 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -330,11 +330,14 @@ static void realview_init(ram_addr_t ram_size, arm_load_kernel(arm_env_get_cpu(first_cpu), &realview_binfo); } -static void realview_eb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void realview_eb_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; if (!cpu_model) { cpu_model = "arm926"; } @@ -342,11 +345,14 @@ static void realview_eb_init(ram_addr_t ram_size, initrd_filename, cpu_model, BOARD_EB); } -static void realview_eb_mpcore_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void realview_eb_mpcore_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; if (!cpu_model) { cpu_model = "arm11mpcore"; } @@ -354,11 +360,14 @@ static void realview_eb_mpcore_init(ram_addr_t ram_size, initrd_filename, cpu_model, BOARD_EB_MPCORE); } -static void realview_pb_a8_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void realview_pb_a8_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; if (!cpu_model) { cpu_model = "cortex-a8"; } @@ -366,11 +375,14 @@ static void realview_pb_a8_init(ram_addr_t ram_size, initrd_filename, cpu_model, BOARD_PB_A8); } -static void realview_pbx_a9_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void realview_pbx_a9_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; if (!cpu_model) { cpu_model = "cortex-a9"; } diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 47eed35da3..39ff17828b 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -151,13 +151,14 @@ unsigned s390_del_running_cpu(CPUS390XState *env) } /* PC hardware initialisation */ -static void s390_init(ram_addr_t my_ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void s390_init(QEMUMachineInitArgs *args) { + ram_addr_t my_ram_size = args->ram_size; + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; CPUS390XState *env = NULL; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); diff --git a/hw/shix.c b/hw/shix.c index dd9ce174f9..b56dd54f75 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -37,11 +37,9 @@ #define BIOS_FILENAME "shix_bios.bin" #define BIOS_ADDRESS 0xA0000000 -static void shix_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void shix_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; int ret; CPUSH4State *env; struct SH7750State *s; diff --git a/hw/spapr.c b/hw/spapr.c index 09b8e99221..637b3fb718 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -665,13 +665,14 @@ static int spapr_vga_init(PCIBus *pci_bus) } /* pSeries LPAR / sPAPR hardware init */ -static void ppc_spapr_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void ppc_spapr_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; PowerPCCPU *cpu; CPUPPCState *env; PCIHostState *phb; diff --git a/hw/spitz.c b/hw/spitz.c index 24346dcd5a..29426266b1 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -936,38 +936,46 @@ static void spitz_common_init(ram_addr_t ram_size, sl_bootparam_write(SL_PXA_PARAM_BASE); } -static void spitz_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void spitz_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; spitz_common_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9); } -static void borzoi_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void borzoi_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; spitz_common_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f); } -static void akita_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void akita_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; spitz_common_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8); } -static void terrier_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void terrier_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; spitz_common_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, terrier, 0x33f); } diff --git a/hw/stellaris.c b/hw/stellaris.c index 353ca4c046..bfb18b014e 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1313,19 +1313,17 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, } /* FIXME: Figure out how to generate these from stellaris_boards. */ -static void lm3s811evb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lm3s811evb_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]); } -static void lm3s6965evb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void lm3s6965evb_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]); } diff --git a/hw/sun4m.c b/hw/sun4m.c index a04b485eda..dbe93f9eb9 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -1306,92 +1306,118 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = { }; /* SPARCstation 5 hardware initialisation */ -static void ss5_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss5_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[0], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation 10 hardware initialisation */ -static void ss10_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss10_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[1], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCserver 600MP hardware initialisation */ -static void ss600mp_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss600mp_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[2], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation 20 hardware initialisation */ -static void ss20_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss20_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[3], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation Voyager hardware initialisation */ -static void vger_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void vger_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[4], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation LX hardware initialisation */ -static void ss_lx_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss_lx_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[5], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCstation 4 hardware initialisation */ -static void ss4_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss4_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[6], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCClassic hardware initialisation */ -static void scls_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void scls_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[7], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCbook hardware initialisation */ -static void sbook_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sbook_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4m_hw_init(&sun4m_hwdefs[8], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } @@ -1654,21 +1680,27 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, } /* SPARCserver 1000 hardware initialisation */ -static void ss1000_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss1000_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4d_hw_init(&sun4d_hwdefs[0], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } /* SPARCcenter 2000 hardware initialisation */ -static void ss2000_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss2000_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4d_hw_init(&sun4d_hwdefs[1], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } @@ -1848,11 +1880,14 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, } /* SPARCstation 2 hardware initialisation */ -static void ss2_init(ram_addr_t RAM_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void ss2_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; sun4c_hw_init(&sun4c_hwdefs[0], RAM_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } diff --git a/hw/sun4u.c b/hw/sun4u.c index 940db3348a..abf68cf50f 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -933,31 +933,40 @@ static const struct hwdef hwdefs[] = { }; /* Sun4u hardware initialisation */ -static void sun4u_init(ram_addr_t RAM_size, - const char *boot_devices, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sun4u_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, &hwdefs[0]); } /* Sun4v hardware initialisation */ -static void sun4v_init(ram_addr_t RAM_size, - const char *boot_devices, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void sun4v_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, &hwdefs[1]); } /* Niagara hardware initialisation */ -static void niagara_init(ram_addr_t RAM_size, - const char *boot_devices, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void niagara_init(QEMUMachineInitArgs *args) { + ram_addr_t RAM_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_devices = args->boot_device; sun4uv_init(get_system_memory(), RAM_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, &hwdefs[2]); } diff --git a/hw/tosa.c b/hw/tosa.c index 297a8c2ed0..512278c241 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -205,11 +205,12 @@ static struct arm_boot_info tosa_binfo = { .ram_size = 0x04000000, }; -static void tosa_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void tosa_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *rom = g_new(MemoryRegion, 1); PXA2xxState *mpu; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 7b1b0256aa..756ec29da5 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -348,22 +348,28 @@ static void versatile_init(ram_addr_t ram_size, arm_load_kernel(cpu, &versatile_binfo); } -static void vpb_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void vpb_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; versatile_init(ram_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model, 0x183); } -static void vab_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void vab_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; versatile_init(ram_size, boot_device, kernel_filename, kernel_cmdline, diff --git a/hw/vexpress.c b/hw/vexpress.c index 3596d1e33f..36503d69fa 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -467,25 +467,27 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, arm_load_kernel(arm_env_get_cpu(first_cpu), &vexpress_binfo); } -static void vexpress_a9_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void vexpress_a9_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; vexpress_common_init(&a9_daughterboard, ram_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); } -static void vexpress_a15_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void vexpress_a15_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; vexpress_common_init(&a15_daughterboard, ram_size, boot_device, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index 79bc0d10ee..a09b27a346 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -183,12 +183,12 @@ static int xilinx_load_device_tree(target_phys_addr_t addr, return fdt_size; } -static void virtex_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void virtex_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev; PowerPCCPU *cpu; diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 4b72aa7557..426470351e 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -29,13 +29,12 @@ #include "xen_domainbuild.h" #include "blockdev.h" -static void xen_init_pv(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *cpu_model) +static void xen_init_pv(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; X86CPU *cpu; CPUX86State *env; DriveInfo *dinfo; diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index fd46ba2527..c55dafba6b 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -77,10 +77,13 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq) } -static void zynq_init(ram_addr_t ram_size, const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void zynq_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; ARMCPU *cpu; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *ext_ram = g_new(MemoryRegion, 1); diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index 3653f65b1e..1fd2c47ac5 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -268,11 +268,14 @@ static void lx_init(const LxBoardDesc *board, } } -static void xtensa_lx60_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void xtensa_lx60_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; static const LxBoardDesc lx60_board = { .flash_size = 0x400000, .flash_sector_size = 0x10000, @@ -283,11 +286,14 @@ static void xtensa_lx60_init(ram_addr_t ram_size, initrd_filename, cpu_model); } -static void xtensa_lx200_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void xtensa_lx200_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; static const LxBoardDesc lx200_board = { .flash_size = 0x1000000, .flash_sector_size = 0x20000, diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c index 831460b7c4..2e846d8aa6 100644 --- a/hw/xtensa_sim.c +++ b/hw/xtensa_sim.c @@ -96,11 +96,14 @@ static void sim_init(ram_addr_t ram_size, } } -static void xtensa_sim_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void xtensa_sim_init(QEMUMachineInitArgs *args) { + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; if (!cpu_model) { cpu_model = XTENSA_DEFAULT_CPU_MODEL; } diff --git a/hw/z2.c b/hw/z2.c index 076fad20c6..f62b8067bf 100644 --- a/hw/z2.c +++ b/hw/z2.c @@ -295,11 +295,12 @@ static TypeInfo aer915_info = { .class_init = aer915_class_init, }; -static void z2_init(ram_addr_t ram_size, - const char *boot_device, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, const char *cpu_model) +static void z2_init(QEMUMachineInitArgs *args) { + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; MemoryRegion *address_space_mem = get_system_memory(); uint32_t sector_len = 0x10000; PXA2xxState *mpu; diff --git a/vl.c b/vl.c index 5b357a3b06..ee3c43ae2f 100644 --- a/vl.c +++ b/vl.c @@ -3638,8 +3638,13 @@ int main(int argc, char **argv, char **envp) qdev_machine_init(); - machine->init(ram_size, boot_devices, - kernel_filename, kernel_cmdline, initrd_filename, cpu_model); + QEMUMachineInitArgs args = { .ram_size = ram_size, + .boot_device = boot_devices, + .kernel_filename = kernel_filename, + .kernel_cmdline = kernel_cmdline, + .initrd_filename = initrd_filename, + .cpu_model = cpu_model }; + machine->init(&args); cpu_synchronize_all_post_init(); From f1bc0bcc9dbbbf5674add3075b5efe0a93fe34f0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 17:30:10 +1000 Subject: [PATCH 108/160] exec: Split up and tidy code_gen_buffer It now consists of: A macro definition of MAX_CODE_GEN_BUFFER_SIZE with host-specific values, A function size_code_gen_buffer that applies most of the reasoning for choosing a buffer size, Three variations of a function alloc_code_gen_buffer that contain all of the logic for allocating executable memory via a given allocation mechanism. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- exec.c | 201 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 106 insertions(+), 95 deletions(-) diff --git a/exec.c b/exec.c index 7899042ce9..eecae2f174 100644 --- a/exec.c +++ b/exec.c @@ -103,9 +103,9 @@ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; uint8_t code_gen_prologue[1024] code_gen_section; static uint8_t *code_gen_buffer; -static unsigned long code_gen_buffer_size; +static size_t code_gen_buffer_size; /* threshold to flush the translated code buffer */ -static unsigned long code_gen_buffer_max_size; +static size_t code_gen_buffer_max_size; static uint8_t *code_gen_ptr; #if !defined(CONFIG_USER_ONLY) @@ -497,110 +497,121 @@ bool memory_region_is_unassigned(MemoryRegion *mr) #define mmap_unlock() do { } while(0) #endif -#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024) - #if defined(CONFIG_USER_ONLY) /* Currently it is not recommended to allocate big chunks of data in - user mode. It will change when a dedicated libc will be used */ + user mode. It will change when a dedicated libc will be used. */ +/* ??? 64-bit hosts ought to have no problem mmaping data outside the + region in which the guest needs to run. Revisit this. */ #define USE_STATIC_CODE_GEN_BUFFER #endif +/* ??? Should configure for this, not list operating systems here. */ +#if (defined(__linux__) \ + || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \ + || defined(__DragonFly__) || defined(__OpenBSD__) \ + || defined(__NetBSD__)) +# define USE_MMAP +#endif + +/* Maximum size of the code gen buffer we'd like to use. Unless otherwise + indicated, this is constrained by the range of direct branches on the + host cpu, as used by the TCG implementation of goto_tb. */ +#if defined(__x86_64__) +# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +#elif defined(__sparc__) +# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +#elif defined(__arm__) +# define MAX_CODE_GEN_BUFFER_SIZE (16u * 1024 * 1024) +#elif defined(__s390x__) + /* We have a +- 4GB range on the branches; leave some slop. */ +# define MAX_CODE_GEN_BUFFER_SIZE (3ul * 1024 * 1024 * 1024) +#else +# define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) +#endif + +#define DEFAULT_CODE_GEN_BUFFER_SIZE (32u * 1024 * 1024) + +static inline size_t size_code_gen_buffer(size_t tb_size) +{ + /* Size the buffer. */ + if (tb_size == 0) { +#ifdef USE_STATIC_CODE_GEN_BUFFER + tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE; +#else + /* ??? Needs adjustments. */ + /* ??? If we relax the requirement that CONFIG_USER_ONLY use the + static buffer, we could size this on RESERVED_VA, on the text + segment size of the executable, or continue to use the default. */ + tb_size = (unsigned long)(ram_size / 4); +#endif + } + if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) { + tb_size = MIN_CODE_GEN_BUFFER_SIZE; + } + if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) { + tb_size = MAX_CODE_GEN_BUFFER_SIZE; + } + code_gen_buffer_size = tb_size; + return tb_size; +} + #ifdef USE_STATIC_CODE_GEN_BUFFER static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE] - __attribute__((aligned (CODE_GEN_ALIGN))); -#endif + __attribute__((aligned(CODE_GEN_ALIGN))); -static void code_gen_alloc(unsigned long tb_size) +static inline void *alloc_code_gen_buffer(void) { -#ifdef USE_STATIC_CODE_GEN_BUFFER - code_gen_buffer = static_code_gen_buffer; - code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; - map_exec(code_gen_buffer, code_gen_buffer_size); -#else - code_gen_buffer_size = tb_size; - if (code_gen_buffer_size == 0) { -#if defined(CONFIG_USER_ONLY) - code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; -#else - /* XXX: needs adjustments */ - code_gen_buffer_size = (unsigned long)(ram_size / 4); -#endif - } - if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE) - code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE; - /* The code gen buffer location may have constraints depending on - the host cpu and OS */ -#if defined(__linux__) - { - int flags; - void *start = NULL; + map_exec(static_code_gen_buffer, code_gen_buffer_size); + return static_code_gen_buffer; +} +#elif defined(USE_MMAP) +static inline void *alloc_code_gen_buffer(void) +{ + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + uintptr_t start = 0; + void *buf; - flags = MAP_PRIVATE | MAP_ANONYMOUS; -#if defined(__x86_64__) - flags |= MAP_32BIT; - /* Cannot map more than that */ - if (code_gen_buffer_size > (800 * 1024 * 1024)) - code_gen_buffer_size = (800 * 1024 * 1024); -#elif defined(__sparc__) && HOST_LONG_BITS == 64 - // Map the buffer below 2G, so we can use direct calls and branches - start = (void *) 0x40000000UL; - if (code_gen_buffer_size > (512 * 1024 * 1024)) - code_gen_buffer_size = (512 * 1024 * 1024); -#elif defined(__arm__) - /* Keep the buffer no bigger than 16MB to branch between blocks */ - if (code_gen_buffer_size > 16 * 1024 * 1024) - code_gen_buffer_size = 16 * 1024 * 1024; -#elif defined(__s390x__) - /* Map the buffer so that we can use direct calls and branches. */ - /* We have a +- 4GB range on the branches; leave some slop. */ - if (code_gen_buffer_size > (3ul * 1024 * 1024 * 1024)) { - code_gen_buffer_size = 3ul * 1024 * 1024 * 1024; - } - start = (void *)0x90000000UL; -#endif - code_gen_buffer = mmap(start, code_gen_buffer_size, - PROT_WRITE | PROT_READ | PROT_EXEC, - flags, -1, 0); - if (code_gen_buffer == MAP_FAILED) { - fprintf(stderr, "Could not allocate dynamic translator buffer\n"); - exit(1); - } - } -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \ - || defined(__DragonFly__) || defined(__OpenBSD__) \ - || defined(__NetBSD__) - { - int flags; - void *addr = NULL; - flags = MAP_PRIVATE | MAP_ANONYMOUS; -#if defined(__x86_64__) - /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume - * 0x40000000 is free */ - flags |= MAP_FIXED; - addr = (void *)0x40000000; - /* Cannot map more than that */ - if (code_gen_buffer_size > (800 * 1024 * 1024)) - code_gen_buffer_size = (800 * 1024 * 1024); -#elif defined(__sparc__) && HOST_LONG_BITS == 64 - // Map the buffer below 2G, so we can use direct calls and branches - addr = (void *) 0x40000000UL; - if (code_gen_buffer_size > (512 * 1024 * 1024)) { - code_gen_buffer_size = (512 * 1024 * 1024); - } -#endif - code_gen_buffer = mmap(addr, code_gen_buffer_size, - PROT_WRITE | PROT_READ | PROT_EXEC, - flags, -1, 0); - if (code_gen_buffer == MAP_FAILED) { - fprintf(stderr, "Could not allocate dynamic translator buffer\n"); - exit(1); - } + /* Constrain the position of the buffer based on the host cpu. + Note that these addresses are chosen in concert with the + addresses assigned in the relevant linker script file. */ +# if defined(__x86_64__) && defined(MAP_32BIT) + /* Force the memory down into low memory with the executable. + Leave the choice of exact location with the kernel. */ + flags |= MAP_32BIT; + /* Cannot expect to map more than 800MB in low memory. */ + if (code_gen_buffer_size > 800u * 1024 * 1024) { + code_gen_buffer_size = 800u * 1024 * 1024; } +# elif defined(__sparc__) + start = 0x40000000ul; +# elif defined(__s390x__) + start = 0x90000000ul; +# endif + + buf = mmap((void *)start, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, flags, -1, 0); + return buf == MAP_FAILED ? NULL : buf; +} #else - code_gen_buffer = g_malloc(code_gen_buffer_size); - map_exec(code_gen_buffer, code_gen_buffer_size); -#endif -#endif /* !USE_STATIC_CODE_GEN_BUFFER */ +static inline void *alloc_code_gen_buffer(void) +{ + void *buf = g_malloc(code_gen_buffer_size); + if (buf) { + map_exec(buf, code_gen_buffer_size); + } + return buf; +} +#endif /* USE_STATIC_CODE_GEN_BUFFER, USE_MMAP */ + +static inline void code_gen_alloc(size_t tb_size) +{ + code_gen_buffer_size = size_code_gen_buffer(tb_size); + code_gen_buffer = alloc_code_gen_buffer(); + if (code_gen_buffer == NULL) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + map_exec(code_gen_prologue, sizeof(code_gen_prologue)); code_gen_buffer_max_size = code_gen_buffer_size - (TCG_MAX_OP_SIZE * OPC_BUF_SIZE); @@ -4188,7 +4199,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) } /* XXX: avoid using doubles ? */ cpu_fprintf(f, "Translation buffer state:\n"); - cpu_fprintf(f, "gen code size %td/%ld\n", + cpu_fprintf(f, "gen code size %td/%zd\n", code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size); cpu_fprintf(f, "TB count %d/%d\n", nb_tbs, code_gen_max_blocks); From 3d85a72fd8af6804f66a48d85187f448b14ddba3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 17:30:11 +1000 Subject: [PATCH 109/160] exec: Don't make DEFAULT_CODE_GEN_BUFFER_SIZE too large For ARM we cap the buffer size to 16MB. Do not allocate 32MB in that case. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- exec.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index eecae2f174..6c0b2d715a 100644 --- a/exec.c +++ b/exec.c @@ -529,7 +529,11 @@ bool memory_region_is_unassigned(MemoryRegion *mr) # define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) #endif -#define DEFAULT_CODE_GEN_BUFFER_SIZE (32u * 1024 * 1024) +#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32u * 1024 * 1024) + +#define DEFAULT_CODE_GEN_BUFFER_SIZE \ + (DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \ + ? DEFAULT_CODE_GEN_BUFFER_SIZE_1 : MAX_CODE_GEN_BUFFER_SIZE) static inline size_t size_code_gen_buffer(size_t tb_size) { From 405def18466d0cbd84e6a0edb598466b0a5e15c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 17:30:12 +1000 Subject: [PATCH 110/160] exec: Do not use absolute address hints for code_gen_buffer with -fpie The hard-coded addresses inside alloc_code_gen_buffer only make sense if we're building an executable that will actually run at the address we've put into the linker scripts. When we're building with -fpie, the executable will run at some random location chosen by the kernel. We get better placement for the code_gen_buffer if we allow the kernel to place the memory, as it will tend to to place it near the executable, based on the PROT_EXEC bit. Since code_gen_prologue is always inside the executable, this effect is easily seen at the end of most TB, with the exit_tb opcode, and with any calls to helper functions. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- exec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 6c0b2d715a..5e33a3d435 100644 --- a/exec.c +++ b/exec.c @@ -578,7 +578,12 @@ static inline void *alloc_code_gen_buffer(void) /* Constrain the position of the buffer based on the host cpu. Note that these addresses are chosen in concert with the addresses assigned in the relevant linker script file. */ -# if defined(__x86_64__) && defined(MAP_32BIT) +# if defined(__PIE__) || defined(__PIC__) + /* Don't bother setting a preferred location if we're building + a position-independent executable. We're more likely to get + an address near the main executable if we let the kernel + choose the address. */ +# elif defined(__x86_64__) && defined(MAP_32BIT) /* Force the memory down into low memory with the executable. Leave the choice of exact location with the kernel. */ flags |= MAP_32BIT; From 4438c8a9469d79fa2c58189418befb506da54d97 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 17:30:13 +1000 Subject: [PATCH 111/160] exec: Allocate code_gen_prologue from code_gen_buffer We had a hack for arm and sparc, allocating code_gen_prologue to a special section. Which, honestly does no good under certain cases. We've already got limits on code_gen_buffer_size to ensure that all TBs can use direct branches between themselves; reuse this limit to ensure the prologue is also reachable. As a bonus, we get to avoid marking a page of the main executable's data segment as executable. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- exec.c | 30 +++++++++++------------------- tcg/tcg.h | 2 +- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/exec.c b/exec.c index 5e33a3d435..8958b281dc 100644 --- a/exec.c +++ b/exec.c @@ -86,22 +86,7 @@ static int nb_tbs; /* any access to the tbs or the page table must use this lock */ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; -#if defined(__arm__) || defined(__sparc__) -/* The prologue must be reachable with a direct jump. ARM and Sparc64 - have limited branch ranges (possibly also PPC) so place it in a - section close to code segment. */ -#define code_gen_section \ - __attribute__((__section__(".gen_code"))) \ - __attribute__((aligned (32))) -#elif defined(_WIN32) && !defined(_WIN64) -#define code_gen_section \ - __attribute__((aligned (16))) -#else -#define code_gen_section \ - __attribute__((aligned (32))) -#endif - -uint8_t code_gen_prologue[1024] code_gen_section; +uint8_t *code_gen_prologue; static uint8_t *code_gen_buffer; static size_t code_gen_buffer_size; /* threshold to flush the translated code buffer */ @@ -221,7 +206,7 @@ static int tb_flush_count; static int tb_phys_invalidate_count; #ifdef _WIN32 -static void map_exec(void *addr, long size) +static inline void map_exec(void *addr, long size) { DWORD old_protect; VirtualProtect(addr, size, @@ -229,7 +214,7 @@ static void map_exec(void *addr, long size) } #else -static void map_exec(void *addr, long size) +static inline void map_exec(void *addr, long size) { unsigned long start, end, page_size; @@ -621,7 +606,14 @@ static inline void code_gen_alloc(size_t tb_size) exit(1); } - map_exec(code_gen_prologue, sizeof(code_gen_prologue)); + /* Steal room for the prologue at the end of the buffer. This ensures + (via the MAX_CODE_GEN_BUFFER_SIZE limits above) that direct branches + from TB's to the prologue are going to be in range. It also means + that we don't need to mark (additional) portions of the data segment + as executable. */ + code_gen_prologue = code_gen_buffer + code_gen_buffer_size - 1024; + code_gen_buffer_size -= 1024; + code_gen_buffer_max_size = code_gen_buffer_size - (TCG_MAX_OP_SIZE * OPC_BUF_SIZE); code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; diff --git a/tcg/tcg.h b/tcg/tcg.h index 7bafe0eeb6..45e94f536c 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -616,7 +616,7 @@ TCGv_i64 tcg_const_i64(int64_t val); TCGv_i32 tcg_const_local_i32(int32_t val); TCGv_i64 tcg_const_local_i64(int64_t val); -extern uint8_t code_gen_prologue[]; +extern uint8_t *code_gen_prologue; /* TCG targets may use a different definition of tcg_qemu_tb_exec. */ #if !defined(tcg_qemu_tb_exec) From 74d590c8e930e42832711604ef0ffd7df6bd5873 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 17:30:14 +1000 Subject: [PATCH 112/160] exec: Make MIN_CODE_GEN_BUFFER_SIZE private to exec.c It is used nowhere else, and the corresponding MAX_CODE_GEN_BUFFER_SIZE also lives there. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- exec-all.h | 2 -- exec.c | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/exec-all.h b/exec-all.h index f7f649ee61..16caf49db7 100644 --- a/exec-all.h +++ b/exec-all.h @@ -121,8 +121,6 @@ static inline void tlb_flush(CPUArchState *env, int flush_global) #define CODE_GEN_PHYS_HASH_BITS 15 #define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) -#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024) - /* estimated block size for TB allocation */ /* XXX: use a per code average code fragment size and modulate it according to the host CPU */ diff --git a/exec.c b/exec.c index 8958b281dc..4a86b0f4c4 100644 --- a/exec.c +++ b/exec.c @@ -498,6 +498,10 @@ bool memory_region_is_unassigned(MemoryRegion *mr) # define USE_MMAP #endif +/* Minimum size of the code gen buffer. This number is randomly chosen, + but not so small that we can't have a fair number of TB's live. */ +#define MIN_CODE_GEN_BUFFER_SIZE (1024u * 1024) + /* Maximum size of the code gen buffer we'd like to use. Unless otherwise indicated, this is constrained by the range of direct branches on the host cpu, as used by the TCG implementation of goto_tb. */ From 8802361689c7aa9224aea39329af72fbc7b366ef Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:12 +1000 Subject: [PATCH 113/160] target-sparc: Add gen_load/store/dest_gpr Infrastructure to be used to clean up handling of temporaries. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 6cef96bfa6..eec0db0d70 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -83,7 +83,9 @@ typedef struct DisasContext { struct TranslationBlock *tb; sparc_def_t *def; TCGv_i32 t32[3]; + TCGv ttl[5]; int n_t32; + int n_ttl; } DisasContext; typedef struct { @@ -263,6 +265,49 @@ static inline void gen_address_mask(DisasContext *dc, TCGv addr) #endif } +static inline TCGv get_temp_tl(DisasContext *dc) +{ + TCGv t; + assert(dc->n_ttl < ARRAY_SIZE(dc->ttl)); + dc->ttl[dc->n_ttl++] = t = tcg_temp_new(); + return t; +} + +static inline TCGv gen_load_gpr(DisasContext *dc, int reg) +{ + if (reg == 0 || reg >= 8) { + TCGv t = get_temp_tl(dc); + if (reg == 0) { + tcg_gen_movi_tl(t, 0); + } else { + tcg_gen_ld_tl(t, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); + } + return t; + } else { + return cpu_gregs[reg]; + } +} + +static inline void gen_store_gpr(DisasContext *dc, int reg, TCGv v) +{ + if (reg > 0) { + if (reg < 8) { + tcg_gen_mov_tl(cpu_gregs[reg], v); + } else { + tcg_gen_st_tl(v, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); + } + } +} + +static inline TCGv gen_dest_gpr(DisasContext *dc, int reg) +{ + if (reg == 0 || reg >= 8) { + return get_temp_tl(dc); + } else { + return cpu_gregs[reg]; + } +} + static inline void gen_movl_reg_TN(int reg, TCGv tn) { if (reg == 0) @@ -5229,6 +5274,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } dc->n_t32 = 0; } + if (dc->n_ttl != 0) { + int i; + for (i = dc->n_ttl - 1; i >= 0; --i) { + tcg_temp_free(dc->ttl[i]); + } + dc->n_ttl = 0; + } } static inline void gen_intermediate_code_internal(TranslationBlock * tb, From 97ea285917d473c8c8ecb627a637d76082cd6584 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:13 +1000 Subject: [PATCH 114/160] target-sparc: Conversion to gen_*_gpr, part 1 Only handle the easy cases directly within disas_sparc_insn. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 420 +++++++++++++++++---------------------- 1 file changed, 177 insertions(+), 243 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index eec0db0d70..0ec3d488c8 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2602,13 +2602,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto jmp_insn; } case 0x4: /* SETHI */ - if (rd) { // nop + /* Special-case %g0 because that's the canonical nop. */ + if (rd) { uint32_t value = GET_FIELD(insn, 10, 31); - TCGv r_const; - - r_const = tcg_const_tl(value << 10); - gen_movl_TN_reg(rd, r_const); - tcg_temp_free(r_const); + TCGv t = gen_dest_gpr(dc, rd); + tcg_gen_movi_tl(t, value << 10); + gen_store_gpr(dc, rd, t); } break; case 0x0: /* UNIMPL */ @@ -2621,11 +2620,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 1: /*CALL*/ { target_long target = GET_FIELDs(insn, 2, 31) << 2; - TCGv r_const; + TCGv o7 = gen_dest_gpr(dc, 15); - r_const = tcg_const_tl(dc->pc); - gen_movl_TN_reg(15, r_const); - tcg_temp_free(r_const); + tcg_gen_movi_tl(o7, dc->pc); + gen_store_gpr(dc, 15, o7); target += dc->pc; gen_mov_pc_npc(dc); #ifdef TARGET_SPARC64 @@ -2689,22 +2687,17 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) /* Signal that the trap value is fully constant. */ mask = 0; } else { - TCGv t1 = tcg_temp_new(); - gen_movl_reg_TN(rs1, t1); + TCGv t1 = gen_load_gpr(dc, rs1); tcg_gen_trunc_tl_i32(trap, t1); - tcg_temp_free(t1); tcg_gen_addi_i32(trap, trap, rs2); } } else { - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); + TCGv t1, t2; rs2 = GET_FIELD_SP(insn, 0, 4); - gen_movl_reg_TN(rs1, t1); - gen_movl_reg_TN(rs2, t2); + t1 = gen_load_gpr(dc, rs1); + t2 = gen_load_gpr(dc, rs2); tcg_gen_add_tl(t1, t1, t2); tcg_gen_trunc_tl_i32(trap, t1); - tcg_temp_free(t1); - tcg_temp_free(t2); } if (mask != 0) { tcg_gen_andi_i32(trap, trap, mask); @@ -2738,27 +2731,24 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) microSPARC II */ /* Read Asr17 */ if (rs1 == 0x11 && dc->def->features & CPU_FEATURE_ASR17) { - TCGv r_const; - + TCGv t = gen_dest_gpr(dc, rd); /* Read Asr17 for a Leon3 monoprocessor */ - r_const = tcg_const_tl((1 << 8) - | (dc->def->nwindows - 1)); - gen_movl_TN_reg(rd, r_const); - tcg_temp_free(r_const); + tcg_gen_movi_tl(t, (1 << 8) | (dc->def->nwindows - 1)); + gen_store_gpr(dc, rd, t); break; } #endif - gen_movl_TN_reg(rd, cpu_y); + gen_store_gpr(dc, rd, cpu_y); break; #ifdef TARGET_SPARC64 case 0x2: /* V9 rdccr */ update_psr(dc); gen_helper_rdccr(cpu_dst, cpu_env); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x3: /* V9 rdasi */ tcg_gen_ext_i32_tl(cpu_dst, cpu_asi); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x4: /* V9 rdtick */ { @@ -2769,25 +2759,23 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) offsetof(CPUSPARCState, tick)); gen_helper_tick_get_count(cpu_dst, r_tickptr); tcg_temp_free_ptr(r_tickptr); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); } break; case 0x5: /* V9 rdpc */ { - TCGv r_const; - + TCGv t = gen_dest_gpr(dc, rd); if (unlikely(AM_CHECK(dc))) { - r_const = tcg_const_tl(dc->pc & 0xffffffffULL); + tcg_gen_movi_tl(t, dc->pc & 0xffffffffULL); } else { - r_const = tcg_const_tl(dc->pc); + tcg_gen_movi_tl(t, dc->pc); } - gen_movl_TN_reg(rd, r_const); - tcg_temp_free(r_const); + gen_store_gpr(dc, rd, t); } break; case 0x6: /* V9 rdfprs */ tcg_gen_ext_i32_tl(cpu_dst, cpu_fprs); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0xf: /* V9 membar */ break; /* no effect */ @@ -2795,14 +2783,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } - gen_movl_TN_reg(rd, cpu_gsr); + gen_store_gpr(dc, rd, cpu_gsr); break; case 0x16: /* Softint */ tcg_gen_ext_i32_tl(cpu_dst, cpu_softint); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x17: /* Tick compare */ - gen_movl_TN_reg(rd, cpu_tick_cmpr); + gen_store_gpr(dc, rd, cpu_tick_cmpr); break; case 0x18: /* System tick */ { @@ -2813,11 +2801,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) offsetof(CPUSPARCState, stick)); gen_helper_tick_get_count(cpu_dst, r_tickptr); tcg_temp_free_ptr(r_tickptr); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); } break; case 0x19: /* System tick compare */ - gen_movl_TN_reg(rd, cpu_stick_cmpr); + gen_store_gpr(dc, rd, cpu_stick_cmpr); break; case 0x10: /* Performance Control */ case 0x11: /* Performance Instrumentation Counter */ @@ -2864,7 +2852,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } #endif - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; } else if (xop == 0x2a) { /* rdwim / V9 rdpr */ if (!supervisor(dc)) @@ -2925,7 +2913,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_ld_ptr(r_tickptr, cpu_env, offsetof(CPUSPARCState, tick)); gen_helper_tick_get_count(cpu_tmp0, r_tickptr); - gen_movl_TN_reg(rd, cpu_tmp0); tcg_temp_free_ptr(r_tickptr); } break; @@ -2997,7 +2984,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #else tcg_gen_ext_i32_tl(cpu_tmp0, cpu_wim); #endif - gen_movl_TN_reg(rd, cpu_tmp0); + gen_store_gpr(dc, rd, cpu_tmp0); break; } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ #ifdef TARGET_SPARC64 @@ -3006,7 +2993,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #else if (!supervisor(dc)) goto priv_insn; - gen_movl_TN_reg(rd, cpu_tbr); + gen_store_gpr(dc, rd, cpu_tbr); #endif break; #endif @@ -3338,38 +3325,40 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } } else if (xop == 0x2) { - // clr/mov shortcut - + TCGv dst = gen_dest_gpr(dc, rd); rs1 = GET_FIELD(insn, 13, 17); if (rs1 == 0) { - // or %g0, x, y -> mov T0, x; mov y, T0 + /* clr/mov shortcut : or %g0, x, y -> mov x, y */ if (IS_IMM) { /* immediate */ - TCGv r_const; - simm = GET_FIELDs(insn, 19, 31); - r_const = tcg_const_tl(simm); - gen_movl_TN_reg(rd, r_const); - tcg_temp_free(r_const); + tcg_gen_movi_tl(dst, simm); + gen_store_gpr(dc, rd, dst); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_TN(rs2, cpu_dst); - gen_movl_TN_reg(rd, cpu_dst); + if (rs2 == 0) { + tcg_gen_movi_tl(dst, 0); + gen_store_gpr(dc, rd, dst); + } else { + cpu_src2 = gen_load_gpr(dc, rs2); + gen_store_gpr(dc, rd, cpu_src2); + } } } else { cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); - tcg_gen_ori_tl(cpu_dst, cpu_src1, simm); - gen_movl_TN_reg(rd, cpu_dst); + tcg_gen_ori_tl(dst, cpu_src1, simm); + gen_store_gpr(dc, rd, dst); } else { /* register */ - // or x, %g0, y -> mov T1, x; mov y, T1 rs2 = GET_FIELD(insn, 27, 31); - if (rs2 != 0) { - gen_movl_reg_TN(rs2, cpu_src2); - tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); - } else - gen_movl_TN_reg(rd, cpu_src1); + if (rs2 == 0) { + /* mov shortcut: or x, %g0, y -> mov x, y */ + gen_store_gpr(dc, rd, cpu_src1); + } else { + cpu_src2 = gen_load_gpr(dc, rs2); + tcg_gen_or_tl(dst, cpu_src1, cpu_src2); + gen_store_gpr(dc, rd, dst); + } } } #ifdef TARGET_SPARC64 @@ -3384,7 +3373,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); if (insn & (1 << 12)) { tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); } else { @@ -3392,7 +3381,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } tcg_gen_shl_i64(cpu_dst, cpu_src1, cpu_tmp0); } - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); } else if (xop == 0x26) { /* srl, V9 srlx */ cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ @@ -3405,7 +3394,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); if (insn & (1 << 12)) { tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); tcg_gen_shr_i64(cpu_dst, cpu_src1, cpu_tmp0); @@ -3415,7 +3404,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_shr_i64(cpu_dst, cpu_dst, cpu_tmp0); } } - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); } else if (xop == 0x27) { /* sra, V9 srax */ cpu_src1 = get_src1(insn, cpu_src1); if (IS_IMM) { /* immediate */ @@ -3423,24 +3412,22 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (insn & (1 << 12)) { tcg_gen_sari_i64(cpu_dst, cpu_src1, simm & 0x3f); } else { - tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL); - tcg_gen_ext32s_i64(cpu_dst, cpu_dst); + tcg_gen_ext32s_i64(cpu_dst, cpu_src1); tcg_gen_sari_i64(cpu_dst, cpu_dst, simm & 0x1f); } } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); if (insn & (1 << 12)) { tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); tcg_gen_sar_i64(cpu_dst, cpu_src1, cpu_tmp0); } else { tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x1f); - tcg_gen_andi_i64(cpu_dst, cpu_src1, 0xffffffffULL); - tcg_gen_ext32s_i64(cpu_dst, cpu_dst); + tcg_gen_ext32s_i64(cpu_dst, cpu_src1); tcg_gen_sar_i64(cpu_dst, cpu_dst, cpu_tmp0); } } - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); #endif } else if (xop < 0x36) { if (xop < 0x20) { @@ -3448,32 +3435,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) cpu_src2 = get_src2(insn, cpu_src2); switch (xop & ~0x10) { case 0x0: /* add */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - if (xop & 0x10) { - gen_op_addi_cc(cpu_dst, cpu_src1, simm); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD); - dc->cc_op = CC_OP_ADD; - } else { - tcg_gen_addi_tl(cpu_dst, cpu_src1, simm); - } + if (xop & 0x10) { + gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); + tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD); + dc->cc_op = CC_OP_ADD; } else { - if (xop & 0x10) { - gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD); - dc->cc_op = CC_OP_ADD; - } else { - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); - } + tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); } break; case 0x1: /* and */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_andi_tl(cpu_dst, cpu_src1, simm); - } else { - tcg_gen_and_tl(cpu_dst, cpu_src1, cpu_src2); - } + tcg_gen_and_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) { tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); @@ -3481,12 +3452,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } break; case 0x2: /* or */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_ori_tl(cpu_dst, cpu_src1, simm); - } else { - tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2); - } + tcg_gen_or_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) { tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); @@ -3494,12 +3460,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } break; case 0x3: /* xor */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_xori_tl(cpu_dst, cpu_src1, simm); - } else { - tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); - } + tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) { tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); @@ -3507,30 +3468,16 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } break; case 0x4: /* sub */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - if (xop & 0x10) { - gen_op_subi_cc(cpu_dst, cpu_src1, simm, dc); - } else { - tcg_gen_subi_tl(cpu_dst, cpu_src1, simm); - } + if (xop & 0x10) { + gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2); + tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB); + dc->cc_op = CC_OP_SUB; } else { - if (xop & 0x10) { - gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB); - dc->cc_op = CC_OP_SUB; - } else { - tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_src2); - } + tcg_gen_sub_tl(cpu_dst, cpu_src1, cpu_src2); } break; case 0x5: /* andn */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_andi_tl(cpu_dst, cpu_src1, ~simm); - } else { - tcg_gen_andc_tl(cpu_dst, cpu_src1, cpu_src2); - } + tcg_gen_andc_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) { tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); @@ -3538,12 +3485,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } break; case 0x6: /* orn */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_ori_tl(cpu_dst, cpu_src1, ~simm); - } else { - tcg_gen_orc_tl(cpu_dst, cpu_src1, cpu_src2); - } + tcg_gen_orc_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) { tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); @@ -3551,13 +3493,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } break; case 0x7: /* xorn */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_xori_tl(cpu_dst, cpu_src1, ~simm); - } else { - tcg_gen_not_tl(cpu_tmp0, cpu_src2); - tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_tmp0); - } + tcg_gen_eqv_tl(cpu_dst, cpu_src1, cpu_src2); if (xop & 0x10) { tcg_gen_mov_tl(cpu_cc_dst, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC); @@ -3570,12 +3506,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #ifdef TARGET_SPARC64 case 0x9: /* V9 mulx */ - if (IS_IMM) { - simm = GET_FIELDs(insn, 19, 31); - tcg_gen_muli_i64(cpu_dst, cpu_src1, simm); - } else { - tcg_gen_mul_i64(cpu_dst, cpu_src1, cpu_src2); - } + tcg_gen_mul_i64(cpu_dst, cpu_src1, cpu_src2); break; #endif case 0xa: /* umul */ @@ -3630,39 +3561,39 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) default: goto illegal_insn; } - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); } else { cpu_src1 = get_src1(insn, cpu_src1); cpu_src2 = get_src2(insn, cpu_src2); switch (xop) { case 0x20: /* taddcc */ gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_TADD); dc->cc_op = CC_OP_TADD; break; case 0x21: /* tsubcc */ gen_op_sub_cc(cpu_dst, cpu_src1, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_TSUB); dc->cc_op = CC_OP_TSUB; break; case 0x22: /* taddcctv */ gen_helper_taddcctv(cpu_dst, cpu_env, cpu_src1, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); dc->cc_op = CC_OP_TADDTV; break; case 0x23: /* tsubcctv */ gen_helper_tsubcctv(cpu_dst, cpu_env, cpu_src1, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); dc->cc_op = CC_OP_TSUBTV; break; case 0x24: /* mulscc */ update_psr(dc); gen_op_mulscc(cpu_dst, cpu_src1, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); tcg_gen_movi_i32(cpu_cc_op, CC_OP_ADD); dc->cc_op = CC_OP_ADD; break; @@ -3675,7 +3606,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); tcg_gen_shl_tl(cpu_dst, cpu_src1, cpu_tmp0); } - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x26: /* srl */ if (IS_IMM) { /* immediate */ @@ -3685,7 +3616,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); tcg_gen_shr_tl(cpu_dst, cpu_src1, cpu_tmp0); } - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x27: /* sra */ if (IS_IMM) { /* immediate */ @@ -3695,7 +3626,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); tcg_gen_sar_tl(cpu_dst, cpu_src1, cpu_tmp0); } - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; #endif case 0x30: @@ -4059,6 +3990,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) int cc = GET_FIELD_SP(insn, 11, 12); int cond = GET_FIELD_SP(insn, 14, 17); DisasCompare cmp; + TCGv dst; if (insn & (1 << 18)) { if (cc == 0) { @@ -4080,28 +4012,27 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_movi_tl(cpu_src2, simm); } - gen_movl_reg_TN(rd, cpu_dst); - tcg_gen_movcond_tl(cmp.cond, cpu_dst, + dst = gen_load_gpr(dc, rd); + tcg_gen_movcond_tl(cmp.cond, dst, cmp.c1, cmp.c2, - cpu_src2, cpu_dst); + cpu_src2, dst); free_compare(&cmp); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, dst); break; } case 0x2d: /* V9 sdivx */ gen_helper_sdivx(cpu_dst, cpu_env, cpu_src1, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x2e: /* V9 popc */ - { - cpu_src2 = get_src2(insn, cpu_src2); - gen_helper_popc(cpu_dst, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); - } + gen_helper_popc(cpu_dst, cpu_src2); + gen_store_gpr(dc, rd, cpu_dst); + break; case 0x2f: /* V9 movr */ { int cond = GET_FIELD_SP(insn, 10, 12); DisasCompare cmp; + TCGv dst; gen_compare_reg(&cmp, cond, cpu_src1); @@ -4113,12 +4044,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_movi_tl(cpu_src2, simm); } - gen_movl_reg_TN(rd, cpu_dst); - tcg_gen_movcond_tl(cmp.cond, cpu_dst, + dst = gen_load_gpr(dc, rd); + tcg_gen_movcond_tl(cmp.cond, dst, cmp.c1, cmp.c2, - cpu_src2, cpu_dst); + cpu_src2, dst); free_compare(&cmp); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, dst); break; } #endif @@ -4138,188 +4069,188 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) switch (opf) { case 0x000: /* VIS I edge8cc */ CHECK_FPU_FEATURE(dc, VIS1); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 1, 0); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x001: /* VIS II edge8n */ CHECK_FPU_FEATURE(dc, VIS2); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 0, 0); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x002: /* VIS I edge8lcc */ CHECK_FPU_FEATURE(dc, VIS1); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 1, 1); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x003: /* VIS II edge8ln */ CHECK_FPU_FEATURE(dc, VIS2); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 8, 0, 1); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x004: /* VIS I edge16cc */ CHECK_FPU_FEATURE(dc, VIS1); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 1, 0); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x005: /* VIS II edge16n */ CHECK_FPU_FEATURE(dc, VIS2); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 0, 0); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x006: /* VIS I edge16lcc */ CHECK_FPU_FEATURE(dc, VIS1); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 1, 1); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x007: /* VIS II edge16ln */ CHECK_FPU_FEATURE(dc, VIS2); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 16, 0, 1); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x008: /* VIS I edge32cc */ CHECK_FPU_FEATURE(dc, VIS1); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 1, 0); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x009: /* VIS II edge32n */ CHECK_FPU_FEATURE(dc, VIS2); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 0, 0); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x00a: /* VIS I edge32lcc */ CHECK_FPU_FEATURE(dc, VIS1); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 1, 1); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x00b: /* VIS II edge32ln */ CHECK_FPU_FEATURE(dc, VIS2); - gen_movl_reg_TN(rs1, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); gen_edge(dc, cpu_dst, cpu_src1, cpu_src2, 32, 0, 1); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x010: /* VIS I array8 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x012: /* VIS I array16 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); tcg_gen_shli_i64(cpu_dst, cpu_dst, 1); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x014: /* VIS I array32 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); tcg_gen_shli_i64(cpu_dst, cpu_dst, 2); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x018: /* VIS I alignaddr */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 0); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x01a: /* VIS I alignaddrl */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1 = get_src1(insn, cpu_src1); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 1); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x019: /* VIS II bmask */ CHECK_FPU_FEATURE(dc, VIS2); cpu_src1 = get_src1(insn, cpu_src1); - cpu_src2 = get_src1(insn, cpu_src2); + cpu_src2 = get_src2(insn, cpu_src2); tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, cpu_dst, 32, 32); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x020: /* VIS I fcmple16 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs1); cpu_src2_64 = gen_load_fpr_D(dc, rs2); gen_helper_fcmple16(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x022: /* VIS I fcmpne16 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs1); cpu_src2_64 = gen_load_fpr_D(dc, rs2); gen_helper_fcmpne16(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x024: /* VIS I fcmple32 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs1); cpu_src2_64 = gen_load_fpr_D(dc, rs2); gen_helper_fcmple32(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x026: /* VIS I fcmpne32 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs1); cpu_src2_64 = gen_load_fpr_D(dc, rs2); gen_helper_fcmpne32(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x028: /* VIS I fcmpgt16 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs1); cpu_src2_64 = gen_load_fpr_D(dc, rs2); gen_helper_fcmpgt16(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x02a: /* VIS I fcmpeq16 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs1); cpu_src2_64 = gen_load_fpr_D(dc, rs2); gen_helper_fcmpeq16(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x02c: /* VIS I fcmpgt32 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs1); cpu_src2_64 = gen_load_fpr_D(dc, rs2); gen_helper_fcmpgt32(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x02e: /* VIS I fcmpeq32 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs1); cpu_src2_64 = gen_load_fpr_D(dc, rs2); gen_helper_fcmpeq32(cpu_dst, cpu_src1_64, cpu_src2_64); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x031: /* VIS I fmul8x16 */ CHECK_FPU_FEATURE(dc, VIS1); @@ -4587,10 +4518,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); if (rs2) { - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); - } else + } else { tcg_gen_mov_tl(cpu_dst, cpu_src1); + } } gen_helper_restore(cpu_env); gen_mov_pc_npc(dc); @@ -4609,20 +4541,21 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); if (rs2) { - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); - } else + } else { tcg_gen_mov_tl(cpu_dst, cpu_src1); + } } switch (xop) { case 0x38: /* jmpl */ { - TCGv r_pc; + TCGv t; TCGv_i32 r_const; - r_pc = tcg_const_tl(dc->pc); - gen_movl_TN_reg(rd, r_pc); - tcg_temp_free(r_pc); + t = gen_dest_gpr(dc, rd); + tcg_gen_movi_tl(t, dc->pc); + gen_store_gpr(dc, rd, t); gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); gen_helper_check_align(cpu_env, cpu_dst, r_const); @@ -4657,12 +4590,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x3c: /* save */ save_state(dc); gen_helper_save(cpu_env); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; case 0x3d: /* restore */ save_state(dc); gen_helper_restore(cpu_env); - gen_movl_TN_reg(rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_dst); break; #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) case 0x3e: /* V9 done/retry */ @@ -4702,7 +4635,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) cpu_src1 = get_src1(insn, cpu_src1); if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa rs2 = GET_FIELD(insn, 27, 31); - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); tcg_gen_mov_tl(cpu_addr, cpu_src1); } else if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); @@ -4710,10 +4643,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); if (rs2 != 0) { - gen_movl_reg_TN(rs2, cpu_src2); + cpu_src2 = gen_load_gpr(dc, rs2); tcg_gen_add_tl(cpu_addr, cpu_src1, cpu_src2); - } else + } else { tcg_gen_mov_tl(cpu_addr, cpu_src1); + } } if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || (xop > 0x17 && xop <= 0x1d ) || @@ -4746,7 +4680,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx); tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64); tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffffULL); - gen_movl_TN_reg(rd + 1, cpu_tmp0); + gen_store_gpr(dc, rd + 1, cpu_tmp0); tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32); tcg_gen_trunc_i64_tl(cpu_val, cpu_tmp64); tcg_gen_andi_tl(cpu_val, cpu_val, 0xffffffffULL); @@ -4924,7 +4858,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) default: goto illegal_insn; } - gen_movl_TN_reg(rd, cpu_val); + gen_store_gpr(dc, rd, cpu_val); #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) skip_move: ; #endif @@ -5169,11 +5103,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x3c: /* V9 casa */ gen_cas_asi(cpu_val, cpu_addr, cpu_src2, insn, rd); - gen_movl_TN_reg(rd, cpu_val); + gen_store_gpr(dc, rd, cpu_val); break; case 0x3e: /* V9 casxa */ gen_casx_asi(cpu_val, cpu_addr, cpu_src2, insn, rd); - gen_movl_TN_reg(rd, cpu_val); + gen_store_gpr(dc, rd, cpu_val); break; #else case 0x34: /* stc */ From 9d1d4e342cb154a0f801eabd9758e90599893073 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:14 +1000 Subject: [PATCH 115/160] target-sparc: Use gen_load_gpr in get_src[12] This means we can avoid the incoming temporary, though the cleanup of the existing temporaries is not performed in this patch. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 75 ++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 0ec3d488c8..760cfd60c6 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2248,40 +2248,23 @@ static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn) } #endif -static inline TCGv get_src1(unsigned int insn, TCGv def) +static TCGv get_src1(DisasContext *dc, unsigned int insn) { - TCGv r_rs1 = def; - unsigned int rs1; - - rs1 = GET_FIELD(insn, 13, 17); - if (rs1 == 0) { - tcg_gen_movi_tl(def, 0); - } else if (rs1 < 8) { - r_rs1 = cpu_gregs[rs1]; - } else { - tcg_gen_ld_tl(def, cpu_regwptr, (rs1 - 8) * sizeof(target_ulong)); - } - return r_rs1; + unsigned int rs1 = GET_FIELD(insn, 13, 17); + return gen_load_gpr(dc, rs1); } -static inline TCGv get_src2(unsigned int insn, TCGv def) +static TCGv get_src2(DisasContext *dc, unsigned int insn) { - TCGv r_rs2 = def; - if (IS_IMM) { /* immediate */ target_long simm = GET_FIELDs(insn, 19, 31); - tcg_gen_movi_tl(def, simm); - } else { /* register */ + TCGv t = get_temp_tl(dc); + tcg_gen_movi_tl(t, simm); + return t; + } else { /* register */ unsigned int rs2 = GET_FIELD(insn, 27, 31); - if (rs2 == 0) { - tcg_gen_movi_tl(def, 0); - } else if (rs2 < 8) { - r_rs2 = cpu_gregs[rs2]; - } else { - tcg_gen_ld_tl(def, cpu_regwptr, (rs2 - 8) * sizeof(target_ulong)); - } + return gen_load_gpr(dc, rs2); } - return r_rs2; } #ifdef TARGET_SPARC64 @@ -2560,7 +2543,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) (GET_FIELD_SP(insn, 20, 21) << 14); target = sign_extend(target, 16); target <<= 2; - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = get_src1(dc, insn); do_branch_reg(dc, target, insn, cpu_src1); goto jmp_insn; } @@ -3187,7 +3170,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) do { \ DisasCompare cmp; \ cond = GET_FIELD_SP(insn, 14, 17); \ - cpu_src1 = get_src1(insn, cpu_src1); \ + cpu_src1 = get_src1(dc, insn); \ gen_compare_reg(&cmp, cond, cpu_src1); \ gen_fmov##sz(dc, &cmp, rd, rs2); \ free_compare(&cmp); \ @@ -3344,7 +3327,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } } } else { - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = get_src1(dc, insn); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); tcg_gen_ori_tl(dst, cpu_src1, simm); @@ -3363,7 +3346,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } #ifdef TARGET_SPARC64 } else if (xop == 0x25) { /* sll, V9 sllx */ - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = get_src1(dc, insn); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 20, 31); if (insn & (1 << 12)) { @@ -3383,7 +3366,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } gen_store_gpr(dc, rd, cpu_dst); } else if (xop == 0x26) { /* srl, V9 srlx */ - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = get_src1(dc, insn); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 20, 31); if (insn & (1 << 12)) { @@ -3406,7 +3389,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } gen_store_gpr(dc, rd, cpu_dst); } else if (xop == 0x27) { /* sra, V9 srax */ - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = get_src1(dc, insn); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 20, 31); if (insn & (1 << 12)) { @@ -3431,8 +3414,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif } else if (xop < 0x36) { if (xop < 0x20) { - cpu_src1 = get_src1(insn, cpu_src1); - cpu_src2 = get_src2(insn, cpu_src2); + cpu_src1 = get_src1(dc, insn); + cpu_src2 = get_src2(dc, insn); switch (xop & ~0x10) { case 0x0: /* add */ if (xop & 0x10) { @@ -3563,8 +3546,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } gen_store_gpr(dc, rd, cpu_dst); } else { - cpu_src1 = get_src1(insn, cpu_src1); - cpu_src2 = get_src2(insn, cpu_src2); + cpu_src1 = get_src1(dc, insn); + cpu_src2 = get_src2(dc, insn); switch (xop) { case 0x20: /* taddcc */ gen_op_add_cc(cpu_dst, cpu_src1, cpu_src2); @@ -4153,14 +4136,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x010: /* VIS I array8 */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = gen_load_gpr(dc, rs1); cpu_src2 = gen_load_gpr(dc, rs2); gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); gen_store_gpr(dc, rd, cpu_dst); break; case 0x012: /* VIS I array16 */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = gen_load_gpr(dc, rs1); cpu_src2 = gen_load_gpr(dc, rs2); gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); tcg_gen_shli_i64(cpu_dst, cpu_dst, 1); @@ -4168,7 +4151,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x014: /* VIS I array32 */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = gen_load_gpr(dc, rs1); cpu_src2 = gen_load_gpr(dc, rs2); gen_helper_array8(cpu_dst, cpu_src1, cpu_src2); tcg_gen_shli_i64(cpu_dst, cpu_dst, 2); @@ -4176,22 +4159,22 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x018: /* VIS I alignaddr */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = gen_load_gpr(dc, rs1); cpu_src2 = gen_load_gpr(dc, rs2); gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 0); gen_store_gpr(dc, rd, cpu_dst); break; case 0x01a: /* VIS I alignaddrl */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = gen_load_gpr(dc, rs1); cpu_src2 = gen_load_gpr(dc, rs2); gen_alignaddr(cpu_dst, cpu_src1, cpu_src2, 1); gen_store_gpr(dc, rd, cpu_dst); break; case 0x019: /* VIS II bmask */ CHECK_FPU_FEATURE(dc, VIS2); - cpu_src1 = get_src1(insn, cpu_src1); - cpu_src2 = get_src2(insn, cpu_src2); + cpu_src1 = gen_load_gpr(dc, rs1); + cpu_src2 = gen_load_gpr(dc, rs2); tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, cpu_dst, 32, 32); gen_store_gpr(dc, rd, cpu_dst); @@ -4511,7 +4494,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) TCGv_i32 r_const; save_state(dc); - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = get_src1(dc, insn); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); tcg_gen_addi_tl(cpu_dst, cpu_src1, simm); @@ -4534,7 +4517,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto jmp_insn; #endif } else { - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = get_src1(dc, insn); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); tcg_gen_addi_tl(cpu_dst, cpu_src1, simm); @@ -4632,7 +4615,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { unsigned int xop = GET_FIELD(insn, 7, 12); - cpu_src1 = get_src1(insn, cpu_src1); + cpu_src1 = get_src1(dc, insn); if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa rs2 = GET_FIELD(insn, 27, 31); cpu_src2 = gen_load_gpr(dc, rs2); From c7785e1682405d8ec7002918c76857aaebd812b2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:15 +1000 Subject: [PATCH 116/160] target-sparc: Convert asi helpers to gen_*_gpr Push the DisasContext down so that we can use gen_load/store_gpr in sode gen_ldda_asi, gen_stda_ast, gen_cas_asi, gen_casx_asi. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 61 +++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 760cfd60c6..f4ab6ccc92 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2101,7 +2101,8 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) tcg_gen_trunc_i64_tl(dst, cpu_tmp64); } -static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd) +static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, + int insn, int rd) { TCGv_i32 r_asi, r_rd; @@ -2112,12 +2113,13 @@ static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd) tcg_temp_free_i32(r_asi); } -static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd) +static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, + int insn, int rd) { TCGv_i32 r_asi, r_size; + TCGv lo = gen_load_gpr(dc, rd + 1); - gen_movl_reg_TN(rd + 1, cpu_tmp0); - tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi); + tcg_gen_concat_tl_i64(cpu_tmp64, lo, hi); r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(8); gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size); @@ -2125,28 +2127,23 @@ static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd) tcg_temp_free_i32(r_asi); } -static inline void gen_cas_asi(TCGv dst, TCGv addr, TCGv val2, int insn, - int rd) +static inline void gen_cas_asi(DisasContext *dc, TCGv dst, TCGv addr, + TCGv val2, int insn, int rd) { - TCGv r_val1; - TCGv_i32 r_asi; + TCGv r_val1 = gen_load_gpr(dc, rd); + TCGv_i32 r_asi = gen_get_asi(insn, addr); - r_val1 = tcg_temp_new(); - gen_movl_reg_TN(rd, r_val1); - r_asi = gen_get_asi(insn, addr); gen_helper_cas_asi(dst, cpu_env, addr, r_val1, val2, r_asi); tcg_temp_free_i32(r_asi); - tcg_temp_free(r_val1); } -static inline void gen_casx_asi(TCGv dst, TCGv addr, TCGv val2, int insn, - int rd) +static inline void gen_casx_asi(DisasContext *dc, TCGv dst, TCGv addr, + TCGv val2, int insn, int rd) { - TCGv_i32 r_asi; + TCGv r_val1 = gen_load_gpr(dc, rd); + TCGv_i32 r_asi = gen_get_asi(insn, addr); - gen_movl_reg_TN(rd, cpu_tmp64); - r_asi = gen_get_asi(insn, addr); - gen_helper_casx_asi(dst, cpu_env, addr, cpu_tmp64, val2, r_asi); + gen_helper_casx_asi(dst, cpu_env, addr, r_val1, val2, r_asi); tcg_temp_free_i32(r_asi); } @@ -2198,9 +2195,11 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) tcg_gen_trunc_i64_tl(dst, cpu_tmp64); } -static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd) +static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, + int insn, int rd) { TCGv_i32 r_asi, r_size, r_sign; + TCGv t; r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(8); @@ -2209,19 +2208,23 @@ static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd) tcg_temp_free(r_sign); tcg_temp_free(r_size); tcg_temp_free(r_asi); - tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64); - gen_movl_TN_reg(rd + 1, cpu_tmp0); + + t = gen_dest_gpr(dc, rd + 1); + tcg_gen_trunc_i64_tl(t, cpu_tmp64); + gen_store_gpr(dc, rd + 1, t); + tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32); tcg_gen_trunc_i64_tl(hi, cpu_tmp64); - gen_movl_TN_reg(rd, hi); + gen_store_gpr(dc, rd, hi); } -static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd) +static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, + int insn, int rd) { TCGv_i32 r_asi, r_size; + TCGv lo = gen_load_gpr(dc, rd + 1); - gen_movl_reg_TN(rd + 1, cpu_tmp0); - tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi); + tcg_gen_concat_tl_i64(cpu_tmp64, lo, hi); r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(8); gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size); @@ -4738,7 +4741,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (rd & 1) goto illegal_insn; save_state(dc); - gen_ldda_asi(cpu_val, cpu_addr, insn, rd); + gen_ldda_asi(dc, cpu_val, cpu_addr, insn, rd); goto skip_move; case 0x19: /* ldsba, load signed byte alternate */ #ifndef TARGET_SPARC64 @@ -4976,7 +4979,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; else { save_state(dc); - gen_stda_asi(cpu_val, cpu_addr, insn, rd); + gen_stda_asi(dc, cpu_val, cpu_addr, insn, rd); } break; #endif @@ -5085,11 +5088,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); break; case 0x3c: /* V9 casa */ - gen_cas_asi(cpu_val, cpu_addr, cpu_src2, insn, rd); + gen_cas_asi(dc, cpu_val, cpu_addr, cpu_src2, insn, rd); gen_store_gpr(dc, rd, cpu_val); break; case 0x3e: /* V9 casxa */ - gen_casx_asi(cpu_val, cpu_addr, cpu_src2, insn, rd); + gen_casx_asi(dc, cpu_val, cpu_addr, cpu_src2, insn, rd); gen_store_gpr(dc, rd, cpu_val); break; #else From 06828032e3f88710b3135ff55ecf1c0308027900 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:16 +1000 Subject: [PATCH 117/160] target-sparc: Convert swap to gen_load/store_gpr Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index f4ab6ccc92..8a2e91439f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2086,7 +2086,7 @@ static inline void gen_stf_asi(TCGv addr, int insn, int size, int rd) tcg_temp_free_i32(r_asi); } -static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) +static inline void gen_swap_asi(TCGv dst, TCGv src, TCGv addr, int insn) { TCGv_i32 r_asi, r_size, r_sign; @@ -2095,7 +2095,7 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) r_sign = tcg_const_i32(0); gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free_i32(r_sign); - gen_helper_st_asi(cpu_env, addr, dst, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, src, r_asi, r_size); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); tcg_gen_trunc_i64_tl(dst, cpu_tmp64); @@ -2176,7 +2176,7 @@ static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size) tcg_temp_free(r_asi); } -static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) +static inline void gen_swap_asi(TCGv dst, TCGv src, TCGv addr, int insn) { TCGv_i32 r_asi, r_size, r_sign; TCGv_i64 r_val; @@ -2187,7 +2187,7 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free(r_sign); r_val = tcg_temp_new_i64(); - tcg_gen_extu_tl_i64(r_val, dst); + tcg_gen_extu_tl_i64(r_val, src); gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size); tcg_temp_free_i64(r_val); tcg_temp_free(r_size); @@ -4694,10 +4694,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x0f: /* swap, swap register with memory. Also atomically */ CHECK_IU_FEATURE(dc, SWAP); - gen_movl_reg_TN(rd, cpu_val); + cpu_src1 = gen_load_gpr(dc, rd); gen_address_mask(dc, cpu_addr); tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); - tcg_gen_qemu_st32(cpu_val, cpu_addr, dc->mem_idx); + tcg_gen_qemu_st32(cpu_src1, cpu_addr, dc->mem_idx); tcg_gen_mov_tl(cpu_val, cpu_tmp0); break; #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) @@ -4783,8 +4783,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto priv_insn; #endif save_state(dc); - gen_movl_reg_TN(rd, cpu_val); - gen_swap_asi(cpu_val, cpu_addr, insn); + cpu_src1 = gen_load_gpr(dc, rd); + gen_swap_asi(cpu_val, cpu_src1, cpu_addr, insn); break; #ifndef TARGET_SPARC64 From 81634eea3d5dada203848f89ebd97d6a05aa4cce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:17 +1000 Subject: [PATCH 118/160] target-sparc: Finish conversion to gen_load_gpr All users of gen_movl_{reg_TN,TN_reg} are removed. At the same time, make cpu_val a local variable for load/store disassembly. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 58 ++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 8a2e91439f..3c9b0e3412 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -48,7 +48,7 @@ static TCGv cpu_y; #ifndef CONFIG_USER_ONLY static TCGv cpu_tbr; #endif -static TCGv cpu_cond, cpu_dst, cpu_addr, cpu_val; +static TCGv cpu_cond, cpu_dst, cpu_addr; #ifdef TARGET_SPARC64 static TCGv_i32 cpu_xcc, cpu_asi, cpu_fprs; static TCGv cpu_gsr; @@ -308,28 +308,6 @@ static inline TCGv gen_dest_gpr(DisasContext *dc, int reg) } } -static inline void gen_movl_reg_TN(int reg, TCGv tn) -{ - if (reg == 0) - tcg_gen_movi_tl(tn, 0); - else if (reg < 8) - tcg_gen_mov_tl(tn, cpu_gregs[reg]); - else { - tcg_gen_ld_tl(tn, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); - } -} - -static inline void gen_movl_TN_reg(int reg, TCGv tn) -{ - if (reg == 0) - return; - else if (reg < 8) - tcg_gen_mov_tl(cpu_gregs[reg], tn); - else { - tcg_gen_st_tl(tn, cpu_regwptr, (reg - 8) * sizeof(target_ulong)); - } -} - static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc, target_ulong npc) { @@ -2127,24 +2105,28 @@ static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, tcg_temp_free_i32(r_asi); } -static inline void gen_cas_asi(DisasContext *dc, TCGv dst, TCGv addr, +static inline void gen_cas_asi(DisasContext *dc, TCGv addr, TCGv val2, int insn, int rd) { - TCGv r_val1 = gen_load_gpr(dc, rd); + TCGv val1 = gen_load_gpr(dc, rd); + TCGv dst = gen_dest_gpr(dc, rd); TCGv_i32 r_asi = gen_get_asi(insn, addr); - gen_helper_cas_asi(dst, cpu_env, addr, r_val1, val2, r_asi); + gen_helper_cas_asi(dst, cpu_env, addr, val1, val2, r_asi); tcg_temp_free_i32(r_asi); + gen_store_gpr(dc, rd, dst); } -static inline void gen_casx_asi(DisasContext *dc, TCGv dst, TCGv addr, +static inline void gen_casx_asi(DisasContext *dc, TCGv addr, TCGv val2, int insn, int rd) { - TCGv r_val1 = gen_load_gpr(dc, rd); + TCGv val1 = gen_load_gpr(dc, rd); + TCGv dst = gen_dest_gpr(dc, rd); TCGv_i32 r_asi = gen_get_asi(insn, addr); - gen_helper_casx_asi(dst, cpu_env, addr, r_val1, val2, r_asi); + gen_helper_casx_asi(dst, cpu_env, addr, val1, val2, r_asi); tcg_temp_free_i32(r_asi); + gen_store_gpr(dc, rd, dst); } #elif !defined(CONFIG_USER_ONLY) @@ -4638,6 +4620,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || (xop > 0x17 && xop <= 0x1d ) || (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) { + TCGv cpu_val = gen_dest_gpr(dc, rd); + switch (xop) { case 0x0: /* ld, V9 lduw, load unsigned word */ gen_address_mask(dc, cpu_addr); @@ -4903,7 +4887,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || xop == 0xe || xop == 0x1e) { - gen_movl_reg_TN(rd, cpu_val); + TCGv cpu_val = gen_load_gpr(dc, rd); + switch (xop) { case 0x4: /* st, store word */ gen_address_mask(dc, cpu_addr); @@ -4922,6 +4907,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; else { TCGv_i32 r_const; + TCGv lo; save_state(dc); gen_address_mask(dc, cpu_addr); @@ -4929,8 +4915,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) /* XXX remove alignment check */ gen_helper_check_align(cpu_env, cpu_addr, r_const); tcg_temp_free_i32(r_const); - gen_movl_reg_TN(rd + 1, cpu_tmp0); - tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, cpu_val); + lo = gen_load_gpr(dc, rd + 1); + tcg_gen_concat_tl_i64(cpu_tmp64, lo, cpu_val); tcg_gen_qemu_st64(cpu_tmp64, cpu_addr, dc->mem_idx); } break; @@ -5088,12 +5074,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); break; case 0x3c: /* V9 casa */ - gen_cas_asi(dc, cpu_val, cpu_addr, cpu_src2, insn, rd); - gen_store_gpr(dc, rd, cpu_val); + gen_cas_asi(dc, cpu_addr, cpu_src2, insn, rd); break; case 0x3e: /* V9 casxa */ - gen_casx_asi(dc, cpu_val, cpu_addr, cpu_src2, insn, rd); - gen_store_gpr(dc, rd, cpu_val); + gen_casx_asi(dc, cpu_addr, cpu_src2, insn, rd); break; #else case 0x34: /* stc */ @@ -5269,14 +5253,12 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, cpu_tmp32 = tcg_temp_new_i32(); cpu_tmp64 = tcg_temp_new_i64(); cpu_dst = tcg_temp_new(); - cpu_val = tcg_temp_new(); cpu_addr = tcg_temp_new(); disas_sparc_insn(dc, insn); num_insns++; tcg_temp_free(cpu_addr); - tcg_temp_free(cpu_val); tcg_temp_free(cpu_dst); tcg_temp_free_i64(cpu_tmp64); tcg_temp_free_i32(cpu_tmp32); From a4273524875a960e8ef22ed676853e5988fefbea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:18 +1000 Subject: [PATCH 119/160] target-sparc: Cleanup cpu_src[12] allocation Now that get_temp_tl is used for get_src[12], we don't need to pre-allocate these temporaries. Fallout from this is moving some assignments around cas/casx to avoid uninitialized variable warnings. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 3c9b0e3412..2a95c1fdeb 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2483,7 +2483,7 @@ static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2) static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { unsigned int opc, rs1, rs2, rd; - TCGv cpu_src1, cpu_src2, cpu_tmp1, cpu_tmp2; + TCGv cpu_src1, cpu_src2; TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32; TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64; target_long simm; @@ -2496,9 +2496,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) rd = GET_FIELD(insn, 2, 6); - cpu_tmp1 = cpu_src1 = tcg_temp_new(); - cpu_tmp2 = cpu_src2 = tcg_temp_new(); - switch (opc) { case 0: /* branches/sethi */ { @@ -4602,8 +4599,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) cpu_src1 = get_src1(dc, insn); if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa - rs2 = GET_FIELD(insn, 27, 31); - cpu_src2 = gen_load_gpr(dc, rs2); tcg_gen_mov_tl(cpu_addr, cpu_src1); } else if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); @@ -5074,9 +5069,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd)); break; case 0x3c: /* V9 casa */ + rs2 = GET_FIELD(insn, 27, 31); + cpu_src2 = gen_load_gpr(dc, rs2); gen_cas_asi(dc, cpu_addr, cpu_src2, insn, rd); break; case 0x3e: /* V9 casxa */ + rs2 = GET_FIELD(insn, 27, 31); + cpu_src2 = gen_load_gpr(dc, rs2); gen_casx_asi(dc, cpu_addr, cpu_src2, insn, rd); break; #else @@ -5089,8 +5088,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) default: goto illegal_insn; } - } else + } else { goto illegal_insn; + } } break; } @@ -5169,8 +5169,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto egress; #endif egress: - tcg_temp_free(cpu_tmp1); - tcg_temp_free(cpu_tmp2); if (dc->n_t32 != 0) { int i; for (i = dc->n_t32 - 1; i >= 0; --i) { From 5e6ed43923830b09989a9a2fa2255dadadee67f2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:19 +1000 Subject: [PATCH 120/160] target-sparc: Make the cpu_addr variable local to load/store handling Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 2a95c1fdeb..e3e4256f1e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -48,7 +48,7 @@ static TCGv cpu_y; #ifndef CONFIG_USER_ONLY static TCGv cpu_tbr; #endif -static TCGv cpu_cond, cpu_dst, cpu_addr; +static TCGv cpu_cond, cpu_dst; #ifdef TARGET_SPARC64 static TCGv_i32 cpu_xcc, cpu_asi, cpu_fprs; static TCGv cpu_gsr; @@ -4596,20 +4596,22 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 3: /* load/store instructions */ { unsigned int xop = GET_FIELD(insn, 7, 12); + /* ??? gen_address_mask prevents us from using a source + register directly. Always generate a temporary. */ + TCGv cpu_addr = get_temp_tl(dc); - cpu_src1 = get_src1(dc, insn); - if (xop == 0x3c || xop == 0x3e) { // V9 casa/casxa - tcg_gen_mov_tl(cpu_addr, cpu_src1); + tcg_gen_mov_tl(cpu_addr, get_src1(dc, insn)); + if (xop == 0x3c || xop == 0x3e) { + /* V9 casa/casxa : no offset */ } else if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); - tcg_gen_addi_tl(cpu_addr, cpu_src1, simm); + if (simm != 0) { + tcg_gen_addi_tl(cpu_addr, cpu_addr, simm); + } } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); if (rs2 != 0) { - cpu_src2 = gen_load_gpr(dc, rs2); - tcg_gen_add_tl(cpu_addr, cpu_src1, cpu_src2); - } else { - tcg_gen_mov_tl(cpu_addr, cpu_src1); + tcg_gen_add_tl(cpu_addr, cpu_addr, gen_load_gpr(dc, rs2)); } } if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || @@ -5251,12 +5253,10 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, cpu_tmp32 = tcg_temp_new_i32(); cpu_tmp64 = tcg_temp_new_i64(); cpu_dst = tcg_temp_new(); - cpu_addr = tcg_temp_new(); disas_sparc_insn(dc, insn); num_insns++; - tcg_temp_free(cpu_addr); tcg_temp_free(cpu_dst); tcg_temp_free_i64(cpu_tmp64); tcg_temp_free_i32(cpu_tmp32); From 2ae23e178263ecb7faebd37d9706f36a5cba9791 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:20 +1000 Subject: [PATCH 121/160] target-sparc: Split out get_temp_i32 Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index e3e4256f1e..5296a37240 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -125,6 +125,22 @@ static int sign_extend(int x, int len) #define IS_IMM (insn & (1<<13)) +static inline TCGv_i32 get_temp_i32(DisasContext *dc) +{ + TCGv_i32 t; + assert(dc->n_t32 < ARRAY_SIZE(dc->t32)); + dc->t32[dc->n_t32++] = t = tcg_temp_new_i32(); + return t; +} + +static inline TCGv get_temp_tl(DisasContext *dc) +{ + TCGv t; + assert(dc->n_ttl < ARRAY_SIZE(dc->ttl)); + dc->ttl[dc->n_ttl++] = t = tcg_temp_new(); + return t; +} + static inline void gen_update_fprs_dirty(int rd) { #if defined(TARGET_SPARC64) @@ -145,16 +161,13 @@ static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) if (src & 1) { return MAKE_TCGV_I32(GET_TCGV_I64(cpu_fpr[src / 2])); } else { - TCGv_i32 ret = tcg_temp_new_i32(); + TCGv_i32 ret = get_temp_i32(dc); TCGv_i64 t = tcg_temp_new_i64(); tcg_gen_shri_i64(t, cpu_fpr[src / 2], 32); tcg_gen_trunc_i64_i32(ret, t); tcg_temp_free_i64(t); - dc->t32[dc->n_t32++] = ret; - assert(dc->n_t32 <= ARRAY_SIZE(dc->t32)); - return ret; } #endif @@ -265,14 +278,6 @@ static inline void gen_address_mask(DisasContext *dc, TCGv addr) #endif } -static inline TCGv get_temp_tl(DisasContext *dc) -{ - TCGv t; - assert(dc->n_ttl < ARRAY_SIZE(dc->ttl)); - dc->ttl[dc->n_ttl++] = t = tcg_temp_new(); - return t; -} - static inline TCGv gen_load_gpr(DisasContext *dc, int reg) { if (reg == 0 || reg >= 8) { From ba5f5179f2c27c7e9891e404f526d3463e3f4a15 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:21 +1000 Subject: [PATCH 122/160] target-sparc: Use get_temp_i32 in gen_dest_fpr_F Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 5296a37240..5013aeeed2 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -189,9 +189,9 @@ static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v) gen_update_fprs_dirty(dst); } -static TCGv_i32 gen_dest_fpr_F(void) +static TCGv_i32 gen_dest_fpr_F(DisasContext *dc) { - return cpu_tmp32; + return get_temp_i32(dc); } static TCGv_i64 gen_load_fpr_D(DisasContext *dc, unsigned int src) @@ -1703,7 +1703,7 @@ static inline void gen_fop_FF(DisasContext *dc, int rd, int rs, TCGv_i32 dst, src; src = gen_load_fpr_F(dc, rs); - dst = gen_dest_fpr_F(); + dst = gen_dest_fpr_F(dc); gen(dst, cpu_env, src); @@ -1716,7 +1716,7 @@ static inline void gen_ne_fop_FF(DisasContext *dc, int rd, int rs, TCGv_i32 dst, src; src = gen_load_fpr_F(dc, rs); - dst = gen_dest_fpr_F(); + dst = gen_dest_fpr_F(dc); gen(dst, src); @@ -1730,7 +1730,7 @@ static inline void gen_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2, src1 = gen_load_fpr_F(dc, rs1); src2 = gen_load_fpr_F(dc, rs2); - dst = gen_dest_fpr_F(); + dst = gen_dest_fpr_F(dc); gen(dst, cpu_env, src1, src2); @@ -1745,7 +1745,7 @@ static inline void gen_ne_fop_FFF(DisasContext *dc, int rd, int rs1, int rs2, src1 = gen_load_fpr_F(dc, rs1); src2 = gen_load_fpr_F(dc, rs2); - dst = gen_dest_fpr_F(); + dst = gen_dest_fpr_F(dc); gen(dst, src1, src2); @@ -1942,7 +1942,7 @@ static inline void gen_fop_FD(DisasContext *dc, int rd, int rs, TCGv_i64 src; src = gen_load_fpr_D(dc, rs); - dst = gen_dest_fpr_F(); + dst = gen_dest_fpr_F(dc); gen(dst, cpu_env, src); @@ -1955,7 +1955,7 @@ static inline void gen_fop_FQ(DisasContext *dc, int rd, int rs, TCGv_i32 dst; gen_op_load_fpr_QT1(QFPREG(rs)); - dst = gen_dest_fpr_F(); + dst = gen_dest_fpr_F(dc); gen(dst, cpu_env); @@ -2277,7 +2277,7 @@ static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs) s1 = gen_load_fpr_F(dc, rs); s2 = gen_load_fpr_F(dc, rd); - dst = gen_dest_fpr_F(); + dst = gen_dest_fpr_F(dc); zero = tcg_const_i32(0); tcg_gen_movcond_i32(TCG_COND_NE, dst, c32, zero, s1, s2); @@ -4257,14 +4257,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x03b: /* VIS I fpack16 */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs2); - cpu_dst_32 = gen_dest_fpr_F(); + cpu_dst_32 = gen_dest_fpr_F(dc); gen_helper_fpack16(cpu_dst_32, cpu_gsr, cpu_src1_64); gen_store_fpr_F(dc, rd, cpu_dst_32); break; case 0x03d: /* VIS I fpackfix */ CHECK_FPU_FEATURE(dc, VIS1); cpu_src1_64 = gen_load_fpr_D(dc, rs2); - cpu_dst_32 = gen_dest_fpr_F(); + cpu_dst_32 = gen_dest_fpr_F(dc); gen_helper_fpackfix(cpu_dst_32, cpu_gsr, cpu_src1_64); gen_store_fpr_F(dc, rd, cpu_dst_32); break; @@ -4328,7 +4328,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x061: /* VIS I fzeros */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_dst_32 = gen_dest_fpr_F(); + cpu_dst_32 = gen_dest_fpr_F(dc); tcg_gen_movi_i32(cpu_dst_32, 0); gen_store_fpr_F(dc, rd, cpu_dst_32); break; @@ -4456,7 +4456,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x07f: /* VIS I fones */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_dst_32 = gen_dest_fpr_F(); + cpu_dst_32 = gen_dest_fpr_F(dc); tcg_gen_movi_i32(cpu_dst_32, -1); gen_store_fpr_F(dc, rd, cpu_dst_32); break; @@ -4843,7 +4843,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x20: /* ldf, load fpreg */ gen_address_mask(dc, cpu_addr); tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); - cpu_dst_32 = gen_dest_fpr_F(); + cpu_dst_32 = gen_dest_fpr_F(dc); tcg_gen_trunc_tl_i32(cpu_dst_32, cpu_tmp0); gen_store_fpr_F(dc, rd, cpu_dst_32); break; From 45778f99f0fb088af1f92d9a92759b760dceef2a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:22 +1000 Subject: [PATCH 123/160] target-sparc: Avoid cpu_tmp32 in Read Priv Register We don't need another temporary here. Load directly into the register we want to set. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 53 ++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 5013aeeed2..43e44d55de 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2865,14 +2865,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 3: // tt { - TCGv_ptr r_tsptr; + TCGv_ptr r_tsptr = tcg_temp_new_ptr(); - r_tsptr = tcg_temp_new_ptr(); gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_ld_i32(cpu_tmp32, r_tsptr, - offsetof(trap_state, tt)); + tcg_gen_ld32s_tl(cpu_tmp0, r_tsptr, + offsetof(trap_state, tt)); tcg_temp_free_ptr(r_tsptr); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); } break; case 4: // tick @@ -2890,53 +2888,44 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_mov_tl(cpu_tmp0, cpu_tbr); break; case 6: // pstate - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, pstate)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, pstate)); break; case 7: // tl - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, tl)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, tl)); break; case 8: // pil - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, psrpil)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, psrpil)); break; case 9: // cwp gen_helper_rdcwp(cpu_tmp0, cpu_env); break; case 10: // cansave - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, cansave)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, cansave)); break; case 11: // canrestore - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, canrestore)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, canrestore)); break; case 12: // cleanwin - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, cleanwin)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, cleanwin)); break; case 13: // otherwin - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, otherwin)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, otherwin)); break; case 14: // wstate - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, wstate)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, wstate)); break; case 16: // UA2005 gl CHECK_IU_FEATURE(dc, GL); - tcg_gen_ld_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, gl)); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_tmp32); + tcg_gen_ld32s_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, gl)); break; case 26: // UA2005 strand status CHECK_IU_FEATURE(dc, HYPV); From 7b9e066b67c1f8839a1ca63efebcbaf48cc60104 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:23 +1000 Subject: [PATCH 124/160] target-sparc: Avoid cpu_tmp32 in Write Priv Register No need to copy to a temporary to store 32 bits. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 56 +++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 43e44d55de..353ebc60a4 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3801,9 +3801,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) r_tsptr = tcg_temp_new_ptr(); gen_load_trap_state_at_tl(r_tsptr, cpu_env); - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - tcg_gen_st_i32(cpu_tmp32, r_tsptr, - offsetof(trap_state, tt)); + tcg_gen_st32_tl(cpu_tmp0, r_tsptr, + offsetof(trap_state, tt)); tcg_temp_free_ptr(r_tsptr); } break; @@ -3829,8 +3828,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 7: // tl save_state(dc); - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - tcg_gen_st_i32(cpu_tmp32, cpu_env, + tcg_gen_st32_tl(cpu_tmp0, cpu_env, offsetof(CPUSPARCState, tl)); dc->npc = DYNAMIC_PC; break; @@ -3841,40 +3839,34 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_wrcwp(cpu_env, cpu_tmp0); break; case 10: // cansave - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - tcg_gen_st_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, - cansave)); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, + cansave)); break; case 11: // canrestore - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - tcg_gen_st_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, - canrestore)); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, + canrestore)); break; case 12: // cleanwin - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - tcg_gen_st_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, - cleanwin)); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, + cleanwin)); break; case 13: // otherwin - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - tcg_gen_st_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, - otherwin)); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, + otherwin)); break; case 14: // wstate - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - tcg_gen_st_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, - wstate)); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, + wstate)); break; case 16: // UA2005 gl CHECK_IU_FEATURE(dc, GL); - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - tcg_gen_st_i32(cpu_tmp32, cpu_env, - offsetof(CPUSPARCState, gl)); + tcg_gen_st32_tl(cpu_tmp0, cpu_env, + offsetof(CPUSPARCState, gl)); break; case 26: // UA2005 strand status CHECK_IU_FEATURE(dc, HYPV); @@ -3886,11 +3878,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } #else - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - if (dc->def->nwindows != 32) - tcg_gen_andi_tl(cpu_tmp32, cpu_tmp32, + tcg_gen_trunc_tl_i32(cpu_wim, cpu_tmp0); + if (dc->def->nwindows != 32) { + tcg_gen_andi_tl(cpu_wim, cpu_wim, (1 << dc->def->nwindows) - 1); - tcg_gen_mov_i32(cpu_wim, cpu_tmp32); + } #endif } break; From f8641947c2268eab6e73f16883c08ae14432280c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:24 +1000 Subject: [PATCH 125/160] target-sparc: Tidy ldfsr, stfsr Remove the last uses of cpu_tmp32. Unify the code between sparc64 and sparc32 by using the proper "tl" functions. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 353ebc60a4..ed341b896f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -60,7 +60,6 @@ static TCGv cpu_wim; #endif /* local register indexes (only used inside old micro ops) */ static TCGv cpu_tmp0; -static TCGv_i32 cpu_tmp32; static TCGv_i64 cpu_tmp64; /* Floating point registers */ static TCGv_i64 cpu_fpr[TARGET_DPREGS]; @@ -4834,17 +4833,15 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) if (rd == 1) { tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx); gen_helper_ldxfsr(cpu_env, cpu_tmp64); - } else { - tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); - tcg_gen_trunc_tl_i32(cpu_tmp32, cpu_tmp0); - gen_helper_ldfsr(cpu_env, cpu_tmp32); - } -#else - { - tcg_gen_qemu_ld32u(cpu_tmp32, cpu_addr, dc->mem_idx); - gen_helper_ldfsr(cpu_env, cpu_tmp32); + break; } #endif + { + TCGv_i32 t32 = get_temp_i32(dc); + tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); + tcg_gen_trunc_tl_i32(t32, cpu_tmp0); + gen_helper_ldfsr(cpu_env, t32); + } break; case 0x22: /* ldqf, load quad fpreg */ { @@ -4979,17 +4976,19 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_gen_qemu_st32(cpu_tmp0, cpu_addr, dc->mem_idx); break; case 0x25: /* stfsr, V9 stxfsr */ + { + TCGv t = get_temp_tl(dc); + + tcg_gen_ld_tl(t, cpu_env, offsetof(CPUSPARCState, fsr)); #ifdef TARGET_SPARC64 - gen_address_mask(dc, cpu_addr); - tcg_gen_ld_i64(cpu_tmp64, cpu_env, offsetof(CPUSPARCState, fsr)); - if (rd == 1) - tcg_gen_qemu_st64(cpu_tmp64, cpu_addr, dc->mem_idx); - else - tcg_gen_qemu_st32(cpu_tmp64, cpu_addr, dc->mem_idx); -#else - tcg_gen_ld_i32(cpu_tmp32, cpu_env, offsetof(CPUSPARCState, fsr)); - tcg_gen_qemu_st32(cpu_tmp32, cpu_addr, dc->mem_idx); + gen_address_mask(dc, cpu_addr); + if (rd == 1) { + tcg_gen_qemu_st64(t, cpu_addr, dc->mem_idx); + break; + } #endif + tcg_gen_qemu_st32(t, cpu_addr, dc->mem_idx); + } break; case 0x26: #ifdef TARGET_SPARC64 @@ -5236,7 +5235,6 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, insn = cpu_ldl_code(env, dc->pc); cpu_tmp0 = tcg_temp_new(); - cpu_tmp32 = tcg_temp_new_i32(); cpu_tmp64 = tcg_temp_new_i64(); cpu_dst = tcg_temp_new(); @@ -5245,7 +5243,6 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, tcg_temp_free(cpu_dst); tcg_temp_free_i64(cpu_tmp64); - tcg_temp_free_i32(cpu_tmp32); tcg_temp_free(cpu_tmp0); if (dc->is_br) From 1ec789ab68a9eabb5de8b1ba732d60a8fcb00446 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:25 +1000 Subject: [PATCH 126/160] target-sparc: Remove usage of cpu_tmp64 from most helper functions Use a locally allocated temporary instead. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 73 ++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index ed341b896f..9b7bbef1ae 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2071,16 +2071,18 @@ static inline void gen_stf_asi(TCGv addr, int insn, int size, int rd) static inline void gen_swap_asi(TCGv dst, TCGv src, TCGv addr, int insn) { TCGv_i32 r_asi, r_size, r_sign; + TCGv_i64 t64 = tcg_temp_new_i64(); r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(4); r_sign = tcg_const_i32(0); - gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); + gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free_i32(r_sign); gen_helper_st_asi(cpu_env, addr, src, r_asi, r_size); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); - tcg_gen_trunc_i64_tl(dst, cpu_tmp64); + tcg_gen_trunc_i64_tl(dst, t64); + tcg_temp_free_i64(t64); } static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, @@ -2100,13 +2102,15 @@ static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, { TCGv_i32 r_asi, r_size; TCGv lo = gen_load_gpr(dc, rd + 1); + TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_concat_tl_i64(cpu_tmp64, lo, hi); + tcg_gen_concat_tl_i64(t64, lo, hi); r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(8); - gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); + tcg_temp_free_i64(t64); } static inline void gen_cas_asi(DisasContext *dc, TCGv addr, @@ -2139,46 +2143,52 @@ static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size, int sign) { TCGv_i32 r_asi, r_size, r_sign; + TCGv_i64 t64 = tcg_temp_new_i64(); r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(size); r_sign = tcg_const_i32(sign); - gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); - tcg_temp_free(r_sign); - tcg_temp_free(r_size); - tcg_temp_free(r_asi); - tcg_gen_trunc_i64_tl(dst, cpu_tmp64); + gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign); + tcg_temp_free_i32(r_sign); + tcg_temp_free_i32(r_size); + tcg_temp_free_i32(r_asi); + tcg_gen_trunc_i64_tl(dst, t64); + tcg_temp_free_i64(t64); } static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size) { TCGv_i32 r_asi, r_size; + TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_extu_tl_i64(cpu_tmp64, src); + tcg_gen_extu_tl_i64(t64, src); r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(size); - gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size); - tcg_temp_free(r_size); - tcg_temp_free(r_asi); + gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size); + tcg_temp_free_i32(r_size); + tcg_temp_free_i32(r_asi); + tcg_temp_free_i64(t64); } static inline void gen_swap_asi(TCGv dst, TCGv src, TCGv addr, int insn) { TCGv_i32 r_asi, r_size, r_sign; - TCGv_i64 r_val; + TCGv_i64 r_val, t64; r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(4); r_sign = tcg_const_i32(0); - gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); + t64 = tcg_temp_new_i64(); + gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free(r_sign); r_val = tcg_temp_new_i64(); tcg_gen_extu_tl_i64(r_val, src); gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size); tcg_temp_free_i64(r_val); - tcg_temp_free(r_size); - tcg_temp_free(r_asi); - tcg_gen_trunc_i64_tl(dst, cpu_tmp64); + tcg_temp_free_i32(r_size); + tcg_temp_free_i32(r_asi); + tcg_gen_trunc_i64_tl(dst, t64); + tcg_temp_free_i64(t64); } static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, @@ -2186,21 +2196,24 @@ static inline void gen_ldda_asi(DisasContext *dc, TCGv hi, TCGv addr, { TCGv_i32 r_asi, r_size, r_sign; TCGv t; + TCGv_i64 t64; r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(8); r_sign = tcg_const_i32(0); - gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); - tcg_temp_free(r_sign); - tcg_temp_free(r_size); - tcg_temp_free(r_asi); + t64 = tcg_temp_new_i64(); + gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_size, r_sign); + tcg_temp_free_i32(r_sign); + tcg_temp_free_i32(r_size); + tcg_temp_free_i32(r_asi); t = gen_dest_gpr(dc, rd + 1); - tcg_gen_trunc_i64_tl(t, cpu_tmp64); + tcg_gen_trunc_i64_tl(t, t64); gen_store_gpr(dc, rd + 1, t); - tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32); - tcg_gen_trunc_i64_tl(hi, cpu_tmp64); + tcg_gen_shri_i64(t64, t64, 32); + tcg_gen_trunc_i64_tl(hi, t64); + tcg_temp_free_i64(t64); gen_store_gpr(dc, rd, hi); } @@ -2209,13 +2222,15 @@ static inline void gen_stda_asi(DisasContext *dc, TCGv hi, TCGv addr, { TCGv_i32 r_asi, r_size; TCGv lo = gen_load_gpr(dc, rd + 1); + TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_concat_tl_i64(cpu_tmp64, lo, hi); + tcg_gen_concat_tl_i64(t64, lo, hi); r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(8); - gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size); - tcg_temp_free(r_size); - tcg_temp_free(r_asi); + gen_helper_st_asi(cpu_env, addr, t64, r_asi, r_size); + tcg_temp_free_i32(r_size); + tcg_temp_free_i32(r_asi); + tcg_temp_free_i64(t64); } #endif From 3886b8a32029a88111140dfe81f6ef02d6b85e23 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:26 +1000 Subject: [PATCH 127/160] target-sparc: Don't use a temporary for gen_dest_fpr_D In all cases we don't have write-before-read problems. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 9b7bbef1ae..00ceb9debe 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -206,9 +206,9 @@ static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v) gen_update_fprs_dirty(dst); } -static TCGv_i64 gen_dest_fpr_D(void) +static TCGv_i64 gen_dest_fpr_D(DisasContext *dc, unsigned int dst) { - return cpu_tmp64; + return cpu_fpr[DFPREG(dst) / 2]; } static void gen_op_load_fpr_QT0(unsigned int src) @@ -1758,7 +1758,7 @@ static inline void gen_fop_DD(DisasContext *dc, int rd, int rs, TCGv_i64 dst, src; src = gen_load_fpr_D(dc, rs); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, cpu_env, src); @@ -1772,7 +1772,7 @@ static inline void gen_ne_fop_DD(DisasContext *dc, int rd, int rs, TCGv_i64 dst, src; src = gen_load_fpr_D(dc, rs); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, src); @@ -1787,7 +1787,7 @@ static inline void gen_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2, src1 = gen_load_fpr_D(dc, rs1); src2 = gen_load_fpr_D(dc, rs2); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, cpu_env, src1, src2); @@ -1802,7 +1802,7 @@ static inline void gen_ne_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2, src1 = gen_load_fpr_D(dc, rs1); src2 = gen_load_fpr_D(dc, rs2); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, src1, src2); @@ -1816,7 +1816,7 @@ static inline void gen_gsr_fop_DDD(DisasContext *dc, int rd, int rs1, int rs2, src1 = gen_load_fpr_D(dc, rs1); src2 = gen_load_fpr_D(dc, rs2); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, cpu_gsr, src1, src2); @@ -1831,7 +1831,7 @@ static inline void gen_ne_fop_DDDD(DisasContext *dc, int rd, int rs1, int rs2, src1 = gen_load_fpr_D(dc, rs1); src2 = gen_load_fpr_D(dc, rs2); src0 = gen_load_fpr_D(dc, rd); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, src0, src1, src2); @@ -1883,7 +1883,7 @@ static inline void gen_fop_DFF(DisasContext *dc, int rd, int rs1, int rs2, src1 = gen_load_fpr_F(dc, rs1); src2 = gen_load_fpr_F(dc, rs2); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, cpu_env, src1, src2); @@ -1912,7 +1912,7 @@ static inline void gen_fop_DF(DisasContext *dc, int rd, int rs, TCGv_i32 src; src = gen_load_fpr_F(dc, rs); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, cpu_env, src); @@ -1927,7 +1927,7 @@ static inline void gen_ne_fop_DF(DisasContext *dc, int rd, int rs, TCGv_i32 src; src = gen_load_fpr_F(dc, rs); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, cpu_env, src); @@ -1967,7 +1967,7 @@ static inline void gen_fop_DQ(DisasContext *dc, int rd, int rs, TCGv_i64 dst; gen_op_load_fpr_QT1(QFPREG(rs)); - dst = gen_dest_fpr_D(); + dst = gen_dest_fpr_D(dc, rd); gen(dst, cpu_env); @@ -2303,7 +2303,7 @@ static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs) static void gen_fmovd(DisasContext *dc, DisasCompare *cmp, int rd, int rs) { - TCGv_i64 dst = gen_dest_fpr_D(); + TCGv_i64 dst = gen_dest_fpr_D(dc, rd); tcg_gen_movcond_i64(cmp->cond, dst, cmp->c1, cmp->c2, gen_load_fpr_D(dc, rs), gen_load_fpr_D(dc, rd)); @@ -4317,7 +4317,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x060: /* VIS I fzero */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_dst_64 = gen_dest_fpr_D(); + cpu_dst_64 = gen_dest_fpr_D(dc, rd); tcg_gen_movi_i64(cpu_dst_64, 0); gen_store_fpr_D(dc, rd, cpu_dst_64); break; @@ -4445,7 +4445,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x07e: /* VIS I fone */ CHECK_FPU_FEATURE(dc, VIS1); - cpu_dst_64 = gen_dest_fpr_D(); + cpu_dst_64 = gen_dest_fpr_D(dc, rd); tcg_gen_movi_i64(cpu_dst_64, -1); gen_store_fpr_D(dc, rd, cpu_dst_64); break; @@ -4873,7 +4873,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; case 0x23: /* lddf, load double fpreg */ gen_address_mask(dc, cpu_addr); - cpu_dst_64 = gen_dest_fpr_D(); + cpu_dst_64 = gen_dest_fpr_D(dc, rd); tcg_gen_qemu_ld64(cpu_dst_64, cpu_addr, dc->mem_idx); gen_store_fpr_D(dc, rd, cpu_dst_64); break; From aeff993cc59ea043c8d33e3dc3584c61aa31f347 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:27 +1000 Subject: [PATCH 128/160] target-sparc: Remove cpu_tmp64 use from softint insns The use of "tl" functions and a tmp64 is logically incompatible. Use cpu_tmp0 instead. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 00ceb9debe..64feaa326d 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3655,20 +3655,20 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x14: /* Softint set */ if (!supervisor(dc)) goto illegal_insn; - tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); - gen_helper_set_softint(cpu_env, cpu_tmp64); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); + gen_helper_set_softint(cpu_env, cpu_tmp0); break; case 0x15: /* Softint clear */ if (!supervisor(dc)) goto illegal_insn; - tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); - gen_helper_clear_softint(cpu_env, cpu_tmp64); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); + gen_helper_clear_softint(cpu_env, cpu_tmp0); break; case 0x16: /* Softint write */ if (!supervisor(dc)) goto illegal_insn; - tcg_gen_xor_tl(cpu_tmp64, cpu_src1, cpu_src2); - gen_helper_write_softint(cpu_env, cpu_tmp64); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); + gen_helper_write_softint(cpu_env, cpu_tmp0); break; case 0x17: /* Tick compare */ #if !defined(CONFIG_USER_ONLY) From abcc71919c65747af7615c8770754c0ea071a2d2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:28 +1000 Subject: [PATCH 129/160] target-sparc: Remove last uses of cpu_tmp64 Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 64feaa326d..16cf8de9ce 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -60,7 +60,6 @@ static TCGv cpu_wim; #endif /* local register indexes (only used inside old micro ops) */ static TCGv cpu_tmp0; -static TCGv_i64 cpu_tmp64; /* Floating point registers */ static TCGv_i64 cpu_fpr[TARGET_DPREGS]; @@ -4637,6 +4636,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; else { TCGv_i32 r_const; + TCGv_i64 t64; save_state(dc); r_const = tcg_const_i32(7); @@ -4644,12 +4644,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_check_align(cpu_env, cpu_addr, r_const); tcg_temp_free_i32(r_const); gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx); - tcg_gen_trunc_i64_tl(cpu_tmp0, cpu_tmp64); + t64 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx); + tcg_gen_trunc_i64_tl(cpu_tmp0, t64); tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffffULL); gen_store_gpr(dc, rd + 1, cpu_tmp0); - tcg_gen_shri_i64(cpu_tmp64, cpu_tmp64, 32); - tcg_gen_trunc_i64_tl(cpu_val, cpu_tmp64); + tcg_gen_shri_i64(t64, t64, 32); + tcg_gen_trunc_i64_tl(cpu_val, t64); + tcg_temp_free_i64(t64); tcg_gen_andi_tl(cpu_val, cpu_val, 0xffffffffULL); } break; @@ -4846,8 +4848,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #ifdef TARGET_SPARC64 gen_address_mask(dc, cpu_addr); if (rd == 1) { - tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx); - gen_helper_ldxfsr(cpu_env, cpu_tmp64); + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx); + gen_helper_ldxfsr(cpu_env, t64); + tcg_temp_free_i64(t64); break; } #endif @@ -4902,6 +4906,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; else { TCGv_i32 r_const; + TCGv_i64 t64; TCGv lo; save_state(dc); @@ -4911,8 +4916,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_helper_check_align(cpu_env, cpu_addr, r_const); tcg_temp_free_i32(r_const); lo = gen_load_gpr(dc, rd + 1); - tcg_gen_concat_tl_i64(cpu_tmp64, lo, cpu_val); - tcg_gen_qemu_st64(cpu_tmp64, cpu_addr, dc->mem_idx); + + t64 = tcg_temp_new_i64(); + tcg_gen_concat_tl_i64(t64, lo, cpu_val); + tcg_gen_qemu_st64(t64, cpu_addr, dc->mem_idx); + tcg_temp_free_i64(t64); } break; #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) @@ -5250,14 +5258,12 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, insn = cpu_ldl_code(env, dc->pc); cpu_tmp0 = tcg_temp_new(); - cpu_tmp64 = tcg_temp_new_i64(); cpu_dst = tcg_temp_new(); disas_sparc_insn(dc, insn); num_insns++; tcg_temp_free(cpu_dst); - tcg_temp_free_i64(cpu_tmp64); tcg_temp_free(cpu_tmp0); if (dc->is_br) From 7b04bd5ccabf61d5ad8a616ecbe2282c4e2656c4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:29 +1000 Subject: [PATCH 130/160] target-sparc: Only use cpu_dst for eventual writes to a gpr Use cpu_tmp0 for other stuff, like Write Priv Register. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 52 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 16cf8de9ce..5b7e82b1f7 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3620,19 +3620,19 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; #else case 0x2: /* V9 wrccr */ - tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); - gen_helper_wrccr(cpu_env, cpu_dst); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); + gen_helper_wrccr(cpu_env, cpu_tmp0); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); dc->cc_op = CC_OP_FLAGS; break; case 0x3: /* V9 wrasi */ - tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_andi_tl(cpu_dst, cpu_dst, 0xff); - tcg_gen_trunc_tl_i32(cpu_asi, cpu_dst); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); + tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xff); + tcg_gen_trunc_tl_i32(cpu_asi, cpu_tmp0); break; case 0x6: /* V9 wrfprs */ - tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); - tcg_gen_trunc_tl_i32(cpu_fprs, cpu_dst); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); + tcg_gen_trunc_tl_i32(cpu_fprs, cpu_tmp0); save_state(dc); gen_op_next_insn(); tcg_gen_exit_tb(0); @@ -3695,13 +3695,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { TCGv_ptr r_tickptr; - tcg_gen_xor_tl(cpu_dst, cpu_src1, + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); r_tickptr = tcg_temp_new_ptr(); tcg_gen_ld_ptr(r_tickptr, cpu_env, offsetof(CPUSPARCState, stick)); gen_helper_tick_set_count(r_tickptr, - cpu_dst); + cpu_tmp0); tcg_temp_free_ptr(r_tickptr); } break; @@ -3756,8 +3756,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } #else - tcg_gen_xor_tl(cpu_dst, cpu_src1, cpu_src2); - gen_helper_wrpsr(cpu_env, cpu_dst); + tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); + gen_helper_wrpsr(cpu_env, cpu_tmp0); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); dc->cc_op = CC_OP_FLAGS; save_state(dc); @@ -4478,22 +4478,22 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) cpu_src1 = get_src1(dc, insn); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); - tcg_gen_addi_tl(cpu_dst, cpu_src1, simm); + tcg_gen_addi_tl(cpu_tmp0, cpu_src1, simm); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); if (rs2) { cpu_src2 = gen_load_gpr(dc, rs2); - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); + tcg_gen_add_tl(cpu_tmp0, cpu_src1, cpu_src2); } else { - tcg_gen_mov_tl(cpu_dst, cpu_src1); + tcg_gen_mov_tl(cpu_tmp0, cpu_src1); } } gen_helper_restore(cpu_env); gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_env, cpu_dst, r_const); + gen_helper_check_align(cpu_env, cpu_tmp0, r_const); tcg_temp_free_i32(r_const); - tcg_gen_mov_tl(cpu_npc, cpu_dst); + tcg_gen_mov_tl(cpu_npc, cpu_tmp0); dc->npc = DYNAMIC_PC; goto jmp_insn; #endif @@ -4501,14 +4501,14 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) cpu_src1 = get_src1(dc, insn); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); - tcg_gen_addi_tl(cpu_dst, cpu_src1, simm); + tcg_gen_addi_tl(cpu_tmp0, cpu_src1, simm); } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); if (rs2) { cpu_src2 = gen_load_gpr(dc, rs2); - tcg_gen_add_tl(cpu_dst, cpu_src1, cpu_src2); + tcg_gen_add_tl(cpu_tmp0, cpu_src1, cpu_src2); } else { - tcg_gen_mov_tl(cpu_dst, cpu_src1); + tcg_gen_mov_tl(cpu_tmp0, cpu_src1); } } switch (xop) { @@ -4522,10 +4522,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_store_gpr(dc, rd, t); gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_env, cpu_dst, r_const); + gen_helper_check_align(cpu_env, cpu_tmp0, r_const); tcg_temp_free_i32(r_const); - gen_address_mask(dc, cpu_dst); - tcg_gen_mov_tl(cpu_npc, cpu_dst); + gen_address_mask(dc, cpu_tmp0); + tcg_gen_mov_tl(cpu_npc, cpu_tmp0); dc->npc = DYNAMIC_PC; } goto jmp_insn; @@ -4538,9 +4538,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto priv_insn; gen_mov_pc_npc(dc); r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_env, cpu_dst, r_const); + gen_helper_check_align(cpu_env, cpu_tmp0, r_const); tcg_temp_free_i32(r_const); - tcg_gen_mov_tl(cpu_npc, cpu_dst); + tcg_gen_mov_tl(cpu_npc, cpu_tmp0); dc->npc = DYNAMIC_PC; gen_helper_rett(cpu_env); } @@ -4554,12 +4554,12 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 0x3c: /* save */ save_state(dc); gen_helper_save(cpu_env); - gen_store_gpr(dc, rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_tmp0); break; case 0x3d: /* restore */ save_state(dc); gen_helper_restore(cpu_env); - gen_store_gpr(dc, rd, cpu_dst); + gen_store_gpr(dc, rd, cpu_tmp0); break; #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) case 0x3e: /* V9 done/retry */ From 5793f2a47e201d251856c7956d6f7907ec0d9f1f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:30 +1000 Subject: [PATCH 131/160] target-sparc: Make cpu_dst local to OP=2 insns And initialize it such that it (may) write directly to rd. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 5b7e82b1f7..8559cc3507 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -48,7 +48,7 @@ static TCGv cpu_y; #ifndef CONFIG_USER_ONLY static TCGv cpu_tbr; #endif -static TCGv cpu_cond, cpu_dst; +static TCGv cpu_cond; #ifdef TARGET_SPARC64 static TCGv_i32 cpu_xcc, cpu_asi, cpu_fprs; static TCGv cpu_gsr; @@ -2511,7 +2511,6 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } opc = GET_FIELD(insn, 0, 1); - rd = GET_FIELD(insn, 2, 6); switch (opc) { @@ -2620,6 +2619,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) case 2: /* FPU & Logical Operations */ { unsigned int xop = GET_FIELD(insn, 7, 12); + TCGv cpu_dst = gen_dest_gpr(dc, rd); + if (xop == 0x3a) { /* generate trap */ int cond = GET_FIELD(insn, 3, 6); TCGv_i32 trap; @@ -5258,12 +5259,10 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, insn = cpu_ldl_code(env, dc->pc); cpu_tmp0 = tcg_temp_new(); - cpu_dst = tcg_temp_new(); disas_sparc_insn(dc, insn); num_insns++; - tcg_temp_free(cpu_dst); tcg_temp_free(cpu_tmp0); if (dc->is_br) From de9e9d9f17a36ff76c1a02a5348835e5e0a081b0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 16 Oct 2012 19:32:31 +1000 Subject: [PATCH 132/160] target-sparc: Remove cpu_tmp0 as a global Subroutines do their own local temporary management. Within disas_sparc_insn we limit the existance of the variable to OP=2 insns, and delay initialization as late as is reasonable for the specific XOP. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 203 +++++++++++++++++++++++---------------- 1 file changed, 118 insertions(+), 85 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 8559cc3507..5df287629e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -58,8 +58,6 @@ static TCGv_i32 cpu_softint; #else static TCGv cpu_wim; #endif -/* local register indexes (only used inside old micro ops) */ -static TCGv cpu_tmp0; /* Floating point registers */ static TCGv_i64 cpu_fpr[TARGET_DPREGS]; @@ -608,9 +606,10 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) { - TCGv r_temp, zero; + TCGv r_temp, zero, t0; r_temp = tcg_temp_new(); + t0 = tcg_temp_new(); /* old op: if (!(env->y & 1)) @@ -628,22 +627,23 @@ static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) // env->y = (b2 << 31) | (env->y >> 1); tcg_gen_andi_tl(r_temp, cpu_cc_src, 0x1); tcg_gen_shli_tl(r_temp, r_temp, 31); - tcg_gen_shri_tl(cpu_tmp0, cpu_y, 1); - tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0x7fffffff); - tcg_gen_or_tl(cpu_tmp0, cpu_tmp0, r_temp); - tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff); + tcg_gen_shri_tl(t0, cpu_y, 1); + tcg_gen_andi_tl(t0, t0, 0x7fffffff); + tcg_gen_or_tl(t0, t0, r_temp); + tcg_gen_andi_tl(cpu_y, t0, 0xffffffff); // b1 = N ^ V; - gen_mov_reg_N(cpu_tmp0, cpu_psr); + gen_mov_reg_N(t0, cpu_psr); gen_mov_reg_V(r_temp, cpu_psr); - tcg_gen_xor_tl(cpu_tmp0, cpu_tmp0, r_temp); + tcg_gen_xor_tl(t0, t0, r_temp); tcg_temp_free(r_temp); // T0 = (b1 << 31) | (T0 >> 1); // src1 = T0; - tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, 31); + tcg_gen_shli_tl(t0, t0, 31); tcg_gen_shri_tl(cpu_cc_src, cpu_cc_src, 1); - tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0); + tcg_temp_free(t0); tcg_gen_add_tl(cpu_cc_dst, cpu_cc_src, cpu_cc_src2); @@ -675,9 +675,9 @@ static inline void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext) tcg_gen_mul_i64(r_temp2, r_temp, r_temp2); tcg_gen_shri_i64(r_temp, r_temp2, 32); - tcg_gen_trunc_i64_tl(cpu_tmp0, r_temp); + tcg_gen_trunc_i64_tl(cpu_y, r_temp); tcg_temp_free_i64(r_temp); - tcg_gen_andi_tl(cpu_y, cpu_tmp0, 0xffffffff); + tcg_gen_andi_tl(cpu_y, cpu_y, 0xffffffff); tcg_gen_trunc_i64_tl(dst, r_temp2); @@ -714,27 +714,33 @@ static inline void gen_op_eval_be(TCGv dst, TCGv_i32 src) // Z | (N ^ V) static inline void gen_op_eval_ble(TCGv dst, TCGv_i32 src) { - gen_mov_reg_N(cpu_tmp0, src); + TCGv t0 = tcg_temp_new(); + gen_mov_reg_N(t0, src); gen_mov_reg_V(dst, src); - tcg_gen_xor_tl(dst, dst, cpu_tmp0); - gen_mov_reg_Z(cpu_tmp0, src); - tcg_gen_or_tl(dst, dst, cpu_tmp0); + tcg_gen_xor_tl(dst, dst, t0); + gen_mov_reg_Z(t0, src); + tcg_gen_or_tl(dst, dst, t0); + tcg_temp_free(t0); } // N ^ V static inline void gen_op_eval_bl(TCGv dst, TCGv_i32 src) { - gen_mov_reg_V(cpu_tmp0, src); + TCGv t0 = tcg_temp_new(); + gen_mov_reg_V(t0, src); gen_mov_reg_N(dst, src); - tcg_gen_xor_tl(dst, dst, cpu_tmp0); + tcg_gen_xor_tl(dst, dst, t0); + tcg_temp_free(t0); } // C | Z static inline void gen_op_eval_bleu(TCGv dst, TCGv_i32 src) { - gen_mov_reg_Z(cpu_tmp0, src); + TCGv t0 = tcg_temp_new(); + gen_mov_reg_Z(t0, src); gen_mov_reg_C(dst, src); - tcg_gen_or_tl(dst, dst, cpu_tmp0); + tcg_gen_or_tl(dst, dst, t0); + tcg_temp_free(t0); } // C @@ -771,29 +777,21 @@ static inline void gen_op_eval_bne(TCGv dst, TCGv_i32 src) // !(Z | (N ^ V)) static inline void gen_op_eval_bg(TCGv dst, TCGv_i32 src) { - gen_mov_reg_N(cpu_tmp0, src); - gen_mov_reg_V(dst, src); - tcg_gen_xor_tl(dst, dst, cpu_tmp0); - gen_mov_reg_Z(cpu_tmp0, src); - tcg_gen_or_tl(dst, dst, cpu_tmp0); + gen_op_eval_ble(dst, src); tcg_gen_xori_tl(dst, dst, 0x1); } // !(N ^ V) static inline void gen_op_eval_bge(TCGv dst, TCGv_i32 src) { - gen_mov_reg_V(cpu_tmp0, src); - gen_mov_reg_N(dst, src); - tcg_gen_xor_tl(dst, dst, cpu_tmp0); + gen_op_eval_bl(dst, src); tcg_gen_xori_tl(dst, dst, 0x1); } // !(C | Z) static inline void gen_op_eval_bgu(TCGv dst, TCGv_i32 src) { - gen_mov_reg_Z(cpu_tmp0, src); - gen_mov_reg_C(dst, src); - tcg_gen_or_tl(dst, dst, cpu_tmp0); + gen_op_eval_bleu(dst, src); tcg_gen_xori_tl(dst, dst, 0x1); } @@ -843,18 +841,22 @@ static inline void gen_mov_reg_FCC1(TCGv reg, TCGv src, static inline void gen_op_eval_fbne(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_or_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_or_tl(dst, dst, t0); + tcg_temp_free(t0); } // 1 or 2: FCC0 ^ FCC1 static inline void gen_op_eval_fblg(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_xor_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_xor_tl(dst, dst, t0); + tcg_temp_free(t0); } // 1 or 3: FCC0 @@ -868,10 +870,11 @@ static inline void gen_op_eval_fbul(TCGv dst, TCGv src, static inline void gen_op_eval_fbl(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_xori_tl(cpu_tmp0, cpu_tmp0, 0x1); - tcg_gen_and_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_andc_tl(dst, dst, t0); + tcg_temp_free(t0); } // 2 or 3: FCC1 @@ -885,39 +888,46 @@ static inline void gen_op_eval_fbug(TCGv dst, TCGv src, static inline void gen_op_eval_fbg(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - tcg_gen_xori_tl(dst, dst, 0x1); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_and_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_andc_tl(dst, t0, dst); + tcg_temp_free(t0); } // 3: FCC0 & FCC1 static inline void gen_op_eval_fbu(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_and_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_and_tl(dst, dst, t0); + tcg_temp_free(t0); } // 0: !(FCC0 | FCC1) static inline void gen_op_eval_fbe(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_or_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_or_tl(dst, dst, t0); tcg_gen_xori_tl(dst, dst, 0x1); + tcg_temp_free(t0); } // 0 or 3: !(FCC0 ^ FCC1) static inline void gen_op_eval_fbue(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_xor_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_xor_tl(dst, dst, t0); tcg_gen_xori_tl(dst, dst, 0x1); + tcg_temp_free(t0); } // 0 or 2: !FCC0 @@ -932,11 +942,12 @@ static inline void gen_op_eval_fbge(TCGv dst, TCGv src, static inline void gen_op_eval_fbuge(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_xori_tl(cpu_tmp0, cpu_tmp0, 0x1); - tcg_gen_and_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_andc_tl(dst, dst, t0); tcg_gen_xori_tl(dst, dst, 0x1); + tcg_temp_free(t0); } // 0 or 1: !FCC1 @@ -951,21 +962,24 @@ static inline void gen_op_eval_fble(TCGv dst, TCGv src, static inline void gen_op_eval_fbule(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_andc_tl(dst, t0, dst); tcg_gen_xori_tl(dst, dst, 0x1); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_and_tl(dst, dst, cpu_tmp0); - tcg_gen_xori_tl(dst, dst, 0x1); + tcg_temp_free(t0); } // !3: !(FCC0 & FCC1) static inline void gen_op_eval_fbo(TCGv dst, TCGv src, unsigned int fcc_offset) { + TCGv t0 = tcg_temp_new(); gen_mov_reg_FCC0(dst, src, fcc_offset); - gen_mov_reg_FCC1(cpu_tmp0, src, fcc_offset); - tcg_gen_and_tl(dst, dst, cpu_tmp0); + gen_mov_reg_FCC1(t0, src, fcc_offset); + tcg_gen_and_tl(dst, dst, t0); tcg_gen_xori_tl(dst, dst, 0x1); + tcg_temp_free(t0); } static inline void gen_branch2(DisasContext *dc, target_ulong pc1, @@ -2620,6 +2634,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { unsigned int xop = GET_FIELD(insn, 7, 12); TCGv cpu_dst = gen_dest_gpr(dc, rd); + TCGv cpu_tmp0; if (xop == 0x3a) { /* generate trap */ int cond = GET_FIELD(insn, 3, 6); @@ -2839,8 +2854,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_store_gpr(dc, rd, cpu_dst); break; } else if (xop == 0x2a) { /* rdwim / V9 rdpr */ - if (!supervisor(dc)) + if (!supervisor(dc)) { goto priv_insn; + } + cpu_tmp0 = get_temp_tl(dc); #ifdef TARGET_SPARC64 rs1 = GET_FIELD(insn, 13, 17); switch (rs1) { @@ -3347,6 +3364,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); cpu_src2 = gen_load_gpr(dc, rs2); + cpu_tmp0 = get_temp_tl(dc); if (insn & (1 << 12)) { tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); } else { @@ -3368,6 +3386,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); cpu_src2 = gen_load_gpr(dc, rs2); + cpu_tmp0 = get_temp_tl(dc); if (insn & (1 << 12)) { tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); tcg_gen_shr_i64(cpu_dst, cpu_src1, cpu_tmp0); @@ -3391,6 +3410,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) } else { /* register */ rs2 = GET_FIELD(insn, 27, 31); cpu_src2 = gen_load_gpr(dc, rs2); + cpu_tmp0 = get_temp_tl(dc); if (insn & (1 << 12)) { tcg_gen_andi_i64(cpu_tmp0, cpu_src2, 0x3f); tcg_gen_sar_i64(cpu_dst, cpu_src1, cpu_tmp0); @@ -3576,6 +3596,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) simm = GET_FIELDs(insn, 20, 31); tcg_gen_shli_tl(cpu_dst, cpu_src1, simm & 0x1f); } else { /* register */ + cpu_tmp0 = get_temp_tl(dc); tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); tcg_gen_shl_tl(cpu_dst, cpu_src1, cpu_tmp0); } @@ -3586,6 +3607,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) simm = GET_FIELDs(insn, 20, 31); tcg_gen_shri_tl(cpu_dst, cpu_src1, simm & 0x1f); } else { /* register */ + cpu_tmp0 = get_temp_tl(dc); tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); tcg_gen_shr_tl(cpu_dst, cpu_src1, cpu_tmp0); } @@ -3596,6 +3618,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) simm = GET_FIELDs(insn, 20, 31); tcg_gen_sari_tl(cpu_dst, cpu_src1, simm & 0x1f); } else { /* register */ + cpu_tmp0 = get_temp_tl(dc); tcg_gen_andi_tl(cpu_tmp0, cpu_src2, 0x1f); tcg_gen_sar_tl(cpu_dst, cpu_src1, cpu_tmp0); } @@ -3604,6 +3627,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif case 0x30: { + cpu_tmp0 = get_temp_tl(dc); switch(rd) { case 0: /* wry */ tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); @@ -3757,6 +3781,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) goto illegal_insn; } #else + cpu_tmp0 = get_temp_tl(dc); tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); gen_helper_wrpsr(cpu_env, cpu_tmp0); tcg_gen_movi_i32(cpu_cc_op, CC_OP_FLAGS); @@ -3772,6 +3797,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { if (!supervisor(dc)) goto priv_insn; + cpu_tmp0 = get_temp_tl(dc); tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); #ifdef TARGET_SPARC64 switch (rd) { @@ -3910,6 +3936,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) CHECK_IU_FEATURE(dc, HYPV); if (!hypervisor(dc)) goto priv_insn; + cpu_tmp0 = get_temp_tl(dc); tcg_gen_xor_tl(cpu_tmp0, cpu_src1, cpu_src2); switch (rd) { case 0: // hpstate @@ -4477,6 +4504,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) save_state(dc); cpu_src1 = get_src1(dc, insn); + cpu_tmp0 = get_temp_tl(dc); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); tcg_gen_addi_tl(cpu_tmp0, cpu_src1, simm); @@ -4500,6 +4528,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #endif } else { cpu_src1 = get_src1(dc, insn); + cpu_tmp0 = get_temp_tl(dc); if (IS_IMM) { /* immediate */ simm = GET_FIELDs(insn, 19, 31); tcg_gen_addi_tl(cpu_tmp0, cpu_src1, simm); @@ -4647,13 +4676,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) gen_address_mask(dc, cpu_addr); t64 = tcg_temp_new_i64(); tcg_gen_qemu_ld64(t64, cpu_addr, dc->mem_idx); - tcg_gen_trunc_i64_tl(cpu_tmp0, t64); - tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffffULL); - gen_store_gpr(dc, rd + 1, cpu_tmp0); + tcg_gen_trunc_i64_tl(cpu_val, t64); + tcg_gen_ext32u_tl(cpu_val, cpu_val); + gen_store_gpr(dc, rd + 1, cpu_val); tcg_gen_shri_i64(t64, t64, 32); tcg_gen_trunc_i64_tl(cpu_val, t64); tcg_temp_free_i64(t64); - tcg_gen_andi_tl(cpu_val, cpu_val, 0xffffffffULL); + tcg_gen_ext32u_tl(cpu_val, cpu_val); } break; case 0x9: /* ldsb, load signed byte */ @@ -4675,14 +4704,17 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) tcg_temp_free(r_const); } break; - case 0x0f: /* swap, swap register with memory. Also - atomically */ - CHECK_IU_FEATURE(dc, SWAP); - cpu_src1 = gen_load_gpr(dc, rd); - gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); - tcg_gen_qemu_st32(cpu_src1, cpu_addr, dc->mem_idx); - tcg_gen_mov_tl(cpu_val, cpu_tmp0); + case 0x0f: + /* swap, swap register with memory. Also atomically */ + { + TCGv t0 = get_temp_tl(dc); + CHECK_IU_FEATURE(dc, SWAP); + cpu_src1 = gen_load_gpr(dc, rd); + gen_address_mask(dc, cpu_addr); + tcg_gen_qemu_ld32u(t0, cpu_addr, dc->mem_idx); + tcg_gen_qemu_st32(cpu_src1, cpu_addr, dc->mem_idx); + tcg_gen_mov_tl(cpu_val, t0); + } break; #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) case 0x10: /* lda, V9 lduwa, load word alternate */ @@ -4833,6 +4865,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) skip_move: ; #endif } else if (xop >= 0x20 && xop < 0x24) { + TCGv t0; + if (gen_trap_ifnofpu(dc)) { goto jmp_insn; } @@ -4840,9 +4874,10 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) switch (xop) { case 0x20: /* ldf, load fpreg */ gen_address_mask(dc, cpu_addr); - tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); + t0 = get_temp_tl(dc); + tcg_gen_qemu_ld32u(t0, cpu_addr, dc->mem_idx); cpu_dst_32 = gen_dest_fpr_F(dc); - tcg_gen_trunc_tl_i32(cpu_dst_32, cpu_tmp0); + tcg_gen_trunc_tl_i32(cpu_dst_32, t0); gen_store_fpr_F(dc, rd, cpu_dst_32); break; case 0x21: /* ldfsr, V9 ldxfsr */ @@ -4856,12 +4891,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) break; } #endif - { - TCGv_i32 t32 = get_temp_i32(dc); - tcg_gen_qemu_ld32u(cpu_tmp0, cpu_addr, dc->mem_idx); - tcg_gen_trunc_tl_i32(t32, cpu_tmp0); - gen_helper_ldfsr(cpu_env, t32); - } + cpu_dst_32 = get_temp_i32(dc); + t0 = get_temp_tl(dc); + tcg_gen_qemu_ld32u(t0, cpu_addr, dc->mem_idx); + tcg_gen_trunc_tl_i32(cpu_dst_32, t0); + gen_helper_ldfsr(cpu_env, cpu_dst_32); break; case 0x22: /* ldqf, load quad fpreg */ { @@ -4994,10 +5028,13 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) save_state(dc); switch (xop) { case 0x24: /* stf, store fpreg */ - gen_address_mask(dc, cpu_addr); - cpu_src1_32 = gen_load_fpr_F(dc, rd); - tcg_gen_ext_i32_tl(cpu_tmp0, cpu_src1_32); - tcg_gen_qemu_st32(cpu_tmp0, cpu_addr, dc->mem_idx); + { + TCGv t = get_temp_tl(dc); + gen_address_mask(dc, cpu_addr); + cpu_src1_32 = gen_load_fpr_F(dc, rd); + tcg_gen_ext_i32_tl(t, cpu_src1_32); + tcg_gen_qemu_st32(t, cpu_addr, dc->mem_idx); + } break; case 0x25: /* stfsr, V9 stxfsr */ { @@ -5258,13 +5295,9 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, last_pc = dc->pc; insn = cpu_ldl_code(env, dc->pc); - cpu_tmp0 = tcg_temp_new(); - disas_sparc_insn(dc, insn); num_insns++; - tcg_temp_free(cpu_tmp0); - if (dc->is_br) break; /* if the next PC is different, we abort now */ From e54eba1986f6c4bac2951e7f90a849cd842e25e4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 14:11:35 +0100 Subject: [PATCH 133/160] qemu-log: Add new log category for guest bugs Add a new category for device models to log guest behaviour which is likely to be a guest bug of some kind (accessing nonexistent registers, reading 32 bit wide registers with a byte access, etc). Making this its own log category allows those who care (mostly guest OS authors) to see the complaints without bothering most users. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- qemu-log.c | 3 +++ qemu-log.h | 1 + 2 files changed, 4 insertions(+) diff --git a/qemu-log.c b/qemu-log.c index 396aafdf62..a4c3d1f2e3 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -116,6 +116,9 @@ const CPULogItem cpu_log_items[] = { "show all i/o ports accesses" }, { LOG_UNIMP, "unimp", "log unimplemented functionality" }, + { LOG_GUEST_ERROR, "guest_errors", + "log when the guest OS does something invalid (eg accessing a\n" + "non-existent register)" }, { 0, NULL, NULL }, }; diff --git a/qemu-log.h b/qemu-log.h index 5ccecf30af..ce6bb095b3 100644 --- a/qemu-log.h +++ b/qemu-log.h @@ -35,6 +35,7 @@ static inline bool qemu_log_enabled(void) #define CPU_LOG_TB_CPU (1 << 8) #define CPU_LOG_RESET (1 << 9) #define LOG_UNIMP (1 << 10) +#define LOG_GUEST_ERROR (1 << 11) /* Returns true if a bit is set in the current loglevel mask */ From 051c02b6c9c8ab5527f8775808625f9de8346006 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 14:11:36 +0100 Subject: [PATCH 134/160] hw/hw.h: Add include of qemu-log.h Add an include of qemu-log.h to hw.h, so that device model code has access to these logging functions without the need to directly include qemu-log.h. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/hw.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/hw.h b/hw/hw.h index 16101de3ce..b337ee3042 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -12,6 +12,7 @@ #include "irq.h" #include "qemu-file.h" #include "vmstate.h" +#include "qemu-log.h" #ifdef NEED_CPU_H #if TARGET_LONG_BITS == 64 From 9351d70829c6ef2b6e27b4ca89aaca2eab4780ed Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 14:11:37 +0100 Subject: [PATCH 135/160] hw/pl181: Use LOG_UNIMP and LOG_GUEST_ERROR Rather than a mix of direct printing to stderr and aborting via hw_error(), use LOG_UNIMP and LOG_GUEST_ERROR. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/pl181.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/pl181.c b/hw/pl181.c index 7d91fbba1d..5a734735f0 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -352,7 +352,7 @@ static uint64_t pl181_read(void *opaque, target_phys_addr_t offset, case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: case 0xb4: case 0xb8: case 0xbc: if (s->fifo_len == 0) { - fprintf(stderr, "pl181: Unexpected FIFO read\n"); + qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n"); return 0; } else { uint32_t value; @@ -363,7 +363,8 @@ static uint64_t pl181_read(void *opaque, target_phys_addr_t offset, return value; } default: - hw_error("pl181_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl181_read: Bad offset %x\n", (int)offset); return 0; } } @@ -387,11 +388,11 @@ static void pl181_write(void *opaque, target_phys_addr_t offset, s->cmd = value; if (s->cmd & PL181_CMD_ENABLE) { if (s->cmd & PL181_CMD_INTERRUPT) { - fprintf(stderr, "pl181: Interrupt mode not implemented\n"); - abort(); + qemu_log_mask(LOG_UNIMP, + "pl181: Interrupt mode not implemented\n"); } if (s->cmd & PL181_CMD_PENDING) { - fprintf(stderr, "pl181: Pending commands not implemented\n"); - abort(); + qemu_log_mask(LOG_UNIMP, + "pl181: Pending commands not implemented\n"); } else { pl181_send_command(s); pl181_fifo_run(s); @@ -427,14 +428,15 @@ static void pl181_write(void *opaque, target_phys_addr_t offset, case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: case 0xb4: case 0xb8: case 0xbc: if (s->datacnt == 0) { - fprintf(stderr, "pl181: Unexpected FIFO write\n"); + qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n"); } else { pl181_fifo_push(s, value); pl181_fifo_run(s); } break; default: - hw_error("pl181_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl181_write: Bad offset %x\n", (int)offset); } pl181_update(s); } From b1d9df90212984f8e78abc75152527a00d899f89 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 14:11:38 +0100 Subject: [PATCH 136/160] hw/pl041: Use LOG_UNIMP Use the new LOG_UNIMP tracing to report unimplemented features. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/pl041.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/pl041.c b/hw/pl041.c index b6723be0a9..9a6db1b6e2 100644 --- a/hw/pl041.c +++ b/hw/pl041.c @@ -536,8 +536,9 @@ static int pl041_init(SysBusDevice *dev) default: /* NC FIFO depth of 16 is not allowed because its id bits in AACIPERIPHID3 overlap with the id for the default NC FIFO depth */ - fprintf(stderr, "pl041: unsupported non-compact fifo depth [%i]\n", - s->fifo_depth); + qemu_log_mask(LOG_UNIMP, + "pl041: unsupported non-compact fifo depth [%i]\n", + s->fifo_depth); return -1; } From fd271e81aa7334b973285f5c94a4f8ab265df683 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 14:11:39 +0100 Subject: [PATCH 137/160] hw/pl190: Use LOG_GUEST_ERROR If the guest attempts an offset to a nonexistent register, just log this via LOG_GUEST_ERROR rather than killing QEMU with a hw_error. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/pl190.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/pl190.c b/hw/pl190.c index 7332f4dbae..961da5b3af 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -143,7 +143,8 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t offset, case 13: /* DEFVECTADDR */ return s->vect_addr[16]; default: - hw_error("pl190_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl190_read: Bad offset %x\n", (int)offset); return 0; } } @@ -202,7 +203,8 @@ static void pl190_write(void *opaque, target_phys_addr_t offset, } break; default: - hw_error("pl190_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl190_write: Bad offset %x\n", (int)offset); return; } pl190_update(s); From 6d5433e00a73f96dd5cbf93874dd8122672144b6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 14:11:40 +0100 Subject: [PATCH 138/160] hw/pl011: Use LOG_UNIMP and LOG_GUEST_ERROR Use the new LOG_UNIMP and LOG_GUEST_ERROR logging types rather than hw_error(). Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/pl011.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/pl011.c b/hw/pl011.c index 3245702df0..fb22736b6a 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -107,7 +107,8 @@ static uint64_t pl011_read(void *opaque, target_phys_addr_t offset, case 18: /* UARTDMACR */ return s->dmacr; default: - hw_error("pl011_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl011_read: Bad offset %x\n", (int)offset); return 0; } } @@ -178,11 +179,13 @@ static void pl011_write(void *opaque, target_phys_addr_t offset, break; case 18: /* UARTDMACR */ s->dmacr = value; - if (value & 3) - hw_error("PL011: DMA not implemented\n"); + if (value & 3) { + qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n"); + } break; default: - hw_error("pl011_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl011_write: Bad offset %x\n", (int)offset); } } From af83c32bd44b6594db301b4ac8cb44e5eb85d4bf Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 14:11:41 +0100 Subject: [PATCH 139/160] hw/pl022: Use LOG_UNIMP and LOG_GUEST_ERROR Use LOG_UNIMP and LOG_GUEST_ERROR where appropriate rather than hw_error(). Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/pl022.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/pl022.c b/hw/pl022.c index 60e35daeb5..e2ae315efb 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -168,7 +168,8 @@ static uint64_t pl022_read(void *opaque, target_phys_addr_t offset, /* Not implemented. */ return 0; default: - hw_error("pl022_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl022_read: Bad offset %x\n", (int)offset); return 0; } } @@ -211,11 +212,12 @@ static void pl022_write(void *opaque, target_phys_addr_t offset, break; case 0x20: /* DMACR */ if (value) { - hw_error("pl022: DMA not implemented\n"); + qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n"); } break; default: - hw_error("pl022_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl022_write: Bad offset %x\n", (int)offset); } } From a5089c050138933631b8755a664cfd275763b223 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 18 Oct 2012 14:11:42 +0100 Subject: [PATCH 140/160] hw/pl031: Use LOG_GUEST_ERROR Use LOG_GUEST_ERROR rather than hw_error or direct fprintf. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/pl031.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/pl031.c b/hw/pl031.c index 9602664da6..6cbaf2386f 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -120,11 +120,13 @@ static uint64_t pl031_read(void *opaque, target_phys_addr_t offset, case RTC_MIS: return s->is & s->im; case RTC_ICR: - fprintf(stderr, "qemu: pl031_read: Unexpected offset 0x%x\n", - (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl031: read of write-only register at offset 0x%x\n", + (int)offset); break; default: - hw_error("pl031_read: Bad offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl031_read: Bad offset 0x%x\n", (int)offset); break; } @@ -167,12 +169,14 @@ static void pl031_write(void * opaque, target_phys_addr_t offset, case RTC_DR: case RTC_MIS: case RTC_RIS: - fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n", - (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl031: write to read-only register at offset 0x%x\n", + (int)offset); break; default: - hw_error("pl031_write: Bad offset 0x%x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, + "pl031_write: Bad offset 0x%x\n", (int)offset); break; } } From e7c8afb9058f9d46a089a9fb75cccf996886249c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 17 Oct 2012 01:28:35 +0200 Subject: [PATCH 141/160] target-sparc: fix FMOVr instruction Like the MOVr instruction, the FMOVr instruction has the condition encoded between bits 10 and 12. Cc: Blue Swirl Signed-off-by: Aurelien Jarno Signed-off-by: Blue Swirl --- target-sparc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 5df287629e..4321393688 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3176,7 +3176,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) #define FMOVR(sz) \ do { \ DisasCompare cmp; \ - cond = GET_FIELD_SP(insn, 14, 17); \ + cond = GET_FIELD_SP(insn, 10, 12); \ cpu_src1 = get_src1(dc, insn); \ gen_compare_reg(&cmp, cond, cpu_src1); \ gen_fmov##sz(dc, &cmp, rd, rs2); \ From f354b1a1ee7a1c72d51b42808724a2b10eec315f Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sun, 21 Oct 2012 22:52:54 +0400 Subject: [PATCH 142/160] fix CONFIG_QEMU_HELPERDIR generation again commit 38f419f35225 fixed a breakage with CONFIG_QEMU_HELPERDIR which has been introduced by 8bf188aa18ef7a8. But while techinically that fix has been correct, all other similar variables are handled differently. Make it consistent, and let scripts/create_config expand and capitalize the variable properly like for all other qemu_*dir variables. Signed-off-by: Michael Tokarev --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 9f33c7d723..fa5657f6bc 100755 --- a/configure +++ b/configure @@ -3200,7 +3200,7 @@ echo "qemu_confdir=$qemu_confdir" >> $config_host_mak echo "qemu_datadir=$qemu_datadir" >> $config_host_mak echo "qemu_docdir=$qemu_docdir" >> $config_host_mak echo "qemu_localstatedir=$local_statedir" >> $config_host_mak -echo "CONFIG_QEMU_HELPERDIR=\"`eval echo $libexecdir`\"" >> $config_host_mak +echo "qemu_helperdir=$libexecdir" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak if test "$debug_tcg" = "yes" ; then From 95d2994a2f756c9c8684709421d40c45e63e4e04 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 18:21:54 +0200 Subject: [PATCH 143/160] memory: manage coalesced mmio via a MemoryListener Instead of calling a global function on coalesced mmio changes, which routes the call to kvm if enabled, add coalesced mmio hooks to MemoryListener and make kvm use that instead. The motivation is support for multiple address spaces (which means we we need to filter the call on the right address space) but the result is cleaner as well. Signed-off-by: Avi Kivity --- exec.c | 13 ------------- kvm-all.c | 20 ++++++++++---------- kvm-stub.c | 10 ---------- kvm.h | 2 -- memory.c | 17 +++++++++++++---- memory.h | 4 ++++ 6 files changed, 27 insertions(+), 39 deletions(-) diff --git a/exec.c b/exec.c index 6558728d09..5d5d9e33c9 100644 --- a/exec.c +++ b/exec.c @@ -2305,19 +2305,6 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section, } } - -void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) -{ - if (kvm_enabled()) - kvm_coalesce_mmio_region(addr, size); -} - -void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size) -{ - if (kvm_enabled()) - kvm_uncoalesce_mmio_region(addr, size); -} - void qemu_flush_coalesced_mmio_buffer(void) { if (kvm_enabled()) diff --git a/kvm-all.c b/kvm-all.c index 46cf7e9ec4..677dd2d99f 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -454,9 +454,10 @@ static int kvm_physical_sync_dirty_bitmap(MemoryRegionSection *section) return ret; } -int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) +static void kvm_coalesce_mmio_region(MemoryListener *listener, + MemoryRegionSection *secion, + target_phys_addr_t start, target_phys_addr_t size) { - int ret = -ENOSYS; KVMState *s = kvm_state; if (s->coalesced_mmio) { @@ -466,15 +467,14 @@ int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) zone.size = size; zone.pad = 0; - ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone); + (void)kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone); } - - return ret; } -int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) +static void kvm_uncoalesce_mmio_region(MemoryListener *listener, + MemoryRegionSection *secion, + target_phys_addr_t start, target_phys_addr_t size) { - int ret = -ENOSYS; KVMState *s = kvm_state; if (s->coalesced_mmio) { @@ -484,10 +484,8 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) zone.size = size; zone.pad = 0; - ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone); + (void)kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone); } - - return ret; } int kvm_check_extension(KVMState *s, unsigned int extension) @@ -817,6 +815,8 @@ static MemoryListener kvm_memory_listener = { .log_global_stop = kvm_log_global_stop, .eventfd_add = kvm_mem_ioeventfd_add, .eventfd_del = kvm_mem_ioeventfd_del, + .coalesced_mmio_add = kvm_coalesce_mmio_region, + .coalesced_mmio_del = kvm_uncoalesce_mmio_region, .priority = 10, }; diff --git a/kvm-stub.c b/kvm-stub.c index 3c52eb5bc6..a3455e2203 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -29,16 +29,6 @@ int kvm_init_vcpu(CPUArchState *env) return -ENOSYS; } -int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) -{ - return -ENOSYS; -} - -int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) -{ - return -ENOSYS; -} - int kvm_init(void) { return -ENOSYS; diff --git a/kvm.h b/kvm.h index dea2998fd4..eefcb492f0 100644 --- a/kvm.h +++ b/kvm.h @@ -129,8 +129,6 @@ void *kvm_vmalloc(ram_addr_t size); void *kvm_arch_vmalloc(ram_addr_t size); void kvm_setup_guest_memory(void *start, size_t size); -int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); -int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); void kvm_flush_coalesced_mmio_buffer(void); #endif diff --git a/memory.c b/memory.c index 269af3f6b0..d829f67419 100644 --- a/memory.c +++ b/memory.c @@ -1136,11 +1136,19 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa FlatRange *fr; CoalescedMemoryRange *cmr; AddrRange tmp; + MemoryRegionSection section; FOR_EACH_FLAT_RANGE(fr, as->current_map) { if (fr->mr == mr) { - qemu_unregister_coalesced_mmio(int128_get64(fr->addr.start), - int128_get64(fr->addr.size)); + section = (MemoryRegionSection) { + .address_space = as->root, + .offset_within_address_space = int128_get64(fr->addr.start), + .size = int128_get64(fr->addr.size), + }; + + MEMORY_LISTENER_CALL(coalesced_mmio_del, Reverse, §ion, + int128_get64(fr->addr.start), + int128_get64(fr->addr.size)); QTAILQ_FOREACH(cmr, &mr->coalesced, link) { tmp = addrrange_shift(cmr->addr, int128_sub(fr->addr.start, @@ -1149,8 +1157,9 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa continue; } tmp = addrrange_intersection(tmp, fr->addr); - qemu_register_coalesced_mmio(int128_get64(tmp.start), - int128_get64(tmp.size)); + MEMORY_LISTENER_CALL(coalesced_mmio_add, Forward, §ion, + int128_get64(tmp.start), + int128_get64(tmp.size)); } } } diff --git a/memory.h b/memory.h index 46bc5e1cfd..64d2b341b6 100644 --- a/memory.h +++ b/memory.h @@ -217,6 +217,10 @@ struct MemoryListener { bool match_data, uint64_t data, EventNotifier *e); void (*eventfd_del)(MemoryListener *listener, MemoryRegionSection *section, bool match_data, uint64_t data, EventNotifier *e); + void (*coalesced_mmio_add)(MemoryListener *listener, MemoryRegionSection *section, + target_phys_addr_t addr, target_phys_addr_t len); + void (*coalesced_mmio_del)(MemoryListener *listener, MemoryRegionSection *section, + target_phys_addr_t addr, target_phys_addr_t len); /* Lower = earlier (during add), later (during del) */ unsigned priority; MemoryRegion *address_space_filter; From 2673a5da25ea9005e562c20a18cf469ed4f21060 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 18:49:28 +0200 Subject: [PATCH 144/160] memory: move address_space_memory and address_space_io out of memory core With this change, memory.c no longer knows anything about special address spaces, so it is prepared for AddressSpace based DMA. Reviewed-by: Anthony Liguori Signed-off-by: Avi Kivity --- exec-memory.h | 6 ------ exec.c | 9 +++++++-- memory.c | 16 ---------------- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/exec-memory.h b/exec-memory.h index 1cd92eec71..6707e40b2f 100644 --- a/exec-memory.h +++ b/exec-memory.h @@ -33,12 +33,6 @@ MemoryRegion *get_system_memory(void); */ MemoryRegion *get_system_io(void); -/* Set the root memory region. This region is the system memory map. */ -void set_system_memory_map(MemoryRegion *mr); - -/* Set the I/O memory region. This region is the I/O memory map. */ -void set_system_io_map(MemoryRegion *mr); - #endif #endif diff --git a/exec.c b/exec.c index 5d5d9e33c9..dfc0a784f3 100644 --- a/exec.c +++ b/exec.c @@ -116,6 +116,9 @@ RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) }; static MemoryRegion *system_memory; static MemoryRegion *system_io; +static AddressSpace address_space_io; +static AddressSpace address_space_memory; + MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty; static MemoryRegion io_mem_subpage_ram; @@ -3235,11 +3238,13 @@ static void memory_map_init(void) { system_memory = g_malloc(sizeof(*system_memory)); memory_region_init(system_memory, "system", INT64_MAX); - set_system_memory_map(system_memory); + address_space_init(&address_space_memory, system_memory); + address_space_memory.name = "memory"; system_io = g_malloc(sizeof(*system_io)); memory_region_init(system_io, "io", 65536); - set_system_io_map(system_io); + address_space_init(&address_space_io, system_io); + address_space_io.name = "I/O"; memory_listener_register(&core_memory_listener, system_memory); memory_listener_register(&io_memory_listener, system_io); diff --git a/memory.c b/memory.c index d829f67419..49a6ecc6c8 100644 --- a/memory.c +++ b/memory.c @@ -364,8 +364,6 @@ static void access_with_adjusted_size(target_phys_addr_t addr, } } -static AddressSpace address_space_memory; - static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset, unsigned width, bool write) { @@ -454,8 +452,6 @@ const IORangeOps memory_region_iorange_ops = { .destructor = memory_region_iorange_destructor, }; -static AddressSpace address_space_io; - static AddressSpace *memory_region_to_address_space(MemoryRegion *mr) { AddressSpace *as; @@ -1545,18 +1541,6 @@ void address_space_init(AddressSpace *as, MemoryRegion *root) memory_region_transaction_commit(); } -void set_system_memory_map(MemoryRegion *mr) -{ - address_space_init(&address_space_memory, mr); - address_space_memory.name = "memory"; -} - -void set_system_io_map(MemoryRegion *mr) -{ - address_space_init(&address_space_io, mr); - address_space_io.name = "I/O"; -} - uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size) { return memory_region_dispatch_read(mr, addr, size); From 1d71148eace669827ba15101819b54b20fcca616 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 18:54:45 +0200 Subject: [PATCH 145/160] memory: move tcg flush into a tcg memory listener We plan to make the core listener listen to all address spaces; this will cause many more flushes than necessary. Prepare for that by moving the flush into a tcg-specific listener. Later we can avoid registering the listener if tcg is disabled. Signed-off-by: Avi Kivity --- exec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/exec.c b/exec.c index dfc0a784f3..6a7ba0cea6 100644 --- a/exec.c +++ b/exec.c @@ -3166,7 +3166,7 @@ static void core_begin(MemoryListener *listener) phys_section_watch = dummy_section(&io_mem_watch); } -static void core_commit(MemoryListener *listener) +static void tcg_commit(MemoryListener *listener) { CPUArchState *env; @@ -3220,7 +3220,6 @@ static void io_region_del(MemoryListener *listener, static MemoryListener core_memory_listener = { .begin = core_begin, - .commit = core_commit, .region_add = core_region_add, .region_nop = core_region_nop, .log_global_start = core_log_global_start, @@ -3234,6 +3233,10 @@ static MemoryListener io_memory_listener = { .priority = 0, }; +static MemoryListener tcg_memory_listener = { + .commit = tcg_commit, +}; + static void memory_map_init(void) { system_memory = g_malloc(sizeof(*system_memory)); @@ -3248,6 +3251,7 @@ static void memory_map_init(void) memory_listener_register(&core_memory_listener, system_memory); memory_listener_register(&io_memory_listener, system_io); + memory_listener_register(&tcg_memory_listener, system_memory); } MemoryRegion *get_system_memory(void) From f6790af6bcfa35fa9ea3c565a0a2aed54337aef5 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 2 Oct 2012 20:13:51 +0200 Subject: [PATCH 146/160] memory: use AddressSpace for MemoryListener filtering Using the AddressSpace type reduces confusion, as you can't accidentally supply the MemoryRegion you're interested in. Reviewed-by: Anthony Liguori Signed-off-by: Avi Kivity --- exec-memory.h | 3 +++ exec.c | 10 +++++----- hw/vfio_pci.c | 3 +-- hw/vhost.c | 2 +- hw/xen_pt.c | 4 ++-- kvm-all.c | 4 ++-- memory.c | 14 +++++++------- memory.h | 6 +++--- xen-all.c | 2 +- 9 files changed, 25 insertions(+), 23 deletions(-) diff --git a/exec-memory.h b/exec-memory.h index 6707e40b2f..ac1d07dfe4 100644 --- a/exec-memory.h +++ b/exec-memory.h @@ -33,6 +33,9 @@ MemoryRegion *get_system_memory(void); */ MemoryRegion *get_system_io(void); +extern AddressSpace address_space_memory; +extern AddressSpace address_space_io; + #endif #endif diff --git a/exec.c b/exec.c index 6a7ba0cea6..e732b5285e 100644 --- a/exec.c +++ b/exec.c @@ -116,8 +116,8 @@ RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) }; static MemoryRegion *system_memory; static MemoryRegion *system_io; -static AddressSpace address_space_io; -static AddressSpace address_space_memory; +AddressSpace address_space_io; +AddressSpace address_space_memory; MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty; static MemoryRegion io_mem_subpage_ram; @@ -3249,9 +3249,9 @@ static void memory_map_init(void) address_space_init(&address_space_io, system_io); address_space_io.name = "I/O"; - memory_listener_register(&core_memory_listener, system_memory); - memory_listener_register(&io_memory_listener, system_io); - memory_listener_register(&tcg_memory_listener, system_memory); + memory_listener_register(&core_memory_listener, &address_space_memory); + memory_listener_register(&io_memory_listener, &address_space_io); + memory_listener_register(&tcg_memory_listener, &address_space_memory); } MemoryRegion *get_system_memory(void) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 49e11e7db3..f5db4a8567 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -1507,8 +1507,7 @@ static int vfio_connect_container(VFIOGroup *group) container->iommu_data.listener = vfio_memory_listener; container->iommu_data.release = vfio_listener_release; - memory_listener_register(&container->iommu_data.listener, - get_system_memory()); + memory_listener_register(&container->iommu_data.listener, &address_space_memory); } else { error_report("vfio: No available IOMMU models\n"); g_free(container); diff --git a/hw/vhost.c b/hw/vhost.c index 100f7659a0..0b4ac3f1df 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -792,7 +792,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, hdev->log_size = 0; hdev->log_enabled = false; hdev->started = false; - memory_listener_register(&hdev->memory_listener, get_system_memory()); + memory_listener_register(&hdev->memory_listener, &address_space_memory); hdev->force = force; return 0; fail: diff --git a/hw/xen_pt.c b/hw/xen_pt.c index d5dc11e582..d3d7c8bc3c 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -749,8 +749,8 @@ static int xen_pt_initfn(PCIDevice *d) } out: - memory_listener_register(&s->memory_listener, get_system_memory()); - memory_listener_register(&s->io_listener, get_system_io()); + memory_listener_register(&s->memory_listener, &address_space_memory); + memory_listener_register(&s->io_listener, &address_space_io); XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n", bus, slot, func); diff --git a/kvm-all.c b/kvm-all.c index 677dd2d99f..c2c69093ec 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1375,8 +1375,8 @@ int kvm_init(void) } kvm_state = s; - memory_listener_register(&kvm_memory_listener, get_system_memory()); - memory_listener_register(&kvm_io_listener, get_system_io()); + memory_listener_register(&kvm_memory_listener, &address_space_memory); + memory_listener_register(&kvm_io_listener, &address_space_io); s->many_ioeventfds = kvm_check_many_ioeventfds(); diff --git a/memory.c b/memory.c index 49a6ecc6c8..0cf0177f43 100644 --- a/memory.c +++ b/memory.c @@ -147,7 +147,7 @@ static bool memory_listener_match(MemoryListener *listener, #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback) \ MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \ .mr = (fr)->mr, \ - .address_space = (as)->root, \ + .address_space = (as), \ .offset_within_region = (fr)->offset_in_region, \ .size = int128_get64((fr)->addr.size), \ .offset_within_address_space = int128_get64((fr)->addr.start), \ @@ -593,7 +593,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, fds_new[inew]))) { fd = &fds_old[iold]; section = (MemoryRegionSection) { - .address_space = as->root, + .address_space = as, .offset_within_address_space = int128_get64(fd->addr.start), .size = int128_get64(fd->addr.size), }; @@ -606,7 +606,7 @@ static void address_space_add_del_ioeventfds(AddressSpace *as, fds_old[iold]))) { fd = &fds_new[inew]; section = (MemoryRegionSection) { - .address_space = as->root, + .address_space = as, .offset_within_address_space = int128_get64(fd->addr.start), .size = int128_get64(fd->addr.size), }; @@ -1137,7 +1137,7 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa FOR_EACH_FLAT_RANGE(fr, as->current_map) { if (fr->mr == mr) { section = (MemoryRegionSection) { - .address_space = as->root, + .address_space = as, .offset_within_address_space = int128_get64(fr->addr.start), .size = int128_get64(fr->addr.size), }; @@ -1476,7 +1476,7 @@ static void listener_add_address_space(MemoryListener *listener, FlatRange *fr; if (listener->address_space_filter - && listener->address_space_filter != as->root) { + && listener->address_space_filter != as) { return; } @@ -1489,7 +1489,7 @@ static void listener_add_address_space(MemoryListener *listener, FOR_EACH_FLAT_RANGE(fr, as->current_map) { MemoryRegionSection section = { .mr = fr->mr, - .address_space = as->root, + .address_space = as, .offset_within_region = fr->offset_in_region, .size = int128_get64(fr->addr.size), .offset_within_address_space = int128_get64(fr->addr.start), @@ -1501,7 +1501,7 @@ static void listener_add_address_space(MemoryListener *listener, } } -void memory_listener_register(MemoryListener *listener, MemoryRegion *filter) +void memory_listener_register(MemoryListener *listener, AddressSpace *filter) { MemoryListener *other = NULL; AddressSpace *as; diff --git a/memory.h b/memory.h index 64d2b341b6..f5a13a4db6 100644 --- a/memory.h +++ b/memory.h @@ -187,7 +187,7 @@ typedef struct MemoryRegionSection MemoryRegionSection; */ struct MemoryRegionSection { MemoryRegion *mr; - MemoryRegion *address_space; + AddressSpace *address_space; target_phys_addr_t offset_within_region; uint64_t size; target_phys_addr_t offset_within_address_space; @@ -223,7 +223,7 @@ struct MemoryListener { target_phys_addr_t addr, target_phys_addr_t len); /* Lower = earlier (during add), later (during del) */ unsigned priority; - MemoryRegion *address_space_filter; + AddressSpace *address_space_filter; QTAILQ_ENTRY(MemoryListener) link; }; @@ -774,7 +774,7 @@ void memory_region_transaction_commit(void); * @listener: an object containing the callbacks to be called * @filter: if non-%NULL, only regions in this address space will be observed */ -void memory_listener_register(MemoryListener *listener, MemoryRegion *filter); +void memory_listener_register(MemoryListener *listener, AddressSpace *filter); /** * memory_listener_unregister: undo the effect of memory_listener_register() diff --git a/xen-all.c b/xen-all.c index 8731e1165b..9d1e168826 100644 --- a/xen-all.c +++ b/xen-all.c @@ -1141,7 +1141,7 @@ int xen_hvm_init(void) state->memory_listener = xen_memory_listener; QLIST_INIT(&state->physmap); - memory_listener_register(&state->memory_listener, get_system_memory()); + memory_listener_register(&state->memory_listener, &address_space_memory); state->log_for_dirtybit = NULL; /* Initialize backend core & drivers */ From 0e8a6d47afcc88564079387928f2da45736d36e8 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 3 Oct 2012 16:14:23 +0200 Subject: [PATCH 147/160] s390: avoid reaching into memory core internals use cpu_physical_memory_is_io() instead. Signed-off-by: Avi Kivity --- target-s390x/misc_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index e9b3caed49..fdccd58e3d 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -20,7 +20,6 @@ #include "cpu.h" #include "memory.h" -#include "cputlb.h" #include "host-utils.h" #include "helper.h" #include @@ -81,7 +80,7 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) #endif /* basic checks */ - if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) { + if (cpu_physical_memory_is_io(sccb)) { return -PGM_ADDRESSING; } if (sccb & ~0x7ffffff8ul) { From ac1970fbe8ad5a70174f462109ac0f6c7bf1bc43 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 3 Oct 2012 16:22:53 +0200 Subject: [PATCH 148/160] memory: per-AddressSpace dispatch Currently we use a global radix tree to dispatch memory access. This only works with a single address space; to support multiple address spaces we make the radix tree a member of AddressSpace (via an intermediate structure AddressSpaceDispatch to avoid exposing too many internals). A side effect is that address_space_io also gains a dispatch table. When we remove all the pre-memory-API I/O registrations, we can use that for dispatching I/O and get rid of the original I/O dispatch. Signed-off-by: Avi Kivity --- cputlb.c | 3 +- cputlb.h | 3 +- exec.c | 174 ++++++++++++++++++++++++++++------------------ memory-internal.h | 22 +++++- memory.c | 1 + memory.h | 62 +++++++++++++++++ 6 files changed, 194 insertions(+), 71 deletions(-) diff --git a/cputlb.c b/cputlb.c index 0627f32e35..9027557604 100644 --- a/cputlb.c +++ b/cputlb.c @@ -21,6 +21,7 @@ #include "cpu.h" #include "exec-all.h" #include "memory.h" +#include "exec-memory.h" #include "cputlb.h" @@ -251,7 +252,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr, if (size != TARGET_PAGE_SIZE) { tlb_add_large_page(env, vaddr, size); } - section = phys_page_find(paddr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, paddr >> TARGET_PAGE_BITS); #if defined(DEBUG_TLB) printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx " prot=%x idx=%d pd=0x%08lx\n", diff --git a/cputlb.h b/cputlb.h index 2dc2c96cd8..d537b7740f 100644 --- a/cputlb.h +++ b/cputlb.h @@ -26,7 +26,8 @@ void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr, target_ulong vaddr); void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start, uintptr_t length); -MemoryRegionSection *phys_page_find(target_phys_addr_t index); +MemoryRegionSection *phys_page_find(struct AddressSpaceDispatch *d, + target_phys_addr_t index); void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length); void tlb_set_dirty(CPUArchState *env, target_ulong vaddr); extern int tlb_flush_count; diff --git a/exec.c b/exec.c index e732b5285e..bfc4acc206 100644 --- a/exec.c +++ b/exec.c @@ -187,7 +187,6 @@ uintptr_t qemu_host_page_mask; static void *l1_map[V_L1_SIZE]; #if !defined(CONFIG_USER_ONLY) -typedef struct PhysPageEntry PhysPageEntry; static MemoryRegionSection *phys_sections; static unsigned phys_sections_nb, phys_sections_nb_alloc; @@ -196,22 +195,12 @@ static uint16_t phys_section_notdirty; static uint16_t phys_section_rom; static uint16_t phys_section_watch; -struct PhysPageEntry { - uint16_t is_leaf : 1; - /* index into phys_sections (is_leaf) or phys_map_nodes (!is_leaf) */ - uint16_t ptr : 15; -}; - /* Simple allocator for PhysPageEntry nodes */ static PhysPageEntry (*phys_map_nodes)[L2_SIZE]; static unsigned phys_map_nodes_nb, phys_map_nodes_nb_alloc; #define PHYS_MAP_NODE_NIL (((uint16_t)~0) >> 1) -/* This is a multi-level map on the physical address space. - The bottom level has pointers to MemoryRegionSections. */ -static PhysPageEntry phys_map = { .ptr = PHYS_MAP_NODE_NIL, .is_leaf = 0 }; - static void io_mem_init(void); static void memory_map_init(void); @@ -459,18 +448,19 @@ static void phys_page_set_level(PhysPageEntry *lp, target_phys_addr_t *index, } } -static void phys_page_set(target_phys_addr_t index, target_phys_addr_t nb, +static void phys_page_set(AddressSpaceDispatch *d, + target_phys_addr_t index, target_phys_addr_t nb, uint16_t leaf) { /* Wildly overreserve - it doesn't matter much. */ phys_map_node_reserve(3 * P_L2_LEVELS); - phys_page_set_level(&phys_map, &index, &nb, leaf, P_L2_LEVELS - 1); + phys_page_set_level(&d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1); } -MemoryRegionSection *phys_page_find(target_phys_addr_t index) +MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, target_phys_addr_t index) { - PhysPageEntry lp = phys_map; + PhysPageEntry lp = d->phys_map; PhysPageEntry *p; int i; uint16_t s_index = phys_section_unassigned; @@ -1472,7 +1462,7 @@ void tb_invalidate_phys_addr(target_phys_addr_t addr) ram_addr_t ram_addr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || (section->mr->rom_device && section->mr->readable))) { return; @@ -2210,9 +2200,9 @@ static void destroy_l2_mapping(PhysPageEntry *lp, unsigned level) lp->ptr = PHYS_MAP_NODE_NIL; } -static void destroy_all_mappings(void) +static void destroy_all_mappings(AddressSpaceDispatch *d) { - destroy_l2_mapping(&phys_map, P_L2_LEVELS - 1); + destroy_l2_mapping(&d->phys_map, P_L2_LEVELS - 1); phys_map_nodes_reset(); } @@ -2232,12 +2222,12 @@ static void phys_sections_clear(void) phys_sections_nb = 0; } -static void register_subpage(MemoryRegionSection *section) +static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *section) { subpage_t *subpage; target_phys_addr_t base = section->offset_within_address_space & TARGET_PAGE_MASK; - MemoryRegionSection *existing = phys_page_find(base >> TARGET_PAGE_BITS); + MemoryRegionSection *existing = phys_page_find(d, base >> TARGET_PAGE_BITS); MemoryRegionSection subsection = { .offset_within_address_space = base, .size = TARGET_PAGE_SIZE, @@ -2249,7 +2239,7 @@ static void register_subpage(MemoryRegionSection *section) if (!(existing->mr->subpage)) { subpage = subpage_init(base); subsection.mr = &subpage->iomem; - phys_page_set(base >> TARGET_PAGE_BITS, 1, + phys_page_set(d, base >> TARGET_PAGE_BITS, 1, phys_section_add(&subsection)); } else { subpage = container_of(existing->mr, subpage_t, iomem); @@ -2260,7 +2250,7 @@ static void register_subpage(MemoryRegionSection *section) } -static void register_multipage(MemoryRegionSection *section) +static void register_multipage(AddressSpaceDispatch *d, MemoryRegionSection *section) { target_phys_addr_t start_addr = section->offset_within_address_space; ram_addr_t size = section->size; @@ -2270,13 +2260,13 @@ static void register_multipage(MemoryRegionSection *section) assert(size); addr = start_addr; - phys_page_set(addr >> TARGET_PAGE_BITS, size >> TARGET_PAGE_BITS, + phys_page_set(d, addr >> TARGET_PAGE_BITS, size >> TARGET_PAGE_BITS, section_index); } -void cpu_register_physical_memory_log(MemoryRegionSection *section, - bool readonly) +static void mem_add(MemoryListener *listener, MemoryRegionSection *section) { + AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener); MemoryRegionSection now = *section, remain = *section; if ((now.offset_within_address_space & ~TARGET_PAGE_MASK) @@ -2284,7 +2274,7 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section, now.size = MIN(TARGET_PAGE_ALIGN(now.offset_within_address_space) - now.offset_within_address_space, now.size); - register_subpage(&now); + register_subpage(d, &now); remain.size -= now.size; remain.offset_within_address_space += now.size; remain.offset_within_region += now.size; @@ -2293,10 +2283,10 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section, now = remain; if (remain.offset_within_region & ~TARGET_PAGE_MASK) { now.size = TARGET_PAGE_SIZE; - register_subpage(&now); + register_subpage(d, &now); } else { now.size &= TARGET_PAGE_MASK; - register_multipage(&now); + register_multipage(d, &now); } remain.size -= now.size; remain.offset_within_address_space += now.size; @@ -2304,7 +2294,7 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section, } now = remain; if (now.size) { - register_subpage(&now); + register_subpage(d, &now); } } @@ -3155,11 +3145,17 @@ static void io_mem_init(void) "watch", UINT64_MAX); } +static void mem_begin(MemoryListener *listener) +{ + AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener); + + destroy_all_mappings(d); + d->phys_map.ptr = PHYS_MAP_NODE_NIL; +} + static void core_begin(MemoryListener *listener) { - destroy_all_mappings(); phys_sections_clear(); - phys_map.ptr = PHYS_MAP_NODE_NIL; phys_section_unassigned = dummy_section(&io_mem_unassigned); phys_section_notdirty = dummy_section(&io_mem_notdirty); phys_section_rom = dummy_section(&io_mem_rom); @@ -3178,18 +3174,6 @@ static void tcg_commit(MemoryListener *listener) } } -static void core_region_add(MemoryListener *listener, - MemoryRegionSection *section) -{ - cpu_register_physical_memory_log(section, section->readonly); -} - -static void core_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ - cpu_register_physical_memory_log(section, section->readonly); -} - static void core_log_global_start(MemoryListener *listener) { cpu_physical_memory_set_dirty_tracking(1); @@ -3220,11 +3204,9 @@ static void io_region_del(MemoryListener *listener, static MemoryListener core_memory_listener = { .begin = core_begin, - .region_add = core_region_add, - .region_nop = core_region_nop, .log_global_start = core_log_global_start, .log_global_stop = core_log_global_stop, - .priority = 0, + .priority = 1, }; static MemoryListener io_memory_listener = { @@ -3237,6 +3219,21 @@ static MemoryListener tcg_memory_listener = { .commit = tcg_commit, }; +void address_space_init_dispatch(AddressSpace *as) +{ + AddressSpaceDispatch *d = g_new(AddressSpaceDispatch, 1); + + d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .is_leaf = 0 }; + d->listener = (MemoryListener) { + .begin = mem_begin, + .region_add = mem_add, + .region_nop = mem_add, + .priority = 0, + }; + as->dispatch = d; + memory_listener_register(&d->listener, as); +} + static void memory_map_init(void) { system_memory = g_malloc(sizeof(*system_memory)); @@ -3321,9 +3318,10 @@ static void invalidate_and_set_dirty(target_phys_addr_t addr, xen_modified_memory(addr, length); } -void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, - int len, int is_write) +void address_space_rw(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, + int len, bool is_write) { + AddressSpaceDispatch *d = as->dispatch; int l; uint8_t *ptr; uint32_t val; @@ -3335,7 +3333,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(page >> TARGET_PAGE_BITS); + section = phys_page_find(d, page >> TARGET_PAGE_BITS); if (is_write) { if (!memory_region_is_ram(section->mr)) { @@ -3406,10 +3404,36 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } +void address_space_write(AddressSpace *as, target_phys_addr_t addr, + const uint8_t *buf, int len) +{ + address_space_rw(as, addr, (uint8_t *)buf, len, true); +} + +/** + * address_space_read: read from an address space. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @buf: buffer with the data transferred + */ +void address_space_read(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, int len) +{ + address_space_rw(as, addr, buf, len, false); +} + + +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write) +{ + return address_space_rw(&address_space_memory, addr, buf, len, is_write); +} + /* used for ROM loading : can write in RAM and ROM */ void cpu_physical_memory_write_rom(target_phys_addr_t addr, const uint8_t *buf, int len) { + AddressSpaceDispatch *d = address_space_memory.dispatch; int l; uint8_t *ptr; target_phys_addr_t page; @@ -3420,7 +3444,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(page >> TARGET_PAGE_BITS); + section = phys_page_find(d, page >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3494,10 +3518,12 @@ static void cpu_notify_map_clients(void) * Use cpu_register_map_client() to know when retrying the map operation is * likely to succeed. */ -void *cpu_physical_memory_map(target_phys_addr_t addr, - target_phys_addr_t *plen, - int is_write) +void *address_space_map(AddressSpace *as, + target_phys_addr_t addr, + target_phys_addr_t *plen, + bool is_write) { + AddressSpaceDispatch *d = as->dispatch; target_phys_addr_t len = *plen; target_phys_addr_t todo = 0; int l; @@ -3512,7 +3538,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(page >> TARGET_PAGE_BITS); + section = phys_page_find(d, page >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) && !section->readonly)) { if (todo || bounce.buffer) { @@ -3522,7 +3548,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, bounce.addr = addr; bounce.len = l; if (!is_write) { - cpu_physical_memory_read(addr, bounce.buffer, l); + address_space_read(as, addr, bounce.buffer, l); } *plen = l; @@ -3543,12 +3569,12 @@ void *cpu_physical_memory_map(target_phys_addr_t addr, return ret; } -/* Unmaps a memory region previously mapped by cpu_physical_memory_map(). +/* Unmaps a memory region previously mapped by address_space_map(). * Will also mark the memory as dirty if is_write == 1. access_len gives * the amount of memory that was actually read or written by the caller. */ -void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, - int is_write, target_phys_addr_t access_len) +void address_space_unmap(AddressSpace *as, void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len) { if (buffer != bounce.buffer) { if (is_write) { @@ -3569,13 +3595,26 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, return; } if (is_write) { - cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len); + address_space_write(as, bounce.addr, bounce.buffer, access_len); } qemu_vfree(bounce.buffer); bounce.buffer = NULL; cpu_notify_map_clients(); } +void *cpu_physical_memory_map(target_phys_addr_t addr, + target_phys_addr_t *plen, + int is_write) +{ + return address_space_map(&address_space_memory, addr, plen, is_write); +} + +void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len) +{ + return address_space_unmap(&address_space_memory, buffer, len, is_write, access_len); +} + /* warning: addr must be aligned */ static inline uint32_t ldl_phys_internal(target_phys_addr_t addr, enum device_endian endian) @@ -3584,7 +3623,7 @@ static inline uint32_t ldl_phys_internal(target_phys_addr_t addr, uint32_t val; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3643,7 +3682,7 @@ static inline uint64_t ldq_phys_internal(target_phys_addr_t addr, uint64_t val; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3710,7 +3749,7 @@ static inline uint32_t lduw_phys_internal(target_phys_addr_t addr, uint64_t val; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3769,7 +3808,7 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) uint8_t *ptr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!memory_region_is_ram(section->mr) || section->readonly) { addr = memory_region_section_addr(section, addr); @@ -3801,7 +3840,7 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val) uint8_t *ptr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!memory_region_is_ram(section->mr) || section->readonly) { addr = memory_region_section_addr(section, addr); @@ -3830,7 +3869,7 @@ static inline void stl_phys_internal(target_phys_addr_t addr, uint32_t val, uint8_t *ptr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!memory_region_is_ram(section->mr) || section->readonly) { addr = memory_region_section_addr(section, addr); @@ -3897,7 +3936,7 @@ static inline void stw_phys_internal(target_phys_addr_t addr, uint32_t val, uint8_t *ptr; MemoryRegionSection *section; - section = phys_page_find(addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!memory_region_is_ram(section->mr) || section->readonly) { addr = memory_region_section_addr(section, addr); @@ -4133,7 +4172,8 @@ bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr) { MemoryRegionSection *section; - section = phys_page_find(phys_addr >> TARGET_PAGE_BITS); + section = phys_page_find(address_space_memory.dispatch, + phys_addr >> TARGET_PAGE_BITS); return !(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr)); diff --git a/memory-internal.h b/memory-internal.h index 43fa886264..6d8711bb1f 100644 --- a/memory-internal.h +++ b/memory-internal.h @@ -22,6 +22,26 @@ #ifndef CONFIG_USER_ONLY #include "hw/xen.h" +typedef struct PhysPageEntry PhysPageEntry; + +struct PhysPageEntry { + uint16_t is_leaf : 1; + /* index into phys_sections (is_leaf) or phys_map_nodes (!is_leaf) */ + uint16_t ptr : 15; +}; + +typedef struct AddressSpaceDispatch AddressSpaceDispatch; + +struct AddressSpaceDispatch { + /* This is a multi-level map on the physical address space. + * The bottom level has pointers to MemoryRegionSections. + */ + PhysPageEntry phys_map; + MemoryListener listener; +}; + +void address_space_init_dispatch(AddressSpace *as); + ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, MemoryRegion *mr); ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr); @@ -30,8 +50,6 @@ void qemu_ram_free_from_ptr(ram_addr_t addr); struct MemoryRegion; struct MemoryRegionSection; -void cpu_register_physical_memory_log(struct MemoryRegionSection *section, - bool readonly); void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); diff --git a/memory.c b/memory.c index 0cf0177f43..13be84849c 100644 --- a/memory.c +++ b/memory.c @@ -1539,6 +1539,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root) QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); as->name = NULL; memory_region_transaction_commit(); + address_space_init_dispatch(as); } uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size) diff --git a/memory.h b/memory.h index f5a13a4db6..d36c2baa23 100644 --- a/memory.h +++ b/memory.h @@ -169,6 +169,7 @@ struct AddressSpace { struct FlatView *current_map; int ioeventfd_nb; struct MemoryRegionIoeventfd *ioeventfds; + struct AddressSpaceDispatch *dispatch; QTAILQ_ENTRY(AddressSpace) address_spaces_link; }; @@ -803,6 +804,67 @@ void mtree_info(fprintf_function mon_printf, void *f); */ void address_space_init(AddressSpace *as, MemoryRegion *root); +/** + * address_space_rw: read from or write to an address space. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @buf: buffer with the data transferred + * @is_write: indicates the transfer direction + */ +void address_space_rw(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, + int len, bool is_write); + +/** + * address_space_write: write to address space. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @buf: buffer with the data transferred + */ +void address_space_write(AddressSpace *as, target_phys_addr_t addr, + const uint8_t *buf, int len); + +/** + * address_space_read: read from an address space. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @buf: buffer with the data transferred + */ +void address_space_read(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, int len); + +/* address_space_map: map a physical memory region into a host virtual address + * + * May map a subset of the requested range, given by and returned in @plen. + * May return %NULL if resources needed to perform the mapping are exhausted. + * Use only for reads OR writes - not for read-modify-write operations. + * Use cpu_register_map_client() to know when retrying the map operation is + * likely to succeed. + * + * @as: #AddressSpace to be accessed + * @addr: address within that address space + * @plen: pointer to length of buffer; updated on return + * @is_write: indicates the transfer direction + */ +void *address_space_map(AddressSpace *as, target_phys_addr_t addr, + target_phys_addr_t *plen, bool is_write); + +/* address_space_unmap: Unmaps a memory region previously mapped by address_space_map() + * + * Will also mark the memory as dirty if @is_write == %true. @access_len gives + * the amount of memory that was actually read or written by the caller. + * + * @as: #AddressSpace used + * @addr: address within that address space + * @len: buffer length as returned by address_space_map() + * @access_len: amount of data actually transferred + * @is_write: indicates the transfer direction + */ +void address_space_unmap(AddressSpace *as, void *buffer, target_phys_addr_t len, + int is_write, target_phys_addr_t access_len); + + #endif #endif From b90600eed3c0efe5f3260853c873caf51c0677b1 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 3 Oct 2012 16:42:37 +0200 Subject: [PATCH 149/160] dma: make dma access its own address space Instead of accessing the cpu address space, use an address space configured by the caller. Eventually all dma functionality will be folded into AddressSpace, but we have to start from something. Reviewed-by: Anthony Liguori Signed-off-by: Avi Kivity --- dma-helpers.c | 25 ++++++++++++------------- dma.h | 17 ++++++++--------- hw/spapr_iommu.c | 3 ++- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/dma-helpers.c b/dma-helpers.c index 433d8b21b3..3f09dcb072 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -14,7 +14,8 @@ /* #define DEBUG_IOMMU */ -static void do_dma_memory_set(dma_addr_t addr, uint8_t c, dma_addr_t len) +static void do_dma_memory_set(AddressSpace *as, + dma_addr_t addr, uint8_t c, dma_addr_t len) { #define FILLBUF_SIZE 512 uint8_t fillbuf[FILLBUF_SIZE]; @@ -23,7 +24,7 @@ static void do_dma_memory_set(dma_addr_t addr, uint8_t c, dma_addr_t len) memset(fillbuf, c, FILLBUF_SIZE); while (len > 0) { l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; - cpu_physical_memory_rw(addr, fillbuf, l, true); + address_space_rw(as, addr, fillbuf, l, true); len -= l; addr += l; } @@ -36,7 +37,7 @@ int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len) if (dma_has_iommu(dma)) { return iommu_dma_memory_set(dma, addr, c, len); } - do_dma_memory_set(addr, c, len); + do_dma_memory_set(dma->as, addr, c, len); return 0; } @@ -332,8 +333,7 @@ int iommu_dma_memory_rw(DMAContext *dma, dma_addr_t addr, plen = len; } - cpu_physical_memory_rw(paddr, buf, plen, - dir == DMA_DIRECTION_FROM_DEVICE); + address_space_rw(dma->as, paddr, buf, plen, dir == DMA_DIRECTION_FROM_DEVICE); len -= plen; addr += plen; @@ -366,7 +366,7 @@ int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, plen = len; } - do_dma_memory_set(paddr, c, plen); + do_dma_memory_set(dma->as, paddr, c, plen); len -= plen; addr += plen; @@ -375,13 +375,14 @@ int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, return 0; } -void dma_context_init(DMAContext *dma, DMATranslateFunc translate, +void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate, DMAMapFunc map, DMAUnmapFunc unmap) { #ifdef DEBUG_IOMMU fprintf(stderr, "dma_context_init(%p, %p, %p, %p)\n", dma, translate, map, unmap); #endif + dma->as = as; dma->translate = translate; dma->map = map; dma->unmap = unmap; @@ -407,14 +408,13 @@ void *iommu_dma_memory_map(DMAContext *dma, dma_addr_t addr, dma_addr_t *len, /* * If this is true, the virtual region is contiguous, * but the translated physical region isn't. We just - * clamp *len, much like cpu_physical_memory_map() does. + * clamp *len, much like address_space_map() does. */ if (plen < *len) { *len = plen; } - buf = cpu_physical_memory_map(paddr, &plen, - dir == DMA_DIRECTION_FROM_DEVICE); + buf = address_space_map(dma->as, paddr, &plen, dir == DMA_DIRECTION_FROM_DEVICE); *len = plen; return buf; @@ -428,8 +428,7 @@ void iommu_dma_memory_unmap(DMAContext *dma, void *buffer, dma_addr_t len, return; } - cpu_physical_memory_unmap(buffer, len, - dir == DMA_DIRECTION_FROM_DEVICE, - access_len); + address_space_unmap(dma->as, buffer, len, dir == DMA_DIRECTION_FROM_DEVICE, + access_len); } diff --git a/dma.h b/dma.h index 1a33603f22..1bd6f4a651 100644 --- a/dma.h +++ b/dma.h @@ -11,6 +11,7 @@ #define DMA_H #include +#include "memory.h" #include "hw/hw.h" #include "block.h" #include "kvm.h" @@ -61,6 +62,7 @@ typedef void DMAUnmapFunc(DMAContext *dma, dma_addr_t access_len); struct DMAContext { + AddressSpace *as; DMATranslateFunc *translate; DMAMapFunc *map; DMAUnmapFunc *unmap; @@ -93,7 +95,7 @@ static inline void dma_barrier(DMAContext *dma, DMADirection dir) static inline bool dma_has_iommu(DMAContext *dma) { - return !!dma; + return dma && dma->translate; } /* Checks that the given range of addresses is valid for DMA. This is @@ -120,8 +122,7 @@ static inline int dma_memory_rw_relaxed(DMAContext *dma, dma_addr_t addr, { if (!dma_has_iommu(dma)) { /* Fast-path for no IOMMU */ - cpu_physical_memory_rw(addr, buf, len, - dir == DMA_DIRECTION_FROM_DEVICE); + address_space_rw(dma->as, addr, buf, len, dir == DMA_DIRECTION_FROM_DEVICE); return 0; } else { return iommu_dma_memory_rw(dma, addr, buf, len, dir); @@ -179,8 +180,7 @@ static inline void *dma_memory_map(DMAContext *dma, target_phys_addr_t xlen = *len; void *p; - p = cpu_physical_memory_map(addr, &xlen, - dir == DMA_DIRECTION_FROM_DEVICE); + p = address_space_map(dma->as, addr, &xlen, dir == DMA_DIRECTION_FROM_DEVICE); *len = xlen; return p; } else { @@ -196,9 +196,8 @@ static inline void dma_memory_unmap(DMAContext *dma, DMADirection dir, dma_addr_t access_len) { if (!dma_has_iommu(dma)) { - cpu_physical_memory_unmap(buffer, (target_phys_addr_t)len, - dir == DMA_DIRECTION_FROM_DEVICE, - access_len); + address_space_unmap(dma->as, buffer, (target_phys_addr_t)len, + dir == DMA_DIRECTION_FROM_DEVICE, access_len); } else { iommu_dma_memory_unmap(dma, buffer, len, dir, access_len); } @@ -242,7 +241,7 @@ DEFINE_LDST_DMA(q, q, 64, be); #undef DEFINE_LDST_DMA -void dma_context_init(DMAContext *dma, DMATranslateFunc translate, +void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate, DMAMapFunc map, DMAUnmapFunc unmap); struct ScatterGatherEntry { diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c index 38034c07bd..33f84e27aa 100644 --- a/hw/spapr_iommu.c +++ b/hw/spapr_iommu.c @@ -21,6 +21,7 @@ #include "qdev.h" #include "kvm_ppc.h" #include "dma.h" +#include "exec-memory.h" #include "hw/spapr.h" @@ -124,7 +125,7 @@ DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size) } tcet = g_malloc0(sizeof(*tcet)); - dma_context_init(&tcet->dma, spapr_tce_translate, NULL, NULL); + dma_context_init(&tcet->dma, &address_space_memory, spapr_tce_translate, NULL, NULL); tcet->liobn = liobn; tcet->window_size = window_size; From 83f3c251422b0724044f976a7ff26b2e8a47c374 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 7 Oct 2012 12:59:55 +0200 Subject: [PATCH 150/160] memory: add address_space_destroy() Since address spaces can be created dynamically by device hotplug, they can also be destroyed dynamically. Signed-off-by: Avi Kivity --- exec.c | 10 ++++++++++ memory-internal.h | 1 + memory.c | 18 ++++++++++++++++-- memory.h | 12 ++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/exec.c b/exec.c index bfc4acc206..17e8ba21d4 100644 --- a/exec.c +++ b/exec.c @@ -3234,6 +3234,16 @@ void address_space_init_dispatch(AddressSpace *as) memory_listener_register(&d->listener, as); } +void address_space_destroy_dispatch(AddressSpace *as) +{ + AddressSpaceDispatch *d = as->dispatch; + + memory_listener_unregister(&d->listener); + destroy_l2_mapping(&d->phys_map, P_L2_LEVELS - 1); + g_free(d); + as->dispatch = NULL; +} + static void memory_map_init(void) { system_memory = g_malloc(sizeof(*system_memory)); diff --git a/memory-internal.h b/memory-internal.h index 6d8711bb1f..4d33cc9530 100644 --- a/memory-internal.h +++ b/memory-internal.h @@ -41,6 +41,7 @@ struct AddressSpaceDispatch { }; void address_space_init_dispatch(AddressSpace *as); +void address_space_destroy_dispatch(AddressSpace *as); ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, MemoryRegion *mr); diff --git a/memory.c b/memory.c index 13be84849c..2f68d67c21 100644 --- a/memory.c +++ b/memory.c @@ -564,8 +564,10 @@ static FlatView generate_memory_topology(MemoryRegion *mr) flatview_init(&view); - render_memory_region(&view, mr, int128_zero(), - addrrange_make(int128_zero(), int128_2_64()), false); + if (mr) { + render_memory_region(&view, mr, int128_zero(), + addrrange_make(int128_zero(), int128_2_64()), false); + } flatview_simplify(&view); return view; @@ -1542,6 +1544,18 @@ void address_space_init(AddressSpace *as, MemoryRegion *root) address_space_init_dispatch(as); } +void address_space_destroy(AddressSpace *as) +{ + /* Flush out anything from MemoryListeners listening in on this */ + memory_region_transaction_begin(); + as->root = NULL; + memory_region_transaction_commit(); + QTAILQ_REMOVE(&address_spaces, as, address_spaces_link); + address_space_destroy_dispatch(as); + flatview_destroy(as->current_map); + g_free(as->current_map); +} + uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size) { return memory_region_dispatch_read(mr, addr, size); diff --git a/memory.h b/memory.h index d36c2baa23..79393f1a76 100644 --- a/memory.h +++ b/memory.h @@ -804,6 +804,18 @@ void mtree_info(fprintf_function mon_printf, void *f); */ void address_space_init(AddressSpace *as, MemoryRegion *root); + +/** + * address_space_destroy: destroy an address space + * + * Releases all resources associated with an address space. After an address space + * is destroyed, its root memory region (given by address_space_init()) may be destroyed + * as well. + * + * @as: address space to be destroyed + */ +void address_space_destroy(AddressSpace *as); + /** * address_space_rw: read from or write to an address space. * From 817dcc5368988b023c5e1d3f1444fd370c77c6a9 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 3 Oct 2012 17:17:27 +0200 Subject: [PATCH 151/160] pci: give each device its own address space Accesses from different devices can resolve differently (depending on bridge settings, iommus, and PCI_COMMAND_MASTER), so set up an address space for each device. Currently iommus are expressed outside the memory API, so this doesn't work if an iommu is present. Signed-off-by: Avi Kivity --- hw/pci.c | 14 ++++++++++++++ hw/pci.h | 1 + 2 files changed, 15 insertions(+) diff --git a/hw/pci.c b/hw/pci.c index 2ca6ff6fec..b1415dbce6 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -33,6 +33,7 @@ #include "qmp-commands.h" #include "msi.h" #include "msix.h" +#include "exec-memory.h" //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -777,6 +778,13 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, pci_dev->bus = bus; if (bus->dma_context_fn) { pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn); + } else { + /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is + * taken unconditionally */ + /* FIXME: inherit memory region from bus creator */ + address_space_init(&pci_dev->bus_master_as, get_system_memory()); + pci_dev->dma = g_new(DMAContext, 1); + dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); } pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); @@ -830,6 +838,12 @@ static void do_pci_unregister_device(PCIDevice *pci_dev) qemu_free_irqs(pci_dev->irq); pci_dev->bus->devices[pci_dev->devfn] = NULL; pci_config_free(pci_dev); + + if (!pci_dev->bus->dma_context_fn) { + address_space_destroy(&pci_dev->bus_master_as); + g_free(pci_dev->dma); + pci_dev->dma = NULL; + } } static void pci_unregister_io_regions(PCIDevice *pci_dev) diff --git a/hw/pci.h b/hw/pci.h index d50d26c8ac..f9207ca062 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -211,6 +211,7 @@ struct PCIDevice { int32_t devfn; char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; + AddressSpace bus_master_as; DMAContext *dma; /* do not access the following fields */ From 1c380f9460522f32c8dd2577b2a53d518ec91c6d Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 3 Oct 2012 17:42:58 +0200 Subject: [PATCH 152/160] pci: honor PCI_COMMAND_MASTER Currently we ignore PCI_COMMAND_MASTER completely: DMA succeeds even when the bit is clear. Honor PCI_COMMAND_MASTER by inserting a memory region into the device's bus master address space, and tying its enable status to PCI_COMMAND_MASTER. Tested using setpci -s 03 COMMAND=3 while a ping was running on a NIC in slot 3. The kernel (Linux) detected the stall and recovered after the command setpci -s 03 COMMAND=7 was issued. Signed-off-by: Avi Kivity --- hw/pci.c | 13 +++++++++++-- hw/pci.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index b1415dbce6..7eeaac0d3d 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -782,7 +782,11 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, /* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is * taken unconditionally */ /* FIXME: inherit memory region from bus creator */ - address_space_init(&pci_dev->bus_master_as, get_system_memory()); + memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master", + get_system_memory(), 0, + memory_region_size(get_system_memory())); + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region); pci_dev->dma = g_new(DMAContext, 1); dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL); } @@ -841,6 +845,7 @@ static void do_pci_unregister_device(PCIDevice *pci_dev) if (!pci_dev->bus->dma_context_fn) { address_space_destroy(&pci_dev->bus_master_as); + memory_region_destroy(&pci_dev->bus_master_enable_region); g_free(pci_dev->dma); pci_dev->dma = NULL; } @@ -1065,8 +1070,12 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) range_covers_byte(addr, l, PCI_COMMAND)) pci_update_mappings(d); - if (range_covers_byte(addr, l, PCI_COMMAND)) + if (range_covers_byte(addr, l, PCI_COMMAND)) { pci_update_irq_disabled(d, was_irq_disabled); + memory_region_set_enabled(&d->bus_master_enable_region, + pci_get_word(d->config + PCI_COMMAND) + & PCI_COMMAND_MASTER); + } msi_write_config(d, addr, val, l); msix_write_config(d, addr, val, l); diff --git a/hw/pci.h b/hw/pci.h index f9207ca062..1f902f5b59 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -212,6 +212,7 @@ struct PCIDevice { char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; AddressSpace bus_master_as; + MemoryRegion bus_master_enable_region; DMAContext *dma; /* do not access the following fields */ From ad0b5321f1f797274603ebbe20108b0750baee94 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Fri, 5 Oct 2012 16:47:57 -0300 Subject: [PATCH 153/160] Call MADV_HUGEPAGE for guest RAM allocations This makes it possible for QEMU to use transparent huge pages (THP) when transparent_hugepage/enabled=madvise. Otherwise THP is only used when it's enabled system wide. Signed-off-by: Luiz Capitulino Signed-off-by: Anthony Liguori --- exec.c | 1 + osdep.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/exec.c b/exec.c index c4ed6fdef1..750008c4e1 100644 --- a/exec.c +++ b/exec.c @@ -2571,6 +2571,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff); qemu_ram_setup_dump(new_block->host, size); + qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE); if (kvm_enabled()) kvm_setup_guest_memory(new_block->host, size); diff --git a/osdep.h b/osdep.h index cb213e0295..c5fd3d91ff 100644 --- a/osdep.h +++ b/osdep.h @@ -108,6 +108,11 @@ void qemu_vfree(void *ptr); #else #define QEMU_MADV_DONTDUMP QEMU_MADV_INVALID #endif +#ifdef MADV_HUGEPAGE +#define QEMU_MADV_HUGEPAGE MADV_HUGEPAGE +#else +#define QEMU_MADV_HUGEPAGE QEMU_MADV_INVALID +#endif #elif defined(CONFIG_POSIX_MADVISE) From 488cb996cd8d8eaa5ecfdc6ba5f6cbd23a13271b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Oct 2012 09:54:19 +0200 Subject: [PATCH 154/160] serial: split serial.c Split serial.c into serial.c, serial.h and serial-isa.c. While being at creating a serial.h header file move the serial prototypes from pc.h to the new serial.h. The latter leads to s/pc.h/serial.h/ in tons of boards which just want the serial bits from pc.h Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/Makefile.objs | 2 +- hw/alpha_dp264.c | 1 + hw/kzm.c | 2 +- hw/mips_fulong2e.c | 1 + hw/mips_jazz.c | 1 + hw/mips_malta.c | 1 + hw/mips_mipssim.c | 2 +- hw/mips_r4k.c | 1 + hw/musicpal.c | 2 +- hw/omap_uart.c | 3 +- hw/openrisc_sim.c | 3 +- hw/pc.c | 1 + hw/pc.h | 27 -------- hw/petalogix_ml605_mmu.c | 2 +- hw/ppc/e500.c | 2 +- hw/ppc405_uc.c | 2 +- hw/ppc440_bamboo.c | 2 +- hw/ppc_prep.c | 1 + hw/pxa2xx.c | 2 +- hw/serial-isa.c | 130 +++++++++++++++++++++++++++++++++++ hw/serial.c | 143 ++------------------------------------- hw/serial.h | 98 +++++++++++++++++++++++++++ hw/sm501.c | 2 +- hw/sun4u.c | 1 + hw/virtex_ml507.c | 2 +- hw/xtensa_lx60.c | 3 +- 26 files changed, 257 insertions(+), 180 deletions(-) create mode 100644 hw/serial-isa.c create mode 100644 hw/serial.h diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 854faa9b5b..16e7a1e6f3 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -20,7 +20,7 @@ common-obj-$(CONFIG_M48T59) += m48t59.o common-obj-$(CONFIG_ESCC) += escc.o common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o -common-obj-$(CONFIG_SERIAL) += serial.o +common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o common-obj-$(CONFIG_PARALLEL) += parallel.o common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o common-obj-$(CONFIG_PCSPK) += pcspk.o diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 8f082a6656..76d8ae8a84 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -15,6 +15,7 @@ #include "mc146818rtc.h" #include "ide.h" #include "i8254.h" +#include "serial.h" #define MAX_IDE_BUS 2 diff --git a/hw/kzm.c b/hw/kzm.c index d1266d9305..687daf3b2c 100644 --- a/hw/kzm.c +++ b/hw/kzm.c @@ -21,7 +21,7 @@ #include "net.h" #include "sysemu.h" #include "boards.h" -#include "pc.h" /* for the FPGA UART that emulates a 16550 */ +#include "serial.h" #include "imx.h" /* Memory map for Kzm Emulation Baseboard: diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index fb50a1f67b..5fcf900e04 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -20,6 +20,7 @@ #include "hw.h" #include "pc.h" +#include "serial.h" #include "fdc.h" #include "net.h" #include "boards.h" diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 14df4d7745..6bd231dc9b 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -26,6 +26,7 @@ #include "mips.h" #include "mips_cpudevs.h" #include "pc.h" +#include "serial.h" #include "isa.h" #include "fdc.h" #include "sysemu.h" diff --git a/hw/mips_malta.c b/hw/mips_malta.c index ad4910ff66..22ec8b9efa 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -24,6 +24,7 @@ #include "hw.h" #include "pc.h" +#include "serial.h" #include "fdc.h" #include "net.h" #include "boards.h" diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index a1d3945cbb..a95a3c1f11 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -27,7 +27,7 @@ #include "hw.h" #include "mips.h" #include "mips_cpudevs.h" -#include "pc.h" +#include "serial.h" #include "isa.h" #include "net.h" #include "sysemu.h" diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index b73cdc38ec..539577b761 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -11,6 +11,7 @@ #include "mips.h" #include "mips_cpudevs.h" #include "pc.h" +#include "serial.h" #include "isa.h" #include "net.h" #include "sysemu.h" diff --git a/hw/musicpal.c b/hw/musicpal.c index f06814c83b..159d3c3c39 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -15,7 +15,7 @@ #include "net.h" #include "sysemu.h" #include "boards.h" -#include "pc.h" +#include "serial.h" #include "qemu-timer.h" #include "ptimer.h" #include "block.h" diff --git a/hw/omap_uart.c b/hw/omap_uart.c index 167d5c4e50..1c16a54306 100644 --- a/hw/omap_uart.c +++ b/hw/omap_uart.c @@ -20,8 +20,7 @@ #include "qemu-char.h" #include "hw.h" #include "omap.h" -/* We use pc-style serial ports. */ -#include "pc.h" +#include "serial.h" #include "exec-memory.h" /* UARTs */ diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c index e96a94492b..7327740764 100644 --- a/hw/openrisc_sim.c +++ b/hw/openrisc_sim.c @@ -21,7 +21,8 @@ #include "hw.h" #include "boards.h" #include "elf.h" -#include "pc.h" +#include "serial.h" +#include "net.h" #include "loader.h" #include "exec-memory.h" #include "sysemu.h" diff --git a/hw/pc.c b/hw/pc.c index 6c0722db5c..805e8cabcf 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -23,6 +23,7 @@ */ #include "hw.h" #include "pc.h" +#include "serial.h" #include "apic.h" #include "fdc.h" #include "ide.h" diff --git a/hw/pc.h b/hw/pc.h index 9923d96027..6cba7ce7d6 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -12,33 +12,6 @@ /* PC-style peripherals (also used by other machines). */ -/* serial.c */ - -SerialState *serial_init(int base, qemu_irq irq, int baudbase, - CharDriverState *chr); -SerialState *serial_mm_init(MemoryRegion *address_space, - target_phys_addr_t base, int it_shift, - qemu_irq irq, int baudbase, - CharDriverState *chr, enum device_endian); -static inline bool serial_isa_init(ISABus *bus, int index, - CharDriverState *chr) -{ - ISADevice *dev; - - dev = isa_try_create(bus, "isa-serial"); - if (!dev) { - return false; - } - qdev_prop_set_uint32(&dev->qdev, "index", index); - qdev_prop_set_chr(&dev->qdev, "chardev", chr); - if (qdev_init(&dev->qdev) < 0) { - return false; - } - return true; -} - -void serial_set_frequency(SerialState *s, uint32_t frequency); - /* parallel.c */ static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr) { diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index 39df25175b..5b45809d74 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -34,7 +34,7 @@ #include "boards.h" #include "xilinx.h" #include "blockdev.h" -#include "pc.h" +#include "serial.h" #include "exec-memory.h" #include "ssi.h" diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index d23f9b2f60..846f53a8d9 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -19,7 +19,7 @@ #include "e500.h" #include "net.h" #include "hw/hw.h" -#include "hw/pc.h" +#include "hw/serial.h" #include "hw/pci.h" #include "hw/boards.h" #include "sysemu.h" diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index b52ab2f179..e81409dc0f 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -24,7 +24,7 @@ #include "hw.h" #include "ppc.h" #include "ppc405.h" -#include "pc.h" +#include "serial.h" #include "qemu-timer.h" #include "sysemu.h" #include "qemu-log.h" diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 78e7985305..5616a26b38 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -23,7 +23,7 @@ #include "loader.h" #include "elf.h" #include "exec-memory.h" -#include "pc.h" +#include "serial.h" #include "ppc.h" #include "ppc405.h" #include "sysemu.h" diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index b426891e29..a0d1c3d75d 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -24,6 +24,7 @@ #include "hw.h" #include "nvram.h" #include "pc.h" +#include "serial.h" #include "fdc.h" #include "net.h" #include "sysemu.h" diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index d5f1420ed9..4ec904ff20 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -10,7 +10,7 @@ #include "sysbus.h" #include "pxa.h" #include "sysemu.h" -#include "pc.h" +#include "serial.h" #include "i2c.h" #include "ssi.h" #include "qemu-char.h" diff --git a/hw/serial-isa.c b/hw/serial-isa.c new file mode 100644 index 0000000000..96c78f7f8d --- /dev/null +++ b/hw/serial-isa.c @@ -0,0 +1,130 @@ +/* + * QEMU 16550A UART emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "serial.h" +#include "isa.h" + +typedef struct ISASerialState { + ISADevice dev; + uint32_t index; + uint32_t iobase; + uint32_t isairq; + SerialState state; +} ISASerialState; + +static const int isa_serial_io[MAX_SERIAL_PORTS] = { + 0x3f8, 0x2f8, 0x3e8, 0x2e8 +}; +static const int isa_serial_irq[MAX_SERIAL_PORTS] = { + 4, 3, 4, 3 +}; + +static int serial_isa_initfn(ISADevice *dev) +{ + static int index; + ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev); + SerialState *s = &isa->state; + + if (isa->index == -1) { + isa->index = index; + } + if (isa->index >= MAX_SERIAL_PORTS) { + return -1; + } + if (isa->iobase == -1) { + isa->iobase = isa_serial_io[isa->index]; + } + if (isa->isairq == -1) { + isa->isairq = isa_serial_irq[isa->index]; + } + index++; + + s->baudbase = 115200; + isa_init_irq(dev, &s->irq, isa->isairq); + serial_init_core(s); + qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3); + + memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); + isa_register_ioport(dev, &s->io, isa->iobase); + return 0; +} + +static const VMStateDescription vmstate_isa_serial = { + .name = "serial", + .version_id = 3, + .minimum_version_id = 2, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static Property serial_isa_properties[] = { + DEFINE_PROP_UINT32("index", ISASerialState, index, -1), + DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), + DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), + DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), + DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void serial_isa_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = serial_isa_initfn; + dc->vmsd = &vmstate_isa_serial; + dc->props = serial_isa_properties; +} + +static TypeInfo serial_isa_info = { + .name = "isa-serial", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISASerialState), + .class_init = serial_isa_class_initfn, +}; + +static void serial_register_types(void) +{ + type_register_static(&serial_isa_info); +} + +type_init(serial_register_types) + +bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr) +{ + ISADevice *dev; + + dev = isa_try_create(bus, "isa-serial"); + if (!dev) { + return false; + } + qdev_prop_set_uint32(&dev->qdev, "index", index); + qdev_prop_set_chr(&dev->qdev, "chardev", chr); + if (qdev_init(&dev->qdev) < 0) { + return false; + } + return true; +} diff --git a/hw/serial.c b/hw/serial.c index a421d1e7bc..78e219df5c 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -22,12 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" + +#include "serial.h" #include "qemu-char.h" -#include "isa.h" -#include "pc.h" #include "qemu-timer.h" -#include "sysemu.h" //#define DEBUG_SERIAL @@ -93,8 +91,6 @@ #define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ #define UART_FCR_FE 0x01 /* FIFO Enable */ -#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ - #define XMIT_FIFO 0 #define RECV_FIFO 1 #define MAX_XMIT_RETRY 4 @@ -107,64 +103,6 @@ do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0) do {} while (0) #endif -typedef struct SerialFIFO { - uint8_t data[UART_FIFO_LENGTH]; - uint8_t count; - uint8_t itl; /* Interrupt Trigger Level */ - uint8_t tail; - uint8_t head; -} SerialFIFO; - -struct SerialState { - uint16_t divider; - uint8_t rbr; /* receive register */ - uint8_t thr; /* transmit holding register */ - uint8_t tsr; /* transmit shift register */ - uint8_t ier; - uint8_t iir; /* read only */ - uint8_t lcr; - uint8_t mcr; - uint8_t lsr; /* read only */ - uint8_t msr; /* read only */ - uint8_t scr; - uint8_t fcr; - uint8_t fcr_vmstate; /* we can't write directly this value - it has side effects */ - /* NOTE: this hidden state is necessary for tx irq generation as - it can be reset while reading iir */ - int thr_ipending; - qemu_irq irq; - CharDriverState *chr; - int last_break_enable; - int it_shift; - int baudbase; - int tsr_retry; - uint32_t wakeup; - - uint64_t last_xmit_ts; /* Time when the last byte was successfully sent out of the tsr */ - SerialFIFO recv_fifo; - SerialFIFO xmit_fifo; - - struct QEMUTimer *fifo_timeout_timer; - int timeout_ipending; /* timeout interrupt pending state */ - struct QEMUTimer *transmit_timer; - - - uint64_t char_transmit_time; /* time to transmit a char in ticks*/ - int poll_msl; - - struct QEMUTimer *modem_status_poll; - MemoryRegion io; -}; - -typedef struct ISASerialState { - ISADevice dev; - uint32_t index; - uint32_t iobase; - uint32_t isairq; - SerialState state; -} ISASerialState; - static void serial_receive1(void *opaque, const uint8_t *buf, int size); static void fifo_clear(SerialState *s, int fifo) @@ -687,7 +625,7 @@ static int serial_post_load(void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_serial = { +const VMStateDescription vmstate_serial = { .name = "serial", .version_id = 3, .minimum_version_id = 2, @@ -736,7 +674,7 @@ static void serial_reset(void *opaque) qemu_irq_lower(s->irq); } -static void serial_init_core(SerialState *s) +void serial_init_core(SerialState *s) { if (!s->chr) { fprintf(stderr, "Can't create serial device, empty char device\n"); @@ -761,54 +699,15 @@ void serial_set_frequency(SerialState *s, uint32_t frequency) serial_update_parameters(s); } -static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; -static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; - static const MemoryRegionPortio serial_portio[] = { { 0, 8, 1, .read = serial_ioport_read, .write = serial_ioport_write }, PORTIO_END_OF_LIST() }; -static const MemoryRegionOps serial_io_ops = { +const MemoryRegionOps serial_io_ops = { .old_portio = serial_portio }; -static int serial_isa_initfn(ISADevice *dev) -{ - static int index; - ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev); - SerialState *s = &isa->state; - - if (isa->index == -1) - isa->index = index; - if (isa->index >= MAX_SERIAL_PORTS) - return -1; - if (isa->iobase == -1) - isa->iobase = isa_serial_io[isa->index]; - if (isa->isairq == -1) - isa->isairq = isa_serial_irq[isa->index]; - index++; - - s->baudbase = 115200; - isa_init_irq(dev, &s->irq, isa->isairq); - serial_init_core(s); - qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3); - - memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); - isa_register_ioport(dev, &s->io, isa->iobase); - return 0; -} - -static const VMStateDescription vmstate_isa_serial = { - .name = "serial", - .version_id = 3, - .minimum_version_id = 2, - .fields = (VMStateField []) { - VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState), - VMSTATE_END_OF_LIST() - } -}; - SerialState *serial_init(int base, qemu_irq irq, int baudbase, CharDriverState *chr) { @@ -886,35 +785,3 @@ SerialState *serial_mm_init(MemoryRegion *address_space, serial_update_msl(s); return s; } - -static Property serial_isa_properties[] = { - DEFINE_PROP_UINT32("index", ISASerialState, index, -1), - DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), - DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), - DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), - DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void serial_isa_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); - ic->init = serial_isa_initfn; - dc->vmsd = &vmstate_isa_serial; - dc->props = serial_isa_properties; -} - -static TypeInfo serial_isa_info = { - .name = "isa-serial", - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISASerialState), - .class_init = serial_isa_class_initfn, -}; - -static void serial_register_types(void) -{ - type_register_static(&serial_isa_info); -} - -type_init(serial_register_types) diff --git a/hw/serial.h b/hw/serial.h new file mode 100644 index 0000000000..6f5293b202 --- /dev/null +++ b/hw/serial.h @@ -0,0 +1,98 @@ +/* + * QEMU 16550A UART emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "sysemu.h" +#include "memory.h" + +#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ + +typedef struct SerialFIFO { + uint8_t data[UART_FIFO_LENGTH]; + uint8_t count; + uint8_t itl; /* Interrupt Trigger Level */ + uint8_t tail; + uint8_t head; +} SerialFIFO; + +struct SerialState { + uint16_t divider; + uint8_t rbr; /* receive register */ + uint8_t thr; /* transmit holding register */ + uint8_t tsr; /* transmit shift register */ + uint8_t ier; + uint8_t iir; /* read only */ + uint8_t lcr; + uint8_t mcr; + uint8_t lsr; /* read only */ + uint8_t msr; /* read only */ + uint8_t scr; + uint8_t fcr; + uint8_t fcr_vmstate; /* we can't write directly this value + it has side effects */ + /* NOTE: this hidden state is necessary for tx irq generation as + it can be reset while reading iir */ + int thr_ipending; + qemu_irq irq; + CharDriverState *chr; + int last_break_enable; + int it_shift; + int baudbase; + int tsr_retry; + uint32_t wakeup; + + /* Time when the last byte was successfully sent out of the tsr */ + uint64_t last_xmit_ts; + SerialFIFO recv_fifo; + SerialFIFO xmit_fifo; + + struct QEMUTimer *fifo_timeout_timer; + int timeout_ipending; /* timeout interrupt pending state */ + struct QEMUTimer *transmit_timer; + + + uint64_t char_transmit_time; /* time to transmit a char in ticks */ + int poll_msl; + + struct QEMUTimer *modem_status_poll; + MemoryRegion io; +}; + +extern const VMStateDescription vmstate_serial; +extern const MemoryRegionOps serial_io_ops; + +void serial_init_core(SerialState *s); +void serial_set_frequency(SerialState *s, uint32_t frequency); + +/* legacy pre qom */ +SerialState *serial_init(int base, qemu_irq irq, int baudbase, + CharDriverState *chr); +SerialState *serial_mm_init(MemoryRegion *address_space, + target_phys_addr_t base, int it_shift, + qemu_irq irq, int baudbase, + CharDriverState *chr, enum device_endian end); + +/* serial-isa.c */ +bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr); diff --git a/hw/sm501.c b/hw/sm501.c index 786e07629c..050d096533 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -24,7 +24,7 @@ #include #include "hw.h" -#include "pc.h" +#include "serial.h" #include "console.h" #include "devices.h" #include "sysbus.h" diff --git a/hw/sun4u.c b/hw/sun4u.c index abf68cf50f..eeb6496092 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -25,6 +25,7 @@ #include "pci.h" #include "apb_pci.h" #include "pc.h" +#include "serial.h" #include "nvram.h" #include "fdc.h" #include "net.h" diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index a09b27a346..c59e1cb4e4 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -24,7 +24,7 @@ #include "sysbus.h" #include "hw.h" -#include "pc.h" +#include "serial.h" #include "net.h" #include "flash.h" #include "sysemu.h" diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index 1fd2c47ac5..0c407d37b7 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -31,7 +31,8 @@ #include "elf.h" #include "memory.h" #include "exec-memory.h" -#include "pc.h" +#include "serial.h" +#include "net.h" #include "sysbus.h" #include "flash.h" #include "blockdev.h" From 419ad67208a37367932a5bf88d3860f85e06282c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Oct 2012 09:54:20 +0200 Subject: [PATCH 155/160] serial: add pci variant So we get a hot-pluggable 16550 uart. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- default-configs/pci.mak | 2 + hw/Makefile.objs | 1 + hw/pci_ids.h | 1 + hw/serial-pci.c | 101 ++++++++++++++++++++++++++++++++++++++++ hw/serial.c | 6 +++ hw/serial.h | 1 + 6 files changed, 112 insertions(+) create mode 100644 hw/serial-pci.c diff --git a/default-configs/pci.mak b/default-configs/pci.mak index 69e18f1428..ae9d1eb487 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -19,3 +19,5 @@ CONFIG_IDE_PCI=y CONFIG_AHCI=y CONFIG_ESP=y CONFIG_ESP_PCI=y +CONFIG_SERIAL=y +CONFIG_SERIAL_PCI=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 16e7a1e6f3..af4ab0c735 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_ESCC) += escc.o common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o +common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o common-obj-$(CONFIG_PARALLEL) += parallel.o common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o common-obj-$(CONFIG_PCSPK) += pcspk.o diff --git a/hw/pci_ids.h b/hw/pci_ids.h index 301bf1cd86..c017a79998 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -37,6 +37,7 @@ #define PCI_CLASS_BRIDGE_PCI 0x0604 #define PCI_CLASS_BRIDGE_OTHER 0x0680 +#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 #define PCI_CLASS_COMMUNICATION_OTHER 0x0780 #define PCI_CLASS_PROCESSOR_CO 0x0b40 diff --git a/hw/serial-pci.c b/hw/serial-pci.c new file mode 100644 index 0000000000..6fcf1170b3 --- /dev/null +++ b/hw/serial-pci.c @@ -0,0 +1,101 @@ +/* + * QEMU 16550A UART emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2008 Citrix Systems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "serial.h" +#include "pci.h" + +typedef struct PCISerialState { + PCIDevice dev; + SerialState state; +} PCISerialState; + +static int serial_pci_init(PCIDevice *dev) +{ + PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); + SerialState *s = &pci->state; + + s->baudbase = 115200; + serial_init_core(s); + + pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + s->irq = pci->dev.irq[0]; + + memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); + return 0; +} + +static void serial_pci_exit(PCIDevice *dev) +{ + PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); + SerialState *s = &pci->state; + + serial_exit_core(s); + memory_region_destroy(&s->io); +} + +static const VMStateDescription vmstate_pci_serial = { + .name = "pci-serial", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PCISerialState), + VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState), + VMSTATE_END_OF_LIST() + } +}; + +static Property serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void serial_pci_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); + pc->init = serial_pci_init; + pc->exit = serial_pci_exit; + pc->vendor_id = 0x1b36; /* Red Hat */ + pc->device_id = 0x0002; + pc->revision = 1; + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd = &vmstate_pci_serial; + dc->props = serial_pci_properties; +} + +static TypeInfo serial_pci_info = { + .name = "pci-serial", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCISerialState), + .class_init = serial_pci_class_initfn, +}; + +static void serial_pci_register_types(void) +{ + type_register_static(&serial_pci_info); +} + +type_init(serial_pci_register_types) diff --git a/hw/serial.c b/hw/serial.c index 78e219df5c..5adbfafde5 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -692,6 +692,12 @@ void serial_init_core(SerialState *s) serial_event, s); } +void serial_exit_core(SerialState *s) +{ + qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); + qemu_unregister_reset(serial_reset, s); +} + /* Change the main reference oscillator frequency. */ void serial_set_frequency(SerialState *s, uint32_t frequency) { diff --git a/hw/serial.h b/hw/serial.h index 6f5293b202..55a1ac5e9b 100644 --- a/hw/serial.h +++ b/hw/serial.h @@ -84,6 +84,7 @@ extern const VMStateDescription vmstate_serial; extern const MemoryRegionOps serial_io_ops; void serial_init_core(SerialState *s); +void serial_exit_core(SerialState *s); void serial_set_frequency(SerialState *s, uint32_t frequency); /* legacy pre qom */ From fe4f1793a6bd9fdd008a17aa695a2670ff438bb5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Oct 2012 09:54:21 +0200 Subject: [PATCH 156/160] serial: add windows inf file for the pci card to docs Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- docs/qemupciserial.inf | 109 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 docs/qemupciserial.inf diff --git a/docs/qemupciserial.inf b/docs/qemupciserial.inf new file mode 100644 index 0000000000..3474310a4b --- /dev/null +++ b/docs/qemupciserial.inf @@ -0,0 +1,109 @@ +; qemupciserial.inf for QEMU, based on MSPORTS.INF + +; The driver itself is shipped with Windows (serial.sys). This is +; just a inf file to tell windows which pci id the serial pci card +; emulated by qemu has, and to apply a name tag to it which windows +; will show in the device manager. + +; Installing the driver: Go to device manager. You should find a "pci +; serial card" tagged with a yellow question mark. Open properties. +; Pick "update driver". Then "select driver manually". Pick "Ports +; (Com+Lpt)" from the list. Click "Have a disk". Select this file. +; Procedure may vary a bit depending on the windows version. + +; FIXME: This file covers the single port version only. + +[Version] +Signature="$CHICAGO$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%QEMU% +DriverVer=09/24/2012,1.3.0 + +[SourceDisksNames] +3426=windows cd + +[SourceDisksFiles] +serial.sys = 3426 +serenum.sys = 3426 + +[DestinationDirs] +DefaultDestDir = 11 ;LDID_SYS +ComPort.NT.Copy = 12 ;DIRID_DRIVERS +SerialEnumerator.NT.Copy=12 ;DIRID_DRIVERS + +; Drivers +;---------------------------------------------------------- +[Manufacturer] +%QEMU%=QEMU,NTx86 + +[QEMU.NTx86] +%QEMU-PCI_SERIAL.DeviceDesc% = ComPort, "PCI\VEN_1b36&DEV_0002&CC_0700" + +; COM sections +;---------------------------------------------------------- +[ComPort.AddReg] +HKR,,PortSubClass,1,01 + +[ComPort.NT] +AddReg=ComPort.AddReg, ComPort.NT.AddReg +LogConfig=caa +SyssetupPnPFlags = 1 + +[ComPort.NT.HW] +AddReg=ComPort.NT.HW.AddReg + +[ComPort.NT.AddReg] +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[ComPort.NT.HW.AddReg] +HKR,,"UpperFilters",0x00010000,"serenum" + +;-------------- Service installation +; Port Driver (function driver for this device) +[ComPort.NT.Services] +AddService = Serial, 0x00000002, Serial_Service_Inst, Serial_EventLog_Inst +AddService = Serenum,,Serenum_Service_Inst + +; -------------- Serial Port Driver install sections +[Serial_Service_Inst] +DisplayName = %Serial.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 1 ; SERVICE_SYSTEM_START (this driver may do detection) +ErrorControl = 0 ; SERVICE_ERROR_IGNORE +ServiceBinary = %12%\serial.sys +LoadOrderGroup = Extended base + +; -------------- Serenum Driver install section +[Serenum_Service_Inst] +DisplayName = %Serenum.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\serenum.sys +LoadOrderGroup = PNP Filter + +[Serial_EventLog_Inst] +AddReg = Serial_EventLog_AddReg + +[Serial_EventLog_AddReg] +HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\serial.sys" +HKR,,TypesSupported,0x00010001,7 + +; The following sections are COM port resource configs. +; Section name format means: +; Char 1 = c (COM port) +; Char 2 = I/O config: 1 (3f8), 2 (2f8), 3 (3e8), 4 (2e8), a (any) +; Char 3 = IRQ config: #, a (any) + +[caa] ; Any base, any IRQ +ConfigPriority=HARDRECONFIG +IOConfig=8@100-ffff%fff8(3ff::) +IRQConfig=S:3,4,5,7,9,10,11,12,14,15 + +[Strings] +QEMU="QEMU" +QEMU-PCI_SERIAL.DeviceDesc="QEMU Serial PCI Card" + +Serial.SVCDESC = "Serial port driver" +Serenum.SVCDESC = "Serenum Filter Driver" From d66bbea4e0d3faec69e8aa73789a2d1dc3b8312f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Oct 2012 09:54:22 +0200 Subject: [PATCH 157/160] serial: add 2x + 4x pci variant Add multiport serial card implementation, with two variants, one featuring two and one featuring four ports. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/serial-pci.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/hw/serial-pci.c b/hw/serial-pci.c index 6fcf1170b3..badd297220 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -26,11 +26,23 @@ #include "serial.h" #include "pci.h" +#define PCI_SERIAL_MAX_PORTS 4 + typedef struct PCISerialState { PCIDevice dev; SerialState state; } PCISerialState; +typedef struct PCIMultiSerialState { + PCIDevice dev; + MemoryRegion iobar; + uint32_t ports; + char *name[PCI_SERIAL_MAX_PORTS]; + SerialState state[PCI_SERIAL_MAX_PORTS]; + uint32_t level[PCI_SERIAL_MAX_PORTS]; + qemu_irq *irqs; +} PCIMultiSerialState; + static int serial_pci_init(PCIDevice *dev) { PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); @@ -47,6 +59,56 @@ static int serial_pci_init(PCIDevice *dev) return 0; } +static void multi_serial_irq_mux(void *opaque, int n, int level) +{ + PCIMultiSerialState *pci = opaque; + int i, pending = 0; + + pci->level[n] = level; + for (i = 0; i < pci->ports; i++) { + if (pci->level[i]) { + pending = 1; + } + } + qemu_set_irq(pci->dev.irq[0], pending); +} + +static int multi_serial_pci_init(PCIDevice *dev) +{ + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); + SerialState *s; + int i; + + switch (pc->device_id) { + case 0x0003: + pci->ports = 2; + break; + case 0x0004: + pci->ports = 4; + break; + } + assert(pci->ports > 0); + assert(pci->ports <= PCI_SERIAL_MAX_PORTS); + + pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + memory_region_init(&pci->iobar, "multiserial", 8 * pci->ports); + pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); + pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, + pci->ports); + + for (i = 0; i < pci->ports; i++) { + s = pci->state + i; + s->baudbase = 115200; + serial_init_core(s); + s->irq = pci->irqs[i]; + pci->name[i] = g_strdup_printf("uart #%d", i+1); + memory_region_init_io(&s->io, &serial_io_ops, s, pci->name[i], 8); + memory_region_add_subregion(&pci->iobar, 8 * i, &s->io); + } + return 0; +} + static void serial_pci_exit(PCIDevice *dev) { PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); @@ -56,6 +118,22 @@ static void serial_pci_exit(PCIDevice *dev) memory_region_destroy(&s->io); } +static void multi_serial_pci_exit(PCIDevice *dev) +{ + PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); + SerialState *s; + int i; + + for (i = 0; i < pci->ports; i++) { + s = pci->state + i; + serial_exit_core(s); + memory_region_destroy(&s->io); + g_free(pci->name[i]); + } + memory_region_destroy(&pci->iobar); + qemu_free_irqs(pci->irqs); +} + static const VMStateDescription vmstate_pci_serial = { .name = "pci-serial", .version_id = 1, @@ -67,11 +145,38 @@ static const VMStateDescription vmstate_pci_serial = { } }; +static const VMStateDescription vmstate_pci_multi_serial = { + .name = "pci-serial-multi", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState), + VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS, + 0, vmstate_serial, SerialState), + VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS), + VMSTATE_END_OF_LIST() + } +}; + static Property serial_pci_properties[] = { DEFINE_PROP_CHR("chardev", PCISerialState, state.chr), DEFINE_PROP_END_OF_LIST(), }; +static Property multi_2x_serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), + DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static Property multi_4x_serial_pci_properties[] = { + DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), + DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), + DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr), + DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void serial_pci_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -86,6 +191,34 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data) dc->props = serial_pci_properties; } +static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); + pc->init = multi_serial_pci_init; + pc->exit = multi_serial_pci_exit; + pc->vendor_id = 0x1b36; /* Red Hat */ + pc->device_id = 0x0003; + pc->revision = 1; + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd = &vmstate_pci_multi_serial; + dc->props = multi_2x_serial_pci_properties; +} + +static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); + pc->init = multi_serial_pci_init; + pc->exit = multi_serial_pci_exit; + pc->vendor_id = 0x1b36; /* Red Hat */ + pc->device_id = 0x0004; + pc->revision = 1; + pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; + dc->vmsd = &vmstate_pci_multi_serial; + dc->props = multi_4x_serial_pci_properties; +} + static TypeInfo serial_pci_info = { .name = "pci-serial", .parent = TYPE_PCI_DEVICE, @@ -93,9 +226,25 @@ static TypeInfo serial_pci_info = { .class_init = serial_pci_class_initfn, }; +static TypeInfo multi_2x_serial_pci_info = { + .name = "pci-serial-2x", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIMultiSerialState), + .class_init = multi_2x_serial_pci_class_initfn, +}; + +static TypeInfo multi_4x_serial_pci_info = { + .name = "pci-serial-4x", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIMultiSerialState), + .class_init = multi_4x_serial_pci_class_initfn, +}; + static void serial_pci_register_types(void) { type_register_static(&serial_pci_info); + type_register_static(&multi_2x_serial_pci_info); + type_register_static(&multi_4x_serial_pci_info); } type_init(serial_pci_register_types) From 90734e02bd2fb137346d4184cec6c5d26e68f29b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Oct 2012 09:54:23 +0200 Subject: [PATCH 158/160] serial: add pci-serial documentation Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- docs/specs/pci-serial.txt | 34 ++++++++++++++++++++++++++++++++++ hw/serial-pci.c | 2 ++ 2 files changed, 36 insertions(+) create mode 100644 docs/specs/pci-serial.txt diff --git a/docs/specs/pci-serial.txt b/docs/specs/pci-serial.txt new file mode 100644 index 0000000000..66c761f2b4 --- /dev/null +++ b/docs/specs/pci-serial.txt @@ -0,0 +1,34 @@ + +QEMU pci serial devices +======================= + +There is one single-port variant and two muliport-variants. Linux +guests out-of-the box with all cards. There is a Windows inf file +(docs/qemupciserial.inf) to setup the single-port card in Windows +guests. + + +single-port card +---------------- + +Name: pci-serial +PCI ID: 1b36:0002 + +PCI Region 0: + IO bar, 8 bytes long, with the 16550 uart mapped to it. + Interrupt is wired to pin A. + + +multiport cards +--------------- + +Name: pci-serial-2x +PCI ID: 1b36:0003 + +Name: pci-serial-4x +PCI ID: 1b36:0004 + +PCI Region 0: + IO bar, with two/four 16550 uart mapped after each other. + The first is at offset 0, second at offset 8, ... + Interrupt is wired to pin A. diff --git a/hw/serial-pci.c b/hw/serial-pci.c index badd297220..95dc5c8d2f 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -23,6 +23,8 @@ * THE SOFTWARE. */ +/* see docs/specs/pci-serial.txt */ + #include "serial.h" #include "pci.h" From 70330fb3daa2ee295cc5c6f40133e8f8db47856d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Oct 2012 09:54:24 +0200 Subject: [PATCH 159/160] usb-serial: don't magically zap chardev on umplug Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/usb/dev-serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 69b6e48d5a..43214cdd9c 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -421,7 +421,7 @@ static void usb_serial_handle_destroy(USBDevice *dev) { USBSerialState *s = (USBSerialState *)dev; - qemu_chr_delete(s->cs); + qemu_chr_add_handlers(s->cs, NULL, NULL, NULL, NULL); } static int usb_serial_can_read(void *opaque) From da124e62de2109a312e21d85d6a3419774c58948 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 17 Oct 2012 09:54:25 +0200 Subject: [PATCH 160/160] usb-serial: only expose device in guest when the chardev is open Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/usb/dev-serial.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 43214cdd9c..a466f9929c 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -427,6 +427,10 @@ static void usb_serial_handle_destroy(USBDevice *dev) static int usb_serial_can_read(void *opaque) { USBSerialState *s = opaque; + + if (!s->dev.attached) { + return 0; + } return RECV_BUF - s->recv_used; } @@ -469,8 +473,14 @@ static void usb_serial_event(void *opaque, int event) case CHR_EVENT_FOCUS: break; case CHR_EVENT_OPENED: - usb_serial_reset(s); - /* TODO: Reset USB port */ + if (!s->dev.attached) { + usb_device_attach(&s->dev); + } + break; + case CHR_EVENT_CLOSED: + if (s->dev.attached) { + usb_device_detach(&s->dev); + } break; } } @@ -481,6 +491,7 @@ static int usb_serial_initfn(USBDevice *dev) usb_desc_create_serial(dev); usb_desc_init(dev); + dev->auto_attach = 0; if (!s->cs) { error_report("Property chardev is required"); @@ -490,6 +501,10 @@ static int usb_serial_initfn(USBDevice *dev) qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read, usb_serial_event, s); usb_serial_handle_reset(dev); + + if (s->cs->opened && !dev->attached) { + usb_device_attach(dev); + } return 0; }